* [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