qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up.


From: Isaku Yamahata
Subject: [Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up.
Date: Wed, 13 May 2009 16:50:51 +0900

clean up of pci_default_config_write() with callback.

Changes v4
- export some helper functions
- dropped old_val from callback signature

Changes v3
- recreated on top of Michael's patch.

Changes v2
- converted static table into dynamic initialization.
- changed callback signature.

Cc: Michael S. Tsirkin <address@hidden>
Signed-off-by: Isaku Yamahata <address@hidden>
---
 hw/cirrus_vga.c |    2 +-
 hw/pci.c        |  307 +++++++++++++++++++++++++++++++++++++++++++++++--------
 hw/pci.h        |  107 ++++++++++++++++++-
 3 files changed, 369 insertions(+), 47 deletions(-)

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 32cf3e4..8c5d1fc 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -180,7 +180,7 @@
 #define PCI_COMMAND_PALETTESNOOPING         0x0020
 #define PCI_COMMAND_PARITYDETECTION         0x0040
 #define PCI_COMMAND_ADDRESSDATASTEPPING     0x0080
-#define PCI_COMMAND_SERR                    0x0100
+//#define PCI_COMMAND_SERR                    0x0100   /* duplicated */
 #define PCI_COMMAND_BACKTOBACKTRANS         0x0200
 // PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev)
 #define PCI_CLASS_BASE_DISPLAY        0x03
diff --git a/hw/pci.c b/hw/pci.c
index 99d2afe..e22eab9 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -21,6 +21,9 @@
  * 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"
@@ -48,7 +51,6 @@ struct PCIBus {
     int irq_count[];
 };
 
-static void pci_update_mappings(PCIDevice *d);
 static void pci_set_irq(void *opaque, int irq_num, int level);
 
 target_phys_addr_t pci_mem_base;
@@ -236,22 +238,127 @@ int pci_assign_devaddr(const char *addr, int *domp, int 
*busp, unsigned *slotp)
     return pci_parse_devaddr(devaddr, domp, busp, slotp);
 }
 
