All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4
@ 2009-05-13  7:50 Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 1/4] vmware_vga: clean up Isaku Yamahata
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  7:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: yamahata, mtosatti, armbru, mst

This patch series is 4th try for cleaning up pci config space emulation.
Making it table driven with mask and callback.
And this time, I converted pci device to use callback.

Note on pci device conversion:
- cirrus_vga.c
  pci_cirrus_vga_config_write() allways called
  cirrus_update_memory_access().
  By grepping the code roughly I concluded it is unnecessary.
  But I'm not very certain. At least it seems working with my environment.

- wdt_i6300esb.c
  From the code, ESB_CONFIG_REG and ESB_LOCK_REG has only 3bit is valid
  and other bits are read only to 0. But I'm not sure it's correct.


Changes from v3
- changed callback signature
- converted pci device

thanks,

Isaku Yamahata (4):
  vmware_vga: clean up
  qemu: make default_write_config use mask table
  pci: pci_default_config_write() clean up.
  pci/config: convert pci configuration space handler to use callback.

 hw/acpi.c         |   11 +-
 hw/cirrus_vga.c   |   13 +-
 hw/gt64xxx.c      |   13 +--
 hw/pci.c          |  398 +++++++++++++++++++++++++++++++++++-----------------
 hw/pci.h          |  115 +++++++++++++++-
 hw/piix_pci.c     |   18 ++-
 hw/vga.c          |   10 +-
 hw/vmware_vga.c   |    2 +-
 hw/wdt_i6300esb.c |   66 ++++-----
 9 files changed, 440 insertions(+), 206 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/4] vmware_vga: clean up
  2009-05-13  7:50 [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4 Isaku Yamahata
@ 2009-05-13  7:50 ` Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 2/4] qemu: make default_write_config use mask table Isaku Yamahata
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  7:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: yamahata, mtosatti, armbru, mst

use NULL instead of 0 for pci_register_device() argument
for consistency. Any other caller uses NULL.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 hw/vmware_vga.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index ec82f53..ab20562 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1217,7 +1217,7 @@ void pci_vmsvga_init(PCIBus *bus, int vga_ram_size)
     /* Setup PCI configuration */
     s = (struct pci_vmsvga_state_s *)
         pci_register_device(bus, "QEMUware SVGA",
-                sizeof(struct pci_vmsvga_state_s), -1, 0, 0);
+                sizeof(struct pci_vmsvga_state_s), -1, NULL, NULL);
     pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
     pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
     s->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/4] qemu: make default_write_config use mask table
  2009-05-13  7:50 [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4 Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 1/4] vmware_vga: clean up Isaku Yamahata
@ 2009-05-13  7:50 ` Isaku Yamahata
  2009-05-13  8:07   ` [Qemu-devel] " Michael S. Tsirkin
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 4/4] pci/config: convert pci configuration space handler to use callback Isaku Yamahata
  3 siblings, 1 reply; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  7:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: yamahata, mtosatti, armbru, mst

Change much of hw/pci to use symbolic constants and a table-driven
design: add a mask table with writable bits set and readonly bits unset.
Detect change by comparing original and new registers.

As a result, writing a single byte in BAR registers now works as it
should. Writing to upper limit registers in the bridge also works as it
should. Writes to BAR registers trigger mapping update.  Code is also
shorter.

Changelog since v1
- simplify the code some more
- use PCI_CONFIG_SPACE_SIZE instead of 0x100
- only trigger pci update when IO/MEM bits in command register have changed

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/pci.c |  147 +++++++++++++-------------------------------------------------
 hw/pci.h |   18 +++++++-
 2 files changed, 47 insertions(+), 118 deletions(-)

diff --git a/hw/pci.c b/hw/pci.c
index ee7d403..99d2afe 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -236,6 +236,17 @@ 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)
+{
+    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;
+}
+
 /* -1 for devfn means auto assign */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
@@ -261,6 +272,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);
 
     if (!config_read)
         config_read = pci_default_read_config;
@@ -322,6 +334,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
 {
     PCIIORegion *r;
     uint32_t addr;
+    uint32_t mask;
 
     if ((unsigned int)region_num >= PCI_NUM_REGIONS)
         return;
@@ -337,12 +350,17 @@ 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);
     if (region_num == PCI_ROM_SLOT) {
         addr = 0x30;
+        /* ROM enable bit is writeable */
+        mask |= 1;
     } 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);
 }
 
 static void pci_update_mappings(PCIDevice *d)
@@ -451,118 +469,21 @@ uint32_t pci_default_read_config(PCIDevice *d,
     return val;
 }
 
-void pci_default_write_config(PCIDevice *d,
-                              uint32_t address, uint32_t val, int len)
+void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
-    int can_write, i;
-    uint32_t end, addr;
-
-    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
-                     (address >= 0x30 && address < 0x34))) {
-        PCIIORegion *r;
-        int reg;
+    uint8_t orig[PCI_CONFIG_SPACE_SIZE];
+    int i;
 
-        if ( address >= 0x30 ) {
-            reg = PCI_ROM_SLOT;
-        }else{
-            reg = (address - 0x10) >> 2;
-        }
-        r = &d->io_regions[reg];
-        if (r->size == 0)
-            goto default_config;
-        /* compute the stored value */
-        if (reg == PCI_ROM_SLOT) {
-            /* keep ROM enable bit */
-            val &= (~(r->size - 1)) | 1;
-        } else {
-            val &= ~(r->size - 1);
-            val |= r->type;
-        }
-        *(uint32_t *)(d->config + address) = cpu_to_le32(val);
-        pci_update_mappings(d);
-        return;
-    }
- default_config:
     /* not efficient, but simple */
-    addr = address;
-    for(i = 0; i < len; i++) {
-        /* default read/write accesses */
-        switch(d->config[0x0e]) {
-        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;
-            }
-            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;
-            }
-            break;
-        }
-        if (can_write) {
-            /* Mask out writes to reserved bits in registers */
-            switch (addr) {
-	    case 0x05:
-                val &= ~PCI_COMMAND_RESERVED_MASK_HI;
-                break;
-            case 0x06:
-                val &= ~PCI_STATUS_RESERVED_MASK_LO;
-                break;
-            case 0x07:
-                val &= ~PCI_STATUS_RESERVED_MASK_HI;
-                break;
-            }
-            d->config[addr] = val;
-        }
-        if (++addr > 0xff)
-        	break;
-        val >>= 8;
+    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);
     }
-
-    end = address + len;
-    if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
-        /* if the command register is modified, we must modify the mappings */
+    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);
-    }
 }
 
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
@@ -834,16 +755,8 @@ static void pci_bridge_write_config(PCIDevice *d,
 {
     PCIBridge *s = (PCIBridge *)d;
 
-    if (address == 0x19 || (address == 0x18 && len > 1)) {
-        if (address == 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
-    }
     pci_default_write_config(d, address, val, len);
+    s->bus->bus_num = d->config[PCI_SECONDARY_BUS];
 }
 
 PCIBus *pci_find_bus(int bus_num)
diff --git a/hw/pci.h b/hw/pci.h
index ff858a1..a629e60 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -98,16 +98,24 @@ typedef struct PCIIORegion {
 #define PCI_COMMAND		0x04	/* 16 bits */
 #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_STATUS              0x06    /* 16 bits */
 #define PCI_REVISION_ID         0x08    /* 8 bits  */
 #define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
 #define PCI_HEADER_TYPE         0x0e    /* 8 bits */
 #define  PCI_HEADER_TYPE_NORMAL		0
 #define  PCI_HEADER_TYPE_BRIDGE		1
 #define  PCI_HEADER_TYPE_CARDBUS	2
 #define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#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_SUBSYSTEM_VENDOR_ID 0x2c    /* 16 bits */
 #define PCI_SUBSYSTEM_ID        0x2e    /* 16 bits */
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
 #define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
 #define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */
 #define PCI_MIN_GNT		0x3e	/* 8 bits */
@@ -137,9 +145,17 @@ typedef struct PCIIORegion {
 
 #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
 
+/* Size of the standard PCI config header */
+#define PCI_CONFIG_HEADER_SIZE (PCI_INTERRUPT_PIN + 1)
+/* Size of the standard PCI config space */
+#define PCI_CONFIG_SPACE_SIZE 0x100
+
 struct PCIDevice {
     /* PCI config space */
-    uint8_t config[256];
+    uint8_t config[PCI_CONFIG_SPACE_SIZE];
+
+    /* Used to implement R/W bytes */
+    uint8_t mask[PCI_CONFIG_SPACE_SIZE];
 
     /* the following fields are read only */
     PCIBus *bus;
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up.
  2009-05-13  7:50 [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4 Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 1/4] vmware_vga: clean up Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 2/4] qemu: make default_write_config use mask table Isaku Yamahata
@ 2009-05-13  7:50 ` Isaku Yamahata
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 4/4] pci/config: convert pci configuration space handler to use callback Isaku Yamahata
  3 siblings, 0 replies; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  7:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: yamahata, mtosatti, armbru, mst

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 <mst@redhat.com>
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 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

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 4/4] pci/config: convert pci configuration space handler to use callback.
  2009-05-13  7:50 [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4 Isaku Yamahata
                   ` (2 preceding siblings ...)
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up Isaku Yamahata
@ 2009-05-13  7:50 ` Isaku Yamahata
  3 siblings, 0 replies; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  7:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: yamahata, mtosatti, armbru, mst

convert pci configuration space handler into callbacks.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 hw/acpi.c         |   11 ++++-----
 hw/cirrus_vga.c   |   11 +++++----
 hw/gt64xxx.c      |   13 +---------
 hw/piix_pci.c     |   18 +++++++++-----
 hw/vga.c          |   10 +++++---
 hw/wdt_i6300esb.c |   66 +++++++++++++++++++++-------------------------------
 6 files changed, 56 insertions(+), 73 deletions(-)

diff --git a/hw/acpi.c b/hw/acpi.c
index dbaf18a..ef11088 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -433,12 +433,10 @@ static void pm_io_space_update(PIIX4PMState *s)
     }
 }
 
