qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulato


From: Isaku Yamahata
Subject: [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator.
Date: Fri, 1 May 2009 22:17:02 +0900

Signed-off-by: Isaku Yamahata <address@hidden>
---
 hw/pci.c      |  175 +++++++++++++++++++++++++++++++++++++++------------------
 hw/pci.h      |   30 ++++++++++
 hw/unin_pci.c |    2 +-
 3 files changed, 151 insertions(+), 56 deletions(-)

diff --git a/hw/pci.c b/hw/pci.c
index 0be3662..a1123cb 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <assert.h>
 #include "hw.h"
 #include "pci.h"
 #include "monitor.h"
@@ -461,6 +462,9 @@ void pci_default_write_config(PCIDevice *d,
     int can_write, i;
     uint32_t end, addr;
 
+    assert((d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION) ==
+          PCI_HEADER_TYPE_NORMAL);
+
     if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
                      (address >= 0x30 && address < 0x34))) {
         PCIIORegion *r;
@@ -490,56 +494,28 @@ void pci_default_write_config(PCIDevice *d,
     /* not efficient, but simple */
     addr = address;
     for(i = 0; i < len; i++) {
-        /* default read/write accesses */
-        switch(d->config[0x0e]) {
+      /* default read/write accesses */
+        switch(addr) {
         case 0x00:
-        case 0x80:
-            switch(addr) {
-            case 0x00:
-            case 0x01:
-            case 0x02:
-            case 0x03:
-            case 0x06:
-            case 0x07:
-            case 0x08:
-            case 0x09:
-            case 0x0a:
-            case 0x0b:
-            case 0x0e:
-            case 0x10 ... 0x27: /* base */
-            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
-            case 0x30 ... 0x33: /* rom */
-            case 0x3d:
-                can_write = 0;
-                break;
-            default:
-                can_write = 1;
-                break;
-            }
+        case 0x01:
+        case 0x02:
+        case 0x03:
+        case 0x06:
+        case 0x07:
+        case 0x08:
+        case 0x09:
+        case 0x0a:
+        case 0x0b:
+        case 0x0e:
+        case 0x10 ... 0x27: /* base */
+        case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
+        case 0x30 ... 0x33: /* rom */
+        case 0x3d:
+            can_write = 0;
             break;
         default:
-        case 0x01:
-            switch(addr) {
-            case 0x00:
-            case 0x01:
-            case 0x02:
-            case 0x03:
-            case 0x06:
-            case 0x07:
-            case 0x08:
-            case 0x09:
-            case 0x0a:
-            case 0x0b:
-            case 0x0e:
-            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
-            case 0x38 ... 0x3b: /* rom */
-            case 0x3d:
-                can_write = 0;
-                break;
-            default:
-                can_write = 1;
-                break;
-            }
+            can_write = 1;
+
             break;
         }
         if (can_write) {
@@ -836,18 +812,107 @@ typedef struct {
 static void pci_bridge_write_config(PCIDevice *d,
                              uint32_t address, uint32_t val, int len)
 {
+    int can_write;
     PCIBridge *s = (PCIBridge *)d;
+    uint32_t addr = address;
+    int i;
+
+    assert((d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION) ==
+          PCI_HEADER_TYPE_BRIDGE);
+
+    for (i = 0; i < len; i++) {
+        uint8_t val8 = val & 0xff;
+        switch (addr) {
+        case 0x00:
+        case 0x01:
+        case 0x02:
+        case 0x03:
+        case 0x06:
+        case 0x07:
+        case 0x08:
+        case 0x09:
+        case 0x0a:
+        case 0x0b:
+        case 0x0e:      /* header type */
+        case 0x10 ... 0x17: /* BAR */
+            /* BAR0, BAR1, ROM isn't implemented. so RO to 0 */
+        case 0x30 ... 0x33: /* IO base/limit upper 16bits. always 0*/
+        case 0x38 ... 0x3b: /* rom */
+            /* Expansion ROM isn't implemented. so RO to 0 */
+        case 0x3d:
+        case PCI_BRIDGE_CONTROL:        /* 0x3e */
+            can_write = 0;
+            break;
+
+        case PCI_COMMAND:               /* 0x04 */
+            val8 &= ~PCI_COMMAND_RESERVED_BRIDGE;
+            can_write = 1;
+            break;
+        case PCI_COMMAND + 1:           /* 0x05 */
+            val8 &= ~PCI_COMMAND_RESERVED_MASK_HI_BRIDGE;
+            can_write = 1;
+            break;
 
-    if (address == 0x19 || (address == 0x18 && len > 1)) {
-        if (address == 0x19)
+        case PCI_IO_BASE:               /* 0x1c */
+        case PCI_IO_LIMIT:              /* 0x1d */
+            val8 = (val8 & PCI_IO_RANGE_MASK) |
+                (d->config[addr] & ~PCI_IO_BASE);
+            can_write = 1;
+            break;
+
+        case PCI_SECONDARY_BUS: /* 0x19 */
             s->bus->bus_num = val & 0xff;
-        else
-            s->bus->bus_num = (val >> 8) & 0xff;
-#if defined(DEBUG_PCI)
-        printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num);
-#endif
+            can_write = 1;
+            break;
+
+        case PCI_MEMORY_BASE:           /* 0x20 */
+        case PCI_MEMORY_LIMIT:          /* 0x22 */
+            val8 = val8 & PCI_MEMORY_RANGE_MASK;
+            can_write = 1;
+            break;
+        case PCI_MEMORY_BASE + 1:       /* 0x21 */
+        case PCI_MEMORY_LIMIT + 1:      /* 0x23 */
+            can_write = 1;
+            break;
+
+        case PCI_PREF_MEMORY_BASE:      /* 0x24 */
+        case PCI_PREF_MEMORY_LIMIT:     /* 0x26*/
+            val8 = val8 & PCI_PREF_RANGE_MASK;
+            can_write = 1;
+            break;
+        case PCI_PREF_MEMORY_BASE + 1:  /* 0x25 */
+        case PCI_PREF_MEMORY_LIMIT + 1: /* 0x27 */
+            can_write = 1;
+            break;
+
+        case PCI_PREF_BASE_UPPER32:     /* 0x28 */
+        case PCI_PREF_LIMIT_UPPER32:    /* 0x2c */
+            can_write = 0;
+            /*
+            val8 = val8 & PCI_PREF_RANGE_MASK;
+            can_write = 1;
+            */
+            break;
+        case (PCI_PREF_BASE_UPPER32 + 1) ... (PCI_PREF_BASE_UPPER32 + 3):
+            /* 0x28 ... 2b */
+        case (PCI_PREF_LIMIT_UPPER32 + 1) ... (PCI_PREF_LIMIT_UPPER32 + 3):
+            /* 0x2c ... 3f */
+            can_write = 0;
+            /* can_write = 1; */
+            break;
+
+        default:
+            can_write = 1;
+            break;
+        }
+
+        if (can_write)
+            d->config[addr] = val8;
+
+        if (+addr > 0xff)
+            break;
+        val >>= 8;
     }
-    pci_default_write_config(d, address, val, len);
 }
 
 PCIBus *pci_find_bus(int bus_num)
diff --git a/hw/pci.h b/hw/pci.h
index 5993fb3..f5b1052 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -137,6 +137,36 @@ typedef struct PCIIORegion {
 
 #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
 
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
+
+#define PCI_IO_BASE            0x1c    /* I/O range behind the bridge */
+#define PCI_IO_LIMIT           0x1d
+#define  PCI_IO_RANGE_TYPE_MASK        0x0fUL  /* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16  0x00
+#define  PCI_IO_RANGE_TYPE_32  0x01
+#define  PCI_IO_RANGE_MASK     (~0x0fUL)
+#define PCI_MEMORY_BASE                0x20    /* Memory range behind */
+#define PCI_MEMORY_LIMIT       0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_MEMORY_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_MEMORY_BASE   0x24    /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT  0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_PREF_RANGE_TYPE_32        0x00
+#define  PCI_PREF_RANGE_TYPE_64        0x01
+#define  PCI_PREF_RANGE_MASK   (~0x0fUL)
+#define PCI_PREF_BASE_UPPER32  0x28    /* Upper half of prefetchable memory 
range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16    0x30    /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16   0x32
+#define PCI_BRIDGE_CONTROL     0x3e
+
+/* Bits in the PCI Command Register (PCI 2.3 spec) */
+#define PCI_COMMAND_RESERVED_BRIDGE    0xf880
+
+#define PCI_COMMAND_RESERVED_MASK_HI_BRIDGE (PCI_COMMAND_RESERVED >> 8)
+
 struct PCIDevice {
     /* PCI config space */
     uint8_t config[256];
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index b751916..d4c79fc 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -198,7 +198,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
 #if 0 // XXX: not activated as PPC BIOS doesn't handle multiple buses properly
     /* pci-to-pci bridge */
     d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
-                            NULL, NULL);
+                            NULL, pci_bridge_write_config);
     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
     pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
     d->config[0x08] = 0x05; // revision
-- 
1.6.0.2





reply via email to

[Prev in Thread] Current Thread [Next in Thread]