-static void pci_init_mask(PCIDevice *dev)
+static void pci_conf_init(struct PCIConfigReg *config_regs,
+                          uint32_t addr, pci_config_written_t callback,
+                          uint32_t wmask, int len)
 {
     int i;
-    dev->mask[PCI_CACHE_LINE_SIZE] = 0xff;
-    dev->mask[PCI_INTERRUPT_LINE] = 0xff;
-    dev->mask[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY
-                             | PCI_COMMAND_MASTER;
-    for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
-        dev->mask[i] = 0xff;
+
+    for (i = 0; i < len; i++) {
+        config_regs[addr].wmask = wmask & 0xff;
+        config_regs[addr].shift = 8 * i;
+        config_regs[addr].callback = callback;
+
+        wmask >>= 8;
+    }
+}
+
+void pci_conf_initb(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask)
+{
+    pci_conf_init(config_regs, addr, callback,  wmask, 1);
+}
+
+void pci_conf_initw(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask)
+{
+    pci_conf_init(config_regs, addr, callback,  wmask, 2);
+}
+
+void pci_conf_initl(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask)
+{
+    pci_conf_init(config_regs, addr, callback,  wmask, 4);
+}
+
+static void pci_conf_update_mappings(struct PCIDevice *d,
+                             uint32_t written, uint32_t mask)
+{
+    pci_update_mappings(d);
+}
+
+static void pci_conf_init_type_00_default(struct PCIConfigReg *config_regs)
+{
+    uint32_t addr;
+
+    /* Vendor ID, Device ID: read only */
+    pci_conf_initw(config_regs, PCI_VENDOR_ID, NULL, 0);
+    pci_conf_initw(config_regs, PCI_DEVICE_ID, NULL, 0);
+
+    pci_conf_initw(config_regs, PCI_COMMAND, pci_conf_update_mappings,
+                   PCI_COMMAND_IO |
+                   PCI_COMMAND_MEMORY |
+                   PCI_COMMAND_MASTER |
+                   PCI_COMMAND_SPECIAL |
+                   PCI_COMMAND_INVALIDATE |
+                   PCI_COMMAND_VGA_PALETTE |
+                   PCI_COMMAND_PARITY |
+                   PCI_COMMAND_WAIT |
+                   PCI_COMMAND_SERR |
+                   PCI_COMMAND_FAST_BACK |
+                   PCI_COMMAND_INTX_DISABLE);
+
+    /* nothing is emulated at this moment */
+    pci_conf_initw(config_regs, PCI_STATUS, NULL, 0);
+
+    /* revision id, class code: read only */
+    pci_conf_initb(config_regs, PCI_REVISION_ID, NULL, 0);
+    pci_conf_init(config_regs, PCI_CLASS_DEVICE, NULL, 0, 3);
+
+    pci_conf_initb(config_regs, PCI_CACHE_LINE_SIZE, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_LATENCY_TIMER, NULL, ~0);
+
+    /* header type: read only */
+    pci_conf_initb(config_regs, PCI_HEADER_TYPE, NULL, 0);
+
+    /* BIST emulation isn't implemented */
+    pci_conf_initb(config_regs, PCI_BIST, NULL, 0);
+
+    /* bar:wmask will be updated by pci_register_io_region() */
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_0,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_1,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_2,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_3,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_4,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_5,
+                   pci_conf_update_mappings, 0);
+
+    /* not card bus*/
+    pci_conf_initl(config_regs, PCI_CARDBUS_CIS, NULL, 0);
+
+    /* Subsystem ID, Subsystem Vendor ID: read only*/
+    pci_conf_initw(config_regs, PCI_SUBSYSTEM_VENDOR_ID, NULL, 0);
+    pci_conf_initw(config_regs, PCI_SUBSYSTEM_ID, NULL, 0);
+
+
+    /* mask will be updated by pci_register_io_region() */
+    pci_conf_initl(config_regs, PCI_ROM_ADDRESS, pci_conf_update_mappings, 0);
+
+    pci_conf_initb(config_regs, PCI_CAPABILITY_LIST, NULL, 0);
+
+    /* offset 0x35 ... 0x3d are reserved so is read only */
+
+    pci_conf_initb(config_regs, PCI_INTERRUPT_LINE, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_INTERRUPT_PIN, NULL, 0);
+    pci_conf_initb(config_regs, PCI_MIN_GNT, NULL, 0);
+    pci_conf_initb(config_regs, PCI_MAX_LAT, NULL, 0);
+
+    /* device dependent part */
+    for (addr = PCI_CONFIG_HEADER_SIZE; addr < PCI_CONFIG_SPACE_SIZE; addr++)
+        pci_conf_initb(config_regs, addr, NULL, ~0);
 }
 
 /* -1 for devfn means auto assign */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