-static void pm_write_config(PCIDevice *d,
-                            uint32_t address, uint32_t val, int len)
+static void pm_write_config_0x80(struct PCIDevice *d,
+                                 uint32_t written, uint32_t mask)
 {
-    pci_default_write_config(d, address, val, len);
-    if (address == 0x80)
-        pm_io_space_update((PIIX4PMState *)d);
+    pm_io_space_update((PIIX4PMState *)d);
 }
 
 static void pm_save(QEMUFile* f,void *opaque)
@@ -505,7 +503,8 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
 
     s = (PIIX4PMState *)pci_register_device(bus,
                                          "PM", sizeof(PIIX4PMState),
-                                         devfn, NULL, pm_write_config);
+                                         devfn, NULL, NULL);
+    pci_conf_initb(s->dev.config_regs, 0x80, pm_write_config_0x80, 1);
     pm_state = s;
     pci_conf = s->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 8c5d1fc..5751636 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3289,16 +3289,15 @@ static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
 				 s->cirrus_mmio_io_addr);
 }
 
-static void pci_cirrus_write_config(PCIDevice *d,
-                                    uint32_t address, uint32_t val, int len)
+static void pci_cirrus_write_config_bar0(struct PCIDevice *d,
+                                         uint32_t written, uint32_t mask)
 {
     PCICirrusVGAState *pvs = container_of(d, PCICirrusVGAState, dev);
     CirrusVGAState *s = &pvs->cirrus_vga;
 
-    pci_default_write_config(d, address, val, len);
+    pci_update_mappings(d);
     if (s->vga.map_addr && pvs->dev.io_regions[0].addr == -1)
         s->vga.map_addr = 0;
-    cirrus_update_memory_access(s);
 }
 
 void pci_cirrus_vga_init(PCIBus *bus, int vga_ram_size)
@@ -3313,7 +3312,9 @@ void pci_cirrus_vga_init(PCIBus *bus, int vga_ram_size)
     /* setup PCI configuration registers */
     d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA",
                                                  sizeof(PCICirrusVGAState),
-                                                 -1, NULL, pci_cirrus_write_config);
+                                                 -1, NULL, NULL);
+    pci_conf_initl(d->dev.config_regs, PCI_BASE_ADDRESS_0,
+                   pci_cirrus_write_config_bar0, 0);
     pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CIRRUS);
     pci_config_set_device_id(pci_conf, device_id);
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 7fc91dd..2581cd0 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1083,17 +1083,6 @@ static void gt64120_reset(void *opaque)
     gt64120_pci_mapping(s);
 }
 
-static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len)
-{
-    return pci_default_read_config(d, address, len);
-}
-
-static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val,
-                                 int len)
-{
-    pci_default_write_config(d, address, val, len);
-}
-
 static void gt64120_save(QEMUFile* f, void *opaque)
 {
     PCIDevice *d = opaque;
@@ -1132,7 +1121,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
                                    pic, 144, 4);
     s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s);
     d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
-                            0, gt64120_read_config, gt64120_write_config);
+                            0, NULL, NULL);
 
     /* FIXME: Malta specific hw assumptions ahead */
 
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 2b19cc6..d241882 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -128,13 +128,11 @@ void i440fx_init_memory_mappings(PCIDevice *d)
     }
 }
 