-                               int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read,
-                               PCIConfigWriteFunc *config_write)
+PCIDevice *pci_register_device_confreg(PCIBus *bus, const char *name,
+                                      int instance_size, int devfn,
+                                      PCIConfigReadFunc *config_read,
+                                      PCIConfigWriteFunc *config_write,
+                                       pci_conf_init_t conf_init)
 {
     PCIDevice *pci_dev;
 
@@ -272,7 +379,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char 
*name,
     pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
     memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
     pci_set_default_subsystem_id(pci_dev);
-    pci_init_mask(pci_dev);
+    conf_init(pci_dev->config_regs);
 
     if (!config_read)
         config_read = pci_default_read_config;
@@ -286,6 +393,16 @@ PCIDevice *pci_register_device(PCIBus *bus, const char 
*name,
     return pci_dev;
 }
 
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write)
+{
+    return pci_register_device_confreg(bus, name, instance_size, devfn,
+                                       config_read, config_write,
+                                       pci_conf_init_type_00_default);
+}
+
 static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
 {
     return addr + pci_mem_base;
@@ -334,7 +451,8 @@ void pci_register_io_region(PCIDevice *pci_dev, int 
region_num,
 {
     PCIIORegion *r;
     uint32_t addr;
-    uint32_t mask;
+    uint32_t wmask;
+    int i;
 
     if ((unsigned int)region_num >= PCI_NUM_REGIONS)
         return;
@@ -350,20 +468,21 @@ void pci_register_io_region(PCIDevice *pci_dev, int 
region_num,
     r->size = size;
     r->type = type;
     r->map_func = map_func;
-
-    mask = ~(size - 1);
+    wmask = ~(size - 1);
     if (region_num == PCI_ROM_SLOT) {
         addr = 0x30;
         /* ROM enable bit is writeable */
-        mask |= 1;
+        wmask |= PCI_ROM_ADDRESS_ENABLE;
     } else {
         addr = 0x10 + region_num * 4;
     }
     *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
-    *(uint32_t *)(pci_dev->mask + addr) = cpu_to_le32(mask);
+
+    for (i = 0; i < 4; i++)
+        pci_dev->config_regs[addr + i].wmask = (wmask >> (8 * i)) && 0xff;
 }
 
-static void pci_update_mappings(PCIDevice *d)
+void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
     int cmd, i;
@@ -469,21 +588,45 @@ uint32_t pci_default_read_config(PCIDevice *d,
     return val;
 }
 
-void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
+void pci_default_write_config(PCIDevice *d,
+                              uint32_t addr, uint32_t val, int len)
 {
-    uint8_t orig[PCI_CONFIG_SPACE_SIZE];
     int i;
 
-    /* not efficient, but simple */
-    memcpy(orig, d->config, PCI_CONFIG_SPACE_SIZE);
-    for(i = 0; i < l && addr < PCI_CONFIG_SPACE_SIZE; val >>= 8, ++i, ++addr) {
-        uint8_t mask = d->mask[addr];
-        d->config[addr] = (d->config[addr] & ~mask) | (val & mask);
+    uint32_t written[4] = {0, 0, 0, 0};
+    uint32_t mask[4] = {0, 0, 0, 0};
+    pci_config_written_t callback[4] = {NULL, NULL, NULL, NULL};
+    int nb_written = 0;
+
+    assert(len == 1 || len == 2 || len == 4);
+    for (i = 0; i < len; val >>= 8, ++i) {
+        uint8_t wmask = d->config_regs[addr].wmask;
+        uint8_t shift = d->config_regs[addr].shift;
+        pci_config_written_t c = d->config_regs[addr].callback;
+
+        uint8_t new_val = (d->config[addr] & ~wmask) | (val & wmask);
+        d->config[addr] = new_val;
+
+        if (c != NULL) {
+            if (callback[nb_written] != c) {
+                if (callback[nb_written] != NULL)
+                    nb_written++;
+                callback[nb_written] = c;
+            }
+
+            written[nb_written] |= ((uint32_t)val & 0xff) << shift;
+            mask[nb_written] |= 0xff << shift;
+        }
+
+        if (++addr >= PCI_CONFIG_SPACE_SIZE)
+             break;
     }
-    if (memcmp(orig + PCI_BASE_ADDRESS_0, d->config + PCI_BASE_ADDRESS_0, 24)
-        || ((orig[PCI_COMMAND] ^ d->config[PCI_COMMAND])
-            & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)))
-        pci_update_mappings(d);
+
+    if (callback[nb_written] != NULL)
+        nb_written++;
+
+    for (i = 0; i < nb_written; i++)
+        (callback[i])(d, written[i], mask[i]);
 }
 
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
@@ -750,15 +893,6 @@ typedef struct {
     PCIBus *bus;
 } PCIBridge;
 
-static void pci_bridge_write_config(PCIDevice *d,
-                             uint32_t address, uint32_t val, int len)
-{
-    PCIBridge *s = (PCIBridge *)d;
-
-    pci_default_write_config(d, address, val, len);
-    s->bus->bus_num = d->config[PCI_SECONDARY_BUS];
-}
-
 PCIBus *pci_find_bus(int bus_num)
 {
     PCIBus *bus = first_bus;
@@ -779,12 +913,103 @@ PCIDevice *pci_find_device(int bus_num, int slot, int 
function)
     return bus->devices[PCI_DEVFN(slot, function)];
 }
 
+static void pci_conf_secondary_bus_changed(PCIDevice *d,
+                                           uint32_t written, uint32_t mask)
+{
+    PCIBridge *s = (PCIBridge*) d;
+    s->bus->bus_num = s->dev.config[PCI_SECONDARY_BUS];
+}
+
+static void pci_conf_init_type_01_default(struct PCIConfigReg *config_regs)
+{
+    uint32_t addr;
+
+    /* Vendor ID, Device ID: read only */
+    pci_conf_initw(config_regs, PCI_VENDOR_ID, NULL, 0);
+    pci_conf_initw(config_regs, PCI_DEVICE_ID, NULL, 0);
+
+    pci_conf_initw(config_regs, PCI_COMMAND, pci_conf_update_mappings,
+                   PCI_COMMAND_IO |
+                   PCI_COMMAND_MEMORY |
+                   PCI_COMMAND_MASTER |
+                   PCI_COMMAND_SPECIAL |
+                   PCI_COMMAND_INVALIDATE |
+                   PCI_COMMAND_VGA_PALETTE |
+                   PCI_COMMAND_PARITY |
+                   PCI_COMMAND_WAIT |
+                   PCI_COMMAND_SERR |
+                   PCI_COMMAND_FAST_BACK |
+                   PCI_COMMAND_INTX_DISABLE);
+
+    /* nothing is emulated at this moment */
+    pci_conf_initw(config_regs, PCI_STATUS, NULL, 0);
+
+    /* revision id, class code: read only */
+    pci_conf_initb(config_regs, PCI_REVISION_ID, NULL, 0);
+    pci_conf_init(config_regs, PCI_CLASS_DEVICE, NULL, 0, 3);
+
+    pci_conf_initb(config_regs, PCI_CACHE_LINE_SIZE, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_LATENCY_TIMER, NULL, ~0);
+
+    /* header type: read only */
+    pci_conf_initb(config_regs, PCI_HEADER_TYPE, NULL, 0);
+
+    /* BIST emulation isn't implemented */
+    pci_conf_initb(config_regs, PCI_BIST, NULL, 0);
+
+    /* bar:wmask will be updated by pci_register_io_region() */
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_0,
+                   pci_conf_update_mappings, 0);
+    pci_conf_initl(config_regs, PCI_BASE_ADDRESS_1,
+                   pci_conf_update_mappings, 0);
+
+    pci_conf_initb(config_regs, PCI_PRIMARY_BUS, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_SECONDARY_BUS,
+                   pci_conf_secondary_bus_changed, ~0);
+    pci_conf_initb(config_regs, PCI_SUBORDINATE_BUS, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_SEC_LATENCY_TIMER, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_IO_BASE, NULL, PCI_IO_RANGE_MASK & 0xff);
+    pci_conf_initb(config_regs, PCI_IO_LIMIT, NULL, PCI_IO_RANGE_MASK & 0xff);
+
+    /* sec status isn't emulated (yet) */
+    pci_conf_initw(config_regs, PCI_SEC_STATUS, NULL, 0);
+
+    pci_conf_initw(config_regs, PCI_MEMORY_BASE, NULL,
+                   PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_conf_initw(config_regs, PCI_MEMORY_LIMIT, NULL,
+                   PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_conf_initw(config_regs, PCI_PREF_MEMORY_BASE, NULL,
+                   PCI_PREF_RANGE_MASK & 0xffff);
+    pci_conf_initw(config_regs, PCI_PREF_MEMORY_LIMIT, NULL,
+                   PCI_PREF_RANGE_MASK & 0xffff);
+    pci_conf_initl(config_regs, PCI_PREF_BASE_UPPER32, NULL, ~0);
+    pci_conf_initl(config_regs, PCI_PREF_LIMIT_UPPER32, NULL, ~0);
+
+    /* only support 64K io port */
+    pci_conf_initw(config_regs, PCI_IO_BASE_UPPER16, NULL, 0);
+    pci_conf_initw(config_regs, PCI_IO_LIMIT_UPPER16, NULL, 0);
+
+    pci_conf_initb(config_regs, PCI_CAPABILITY_LIST, NULL, 0);
+
+    /* wmask will be updated by pci_register_io_region() */
+    pci_conf_initl(config_regs, PCI_ROM_ADDRESS1, pci_conf_update_mappings, 0);
+
+    pci_conf_initb(config_regs, PCI_INTERRUPT_LINE, NULL, ~0);
+    pci_conf_initb(config_regs, PCI_INTERRUPT_PIN, NULL, 0);
+    pci_conf_initw(config_regs, PCI_BRIDGE_CONTROL, NULL, ~0);
+
+    /* device dependent part */
+    for (addr = PCI_CONFIG_HEADER_SIZE; addr < PCI_CONFIG_SPACE_SIZE; addr++)
+        pci_conf_initb(config_regs, addr, NULL, ~0);
+}
+
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
                         pci_map_irq_fn map_irq, const char *name)
 {
     PCIBridge *s;
-    s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
-                                         devfn, NULL, pci_bridge_write_config);
+    s = (PCIBridge *)pci_register_device_confreg(bus, name, sizeof(PCIBridge),
+                                                 devfn, NULL, NULL,
+                                                 
pci_conf_init_type_01_default);
 
     pci_config_set_vendor_id(s->dev.config, vid);
     pci_config_set_device_id(s->dev.config, did);
diff --git a/hw/pci.h b/hw/pci.h
index a629e60..0e08a99 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -99,6 +99,14 @@ typedef struct PCIIORegion {
 #define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
 #define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
 #define  PCI_COMMAND_MASTER    0x4     /* Enable bus master */
+#define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE 0x10   /* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20  /* Enable palette snooping */
+#define  PCI_COMMAND_PARITY    0x40    /* Enable parity checking */
+#define  PCI_COMMAND_WAIT      0x80    /* Enable address/data stepping */
+#define  PCI_COMMAND_SERR      0x100   /* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK 0x200   /* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
 #define PCI_STATUS              0x06    /* 16 bits */
 #define PCI_REVISION_ID         0x08    /* 8 bits  */
 #define PCI_CLASS_DEVICE        0x0a    /* Device class */
@@ -109,10 +117,30 @@ typedef struct PCIIORegion {
 #define  PCI_HEADER_TYPE_BRIDGE                1
 #define  PCI_HEADER_TYPE_CARDBUS       2
 #define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+#define PCI_BIST               0x0f    /* 8 bits */
+#define  PCI_BIST_CODE_MASK    0x0f    /* Return result */
+#define  PCI_BIST_START                0x40    /* 1 to start BIST, 2 secs or 
less */
+#define  PCI_BIST_CAPABLE      0x80    /* 1 if BIST capable */
 #define PCI_BASE_ADDRESS_0     0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1     0x14    /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2     0x18    /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3     0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4     0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5     0x24    /* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE                0x01    /* 0 = memory, 1 = I/O 
*/
+#define  PCI_BASE_ADDRESS_SPACE_IO     0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32  0x00    /* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M  0x02    /* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64  0x04    /* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH 0x08    /* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03UL)
 #define PCI_PRIMARY_BUS                0x18    /* Primary bus number */
 #define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
 #define PCI_SEC_STATUS         0x1e    /* Secondary status register, only bit 
14 used */
+#define PCI_CARDBUS_CIS         0x28
 #define PCI_SUBSYSTEM_VENDOR_ID 0x2c    /* 16 bits */
 #define PCI_SUBSYSTEM_ID        0x2e    /* 16 bits */
 #define PCI_CAPABILITY_LIST    0x34    /* Offset of first capability list 
entry */
@@ -125,6 +153,10 @@ typedef struct PCIIORegion {
 #define PCI_SUBVENDOR_ID        0x2c    /* obsolete, use 
PCI_SUBSYSTEM_VENDOR_ID */
 #define PCI_SUBDEVICE_ID        0x2e    /* obsolete, use PCI_SUBSYSTEM_ID */
 
+#define PCI_ROM_ADDRESS         0x30    /* Bits 31..11 are address, 10..1 
reserved */
+#define  PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK    (~0x7ffUL)
+
 /* Bits in the PCI Status Register (PCI 2.3 spec) */
 #define PCI_STATUS_RESERVED1   0x007
 #define PCI_STATUS_INT_STATUS  0x008
@@ -145,17 +177,67 @@ typedef struct PCIIORegion {
 
 #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
 
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS                0x18    /* Primary bus number */
+#define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS    0x1a    /* Highest bus number behind the bridge 
*/
+#define PCI_SEC_LATENCY_TIMER  0x1b    /* Latency timer for secondary 
interface */
+#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_SEC_STATUS         0x1e    /* Secondary status register, only bit 
14 used */
+#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
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1       0x38    /* Same as PCI_ROM_ADDRESS, but for 
htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL     0x3e
+#define  PCI_BRIDGE_CTL_PARITY 0x01    /* Enable parity detection on secondary 
interface */
+#define  PCI_BRIDGE_CTL_SERR   0x02    /* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_ISA    0x04    /* Enable ISA mode */
+#define  PCI_BRIDGE_CTL_VGA    0x08    /* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT   0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET      0x40    /* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK      0x80    /* Fast Back2Back enabled on 
secondary interface */
+
+/* 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)
+
 /* Size of the standard PCI config header */
-#define PCI_CONFIG_HEADER_SIZE (PCI_INTERRUPT_PIN + 1)
+#define PCI_CONFIG_HEADER_SIZE  0x40
 /* Size of the standard PCI config space */
-#define PCI_CONFIG_SPACE_SIZE 0x100
+#define PCI_CONFIG_SPACE_SIZE   0x100
+
+typedef void (*pci_config_written_t)(struct PCIDevice *d,
+                                     uint32_t written, uint32_t mask);
+struct PCIConfigReg {
+    uint8_t wmask;
+    uint8_t shift;
+    pci_config_written_t callback;
+};
 
 struct PCIDevice {
     /* PCI config space */
     uint8_t config[PCI_CONFIG_SPACE_SIZE];
-
-    /* Used to implement R/W bytes */
-    uint8_t mask[PCI_CONFIG_SPACE_SIZE];
+    struct PCIConfigReg config_regs[PCI_CONFIG_SPACE_SIZE];
 
     /* the following fields are read only */
     PCIBus *bus;
@@ -177,6 +259,21 @@ struct PCIDevice {
     int irq_state[4];
 };
 
+typedef void(*pci_conf_init_t)(struct PCIConfigReg*);
+
+void pci_conf_initb(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask);
+void pci_conf_initw(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask);
+void pci_conf_initl(struct PCIConfigReg *config_regs, uint32_t addr,
+                   pci_config_written_t callback, uint32_t wmask);
+void pci_update_mappings(PCIDevice *d);
+
+PCIDevice *pci_register_device_confreg(PCIBus *bus, const char *name,
+                                      int instance_size, int devfn,
+                                      PCIConfigReadFunc *config_read,
+                                      PCIConfigWriteFunc *config_write,
+                                       pci_conf_init_t conf_init);
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
-- 
1.6.0.2





reply via email to

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