-static void i440fx_write_config(PCIDevice *d,
-                                uint32_t address, uint32_t val, int len)
+/* XXX: implement SMRAM.D_LOCK */
+static void i440fx_write_config_0x59_0x5f_0x72(struct PCIDevice *d,
+                                               uint32_t written, uint32_t mask)
 {
-    /* XXX: implement SMRAM.D_LOCK */
-    pci_default_write_config(d, address, val, len);
-    if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
-        i440fx_update_memory_mappings(d);
+    i440fx_update_memory_mappings(d);
 }
 
 static void i440fx_save(QEMUFile* f, void *opaque)
@@ -174,6 +172,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
     PCIBus *b;
     PCIDevice *d;
     I440FXState *s;
+    uint32_t addr;
 
     s = qemu_mallocz(sizeof(I440FXState));
     b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
@@ -190,7 +189,12 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
     register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
 
     d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
-                            NULL, i440fx_write_config);
+                            NULL, NULL);
+    for (addr = 0x59; addr <= 0x5f; addr++)
+        pci_conf_initb(d->config_regs, addr,
+                       i440fx_write_config_0x59_0x5f_0x72, 0xff);
+    pci_conf_initb(d->config_regs, 0x72,
+                   i440fx_write_config_0x59_0x5f_0x72, 0xff);
 
     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
     pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_82441);
diff --git a/hw/vga.c b/hw/vga.c
index 2de92af..57e6044 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2469,13 +2469,13 @@ int isa_vga_mm_init(int vga_ram_size, target_phys_addr_t vram_base,
     return 0;
 }
 
-static void pci_vga_write_config(PCIDevice *d,
-                                 uint32_t address, uint32_t val, int len)
+static void pci_vga_write_config_bar0(struct PCIDevice *d,
+                                      uint32_t written, uint32_t mask)
 {
     PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
     VGAState *s = &pvs->vga_state;
 
-    pci_default_write_config(d, address, val, len);
+    pci_update_mappings(d);
     if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
         s->map_addr = 0;
 }
@@ -2489,9 +2489,11 @@ int pci_vga_init(PCIBus *bus, int vga_ram_size,
 
     d = (PCIVGAState *)pci_register_device(bus, "VGA",
                                            sizeof(PCIVGAState),
-                                           -1, NULL, pci_vga_write_config);
+                                           -1, NULL, NULL);
     if (!d)
         return -1;
+    pci_conf_initl(&d->dev.config_regs, PCI_BASE_ADDRESS_0,
+                   pci_vga_write_config_bar0, 0);
     s = &d->vga_state;
 
     vga_common_init(s, vga_ram_size);
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index f7ddea2..9e90704 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -198,56 +198,39 @@ static void i6300esb_timer_expired(void *vp)
     }
 }
 
-static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
-                                  uint32_t data, int len)
+static void i6300esb_config_write_esb_config_reg(struct PCIDevice *dev,
+                                                 uint32_t data, uint32_t mask)
 {
     I6300State *d = (I6300State *) dev;
-    int old;
 
     i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
 
-    if (addr == ESB_CONFIG_REG && len == 2) {
+    if (mask & ESB_WDT_REBOOT)
         d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
+    if (mask & ESB_WDT_FREQ)
         d->clock_scale =
             (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
+    if (mask & ESB_WDT_INTTYPE)
         d->int_type = (data & ESB_WDT_INTTYPE);
-    } else if (addr == ESB_LOCK_REG && len == 1) {
-        if (!d->locked) {
-            d->locked = (data & ESB_WDT_LOCK) != 0;
-            d->free_run = (data & ESB_WDT_FUNC) != 0;
-            old = d->enabled;
-            d->enabled = (data & ESB_WDT_ENABLE) != 0;
-            if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
-                i6300esb_restart_timer(d, 1);
-            else if (!d->enabled)
-                i6300esb_disable_timer(d);
-        }
-    } else {
-        pci_default_write_config(dev, addr, data, len);
-    }
 }
 
-static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
+static void i6300esb_config_write_esb_lock_reg(struct PCIDevice *dev,
+					       uint32_t data, uint32_t mask)
 {
     I6300State *d = (I6300State *) dev;
-    uint32_t data;
-
-    i6300esb_debug ("addr = %x, len = %d\n", addr, len);
-
-    if (addr == ESB_CONFIG_REG && len == 2) {
-        data =
-            (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
-            (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
-            d->int_type;
-        return data;
-    } else if (addr == ESB_LOCK_REG && len == 1) {
-        data =
-            (d->free_run ? ESB_WDT_FUNC : 0) |
-            (d->locked ? ESB_WDT_LOCK : 0) |
-            (d->enabled ? ESB_WDT_ENABLE : 0);
-        return data;
-    } else {
-        return pci_default_read_config(dev, addr, len);
+    int old;
+
+    i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
+
+    if (!d->locked) {
+        d->locked = (data & ESB_WDT_LOCK) != 0;
+        d->free_run = (data & ESB_WDT_FUNC) != 0;
+        old = d->enabled;
+        d->enabled = (data & ESB_WDT_ENABLE) != 0;
+        if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
+            i6300esb_restart_timer(d, 1);
+        else if (!d->enabled)
+            i6300esb_disable_timer(d);
     }
 }
 
@@ -429,8 +412,13 @@ static void i6300esb_pc_init(PCIBus *pci_bus)
 
     d = (I6300State *)
         pci_register_device (pci_bus, "i6300esb_wdt", sizeof (I6300State),
-                             -1,
-                             i6300esb_config_read, i6300esb_config_write);
+                             -1, NULL, NULL);
+    pci_conf_initw(d->dev.config_regs, ESB_CONFIG_REG,
+                   i6300esb_config_write_esb_config_reg,
+                   ESB_WDT_REBOOT | ESB_WDT_FREQ | ESB_WDT_INTTYPE);
+    pci_conf_initb(d->dev.config_regs, ESB_LOCK_REG,
+                   i6300esb_config_write_esb_lock_reg,
+                   ESB_WDT_FUNC | ESB_WDT_LOCK | ESB_WDT_ENABLE);
 
     d->reboot_enabled = 1;
     d->clock_scale = CLOCK_SCALE_1KHZ;
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] Re: [PATCH 2/4] qemu: make default_write_config use mask table
  2009-05-13  7:50 ` [Qemu-devel] [PATCH 2/4] qemu: make default_write_config use mask table Isaku Yamahata
@ 2009-05-13  8:07   ` Michael S. Tsirkin
  2009-05-13  8:27     ` Isaku Yamahata
  0 siblings, 1 reply; 8+ messages in thread
From: Michael S. Tsirkin @ 2009-05-13  8:07 UTC (permalink / raw)
  To: Isaku Yamahata; +Cc: mtosatti, qemu-devel, armbru

On Wed, May 13, 2009 at 04:50:50PM +0900, Isaku Yamahata wrote:
> Change much of hw/pci to use symbolic constants and a table-driven
> design: add a mask table with writable bits set and readonly bits unset.
> Detect change by comparing original and new registers.
> 
> As a result, writing a single byte in BAR registers now works as it
> should. Writing to upper limit registers in the bridge also works as it
> should. Writes to BAR registers trigger mapping update.  Code is also
> shorter.
> 
> Changelog since v1
> - simplify the code some more
> - use PCI_CONFIG_SPACE_SIZE instead of 0x100
> - only trigger pci update when IO/MEM bits in command register have changed
> 
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

You must also add
From: Michael S. Tsirkin <mst@redhat.com>

at the top, otherwise git won't record the authorship
information in log correctly.

-- 
MST

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] Re: [PATCH 2/4] qemu: make default_write_config use mask table
  2009-05-13  8:07   ` [Qemu-devel] " Michael S. Tsirkin
@ 2009-05-13  8:27     ` Isaku Yamahata
  2009-05-13  8:45       ` Michael S. Tsirkin
  0 siblings, 1 reply; 8+ messages in thread
From: Isaku Yamahata @ 2009-05-13  8:27 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: mtosatti, qemu-devel, armbru

On Wed, May 13, 2009 at 11:07:24AM +0300, Michael S. Tsirkin wrote:
> On Wed, May 13, 2009 at 04:50:50PM +0900, Isaku Yamahata wrote:
> > Change much of hw/pci to use symbolic constants and a table-driven
> > design: add a mask table with writable bits set and readonly bits unset.
> > Detect change by comparing original and new registers.
> > 
> > As a result, writing a single byte in BAR registers now works as it
> > should. Writing to upper limit registers in the bridge also works as it
> > should. Writes to BAR registers trigger mapping update.  Code is also
> > shorter.
> > 
> > Changelog since v1
> > - simplify the code some more
> > - use PCI_CONFIG_SPACE_SIZE instead of 0x100
> > - only trigger pci update when IO/MEM bits in command register have changed
> > 
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> 
> You must also add
> From: Michael S. Tsirkin <mst@redhat.com>
> 
> at the top, otherwise git won't record the authorship
> information in log correctly.

Oh sorry, does this looks okay?

From: Michael S. Tsirkin <mst@redhat.com>

Change much of hw/pci to use symbolic constants and a table-driven
design: add a mask table with writable bits set and readonly bits unset.
Detect change by comparing original and new registers.

As a result, writing a single byte in BAR registers now works as it
should. Writing to upper limit registers in the bridge also works as it
should. Writes to BAR registers trigger mapping update.  Code is also
shorter.

Changelog since v1
- simplify the code some more
- use PCI_CONFIG_SPACE_SIZE instead of 0x100
- only trigger pci update when IO/MEM bits in command register have changed

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/pci.c |  147 +++++++++++++-------------------------------------------------
 hw/pci.h |   18 +++++++-
 2 files changed, 47 insertions(+), 118 deletions(-)

diff --git a/hw/pci.c b/hw/pci.c
index ee7d403..99d2afe 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -236,6 +236,17 @@ 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)
+{
+    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;
+}
+
 /* -1 for devfn means auto assign */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
@@ -261,6 +272,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);
 
     if (!config_read)
         config_read = pci_default_read_config;
@@ -322,6 +334,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
 {
     PCIIORegion *r;
     uint32_t addr;
+    uint32_t mask;
 
     if ((unsigned int)region_num >= PCI_NUM_REGIONS)
         return;
@@ -337,12 +350,17 @@ 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);
     if (region_num == PCI_ROM_SLOT) {
         addr = 0x30;
+        /* ROM enable bit is writeable */
+        mask |= 1;
     } 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);
 }
 
 static void pci_update_mappings(PCIDevice *d)
@@ -451,118 +469,21 @@ uint32_t pci_default_read_config(PCIDevice *d,
     return val;
 }
 
-void pci_default_write_config(PCIDevice *d,
-                              uint32_t address, uint32_t val, int len)
+void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
-    int can_write, i;
-    uint32_t end, addr;
-
-    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
-                     (address >= 0x30 && address < 0x34))) {
-        PCIIORegion *r;
-        int reg;
+    uint8_t orig[PCI_CONFIG_SPACE_SIZE];
+    int i;
 
-        if ( address >= 0x30 ) {
-            reg = PCI_ROM_SLOT;
-        }else{
-            reg = (address - 0x10) >> 2;
-        }
-        r = &d->io_regions[reg];
-        if (r->size == 0)
-            goto default_config;
-        /* compute the stored value */
-        if (reg == PCI_ROM_SLOT) {
-            /* keep ROM enable bit */
-            val &= (~(r->size - 1)) | 1;
-        } else {
-            val &= ~(r->size - 1);
-            val |= r->type;
-        }
-        *(uint32_t *)(d->config + address) = cpu_to_le32(val);
-        pci_update_mappings(d);
-        return;
-    }
- default_config:
     /* not efficient, but simple */
-    addr = address;
-    for(i = 0; i < len; i++) {
-        /* default read/write accesses */
-        switch(d->config[0x0e]) {
-        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;
-            }
-            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;
-            }
-            break;
-        }
-        if (can_write) {
-            /* Mask out writes to reserved bits in registers */
-            switch (addr) {
-	    case 0x05:
-                val &= ~PCI_COMMAND_RESERVED_MASK_HI;
-                break;
-            case 0x06:
-                val &= ~PCI_STATUS_RESERVED_MASK_LO;
-                break;
-            case 0x07:
-                val &= ~PCI_STATUS_RESERVED_MASK_HI;
-                break;
-            }
-            d->config[addr] = val;
-        }
-        if (++addr > 0xff)
-        	break;
-        val >>= 8;
+    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);
     }
-
-    end = address + len;
-    if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
-        /* if the command register is modified, we must modify the mappings */
+    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);
-    }
 }
 
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
@@ -834,16 +755,8 @@ static void pci_bridge_write_config(PCIDevice *d,
 {
     PCIBridge *s = (PCIBridge *)d;
 
-    if (address == 0x19 || (address == 0x18 && len > 1)) {
-        if (address == 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
-    }
     pci_default_write_config(d, address, val, len);
+    s->bus->bus_num = d->config[PCI_SECONDARY_BUS];
 }
 
 PCIBus *pci_find_bus(int bus_num)
diff --git a/hw/pci.h b/hw/pci.h
index ff858a1..a629e60 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -98,16 +98,24 @@ typedef struct PCIIORegion {
 #define PCI_COMMAND		0x04	/* 16 bits */
 #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_STATUS              0x06    /* 16 bits */
 #define PCI_REVISION_ID         0x08    /* 8 bits  */
 #define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
 #define PCI_HEADER_TYPE         0x0e    /* 8 bits */
 #define  PCI_HEADER_TYPE_NORMAL		0
 #define  PCI_HEADER_TYPE_BRIDGE		1
 #define  PCI_HEADER_TYPE_CARDBUS	2
 #define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#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_SUBSYSTEM_VENDOR_ID 0x2c    /* 16 bits */
 #define PCI_SUBSYSTEM_ID        0x2e    /* 16 bits */
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
 #define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
 #define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */
 #define PCI_MIN_GNT		0x3e	/* 8 bits */
@@ -137,9 +145,17 @@ typedef struct PCIIORegion {
 
 #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
 
+/* Size of the standard PCI config header */
+#define PCI_CONFIG_HEADER_SIZE (PCI_INTERRUPT_PIN + 1)
+/* Size of the standard PCI config space */
+#define PCI_CONFIG_SPACE_SIZE 0x100
+
 struct PCIDevice {
     /* PCI config space */
-    uint8_t config[256];
+    uint8_t config[PCI_CONFIG_SPACE_SIZE];
+
+    /* Used to implement R/W bytes */
+    uint8_t mask[PCI_CONFIG_SPACE_SIZE];
 
     /* the following fields are read only */
     PCIBus *bus;
-- 
1.6.0.2



-- 
yamahata

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] Re: [PATCH 2/4] qemu: make default_write_config use mask table
  2009-05-13  8:27     ` Isaku Yamahata
@ 2009-05-13  8:45       ` Michael S. Tsirkin
  0 siblings, 0 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2009-05-13  8:45 UTC (permalink / raw)
  To: Isaku Yamahata; +Cc: mtosatti, qemu-devel, armbru

On Wed, May 13, 2009 at 05:27:46PM +0900, Isaku Yamahata wrote:
> On Wed, May 13, 2009 at 11:07:24AM +0300, Michael S. Tsirkin wrote:
> > On Wed, May 13, 2009 at 04:50:50PM +0900, Isaku Yamahata wrote:
> > > Change much of hw/pci to use symbolic constants and a table-driven
> > > design: add a mask table with writable bits set and readonly bits unset.
> > > Detect change by comparing original and new registers.
> > > 
> > > As a result, writing a single byte in BAR registers now works as it
> > > should. Writing to upper limit registers in the bridge also works as it
> > > should. Writes to BAR registers trigger mapping update.  Code is also
> > > shorter.
> > > 
> > > Changelog since v1
> > > - simplify the code some more
> > > - use PCI_CONFIG_SPACE_SIZE instead of 0x100
> > > - only trigger pci update when IO/MEM bits in command register have changed
> > > 
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > 
> > You must also add
> > From: Michael S. Tsirkin <mst@redhat.com>
> > 
> > at the top, otherwise git won't record the authorship
> > information in log correctly.
> 
> Oh sorry, does this looks okay?
> 
> From: Michael S. Tsirkin <mst@redhat.com>
> 
> Change much of hw/pci to use symbolic constants and a table-driven
> design: add a mask table with writable bits set and readonly bits unset.
> Detect change by comparing original and new registers.
> 
> As a result, writing a single byte in BAR registers now works as it
> should. Writing to upper limit registers in the bridge also works as it
> should. Writes to BAR registers trigger mapping update.  Code is also
> shorter.
> 
> Changelog since v1
> - simplify the code some more
> - use PCI_CONFIG_SPACE_SIZE instead of 0x100
> - only trigger pci update when IO/MEM bits in command register have changed
> 
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  hw/pci.c |  147 +++++++++++++-------------------------------------------------
>  hw/pci.h |   18 +++++++-
>  2 files changed, 47 insertions(+), 118 deletions(-)
> 

Right. But Changelog should come after ---: you want git to ignore it.

-- 
MST

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-05-13  8:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-13  7:50 [Qemu-devel] [PATCH 0/4] pci config space emulation clean up TAKE 4 Isaku Yamahata
2009-05-13  7:50 ` [Qemu-devel] [PATCH 1/4] vmware_vga: clean up Isaku Yamahata
2009-05-13  7:50 ` [Qemu-devel] [PATCH 2/4] qemu: make default_write_config use mask table Isaku Yamahata
2009-05-13  8:07   ` [Qemu-devel] " Michael S. Tsirkin
2009-05-13  8:27     ` Isaku Yamahata
2009-05-13  8:45       ` Michael S. Tsirkin
2009-05-13  7:50 ` [Qemu-devel] [PATCH 3/4] pci: pci_default_config_write() clean up Isaku Yamahata
2009-05-13  7:50 ` [Qemu-devel] [PATCH 4/4] pci/config: convert pci configuration space handler to use callback Isaku Yamahata

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.