From 783753fd53fe513d37fbbfe6694c0c1ab9701fd1 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 13 Jul 2010 13:01:39 +0900 Subject: pci/bridge: split out pci bridge code into pci_bridge.c from pci.c Move pci bridge related code into pci_bridge.c from pci.c for further enhancement. pci.c is big enough now, so split it out. No code change but exporting some accesser functions. In fact, few pci bridge functions stays in pci.c. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/dec_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/dec_pci.c') diff --git a/hw/dec_pci.c b/hw/dec_pci.c index ee49d5adf0..f7a9cdcfc3 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -27,6 +27,7 @@ #include "sysbus.h" #include "pci.h" #include "pci_host.h" +#include "pci_bridge.h" /* debug DEC */ //#define DEBUG_DEC -- cgit v1.2.3-55-g7522 From 68f799944b72387c0ef9535612a212a5ea492059 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 13 Jul 2010 13:01:42 +0900 Subject: pci_bridge: introduce pci bridge library. introduce pci bridge library. convert apb bridge and dec p2p bridge to use new pci bridge library. save/restore is supported as a side effect. This is also preparation for pci express root/upstream/downstream port. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/apb_pci.c | 55 ++++++++++++++++++------ hw/dec_pci.c | 45 ++++++++++++++++---- hw/pci_bridge.c | 122 ++++++++++++++++++++++++++++++----------------------- hw/pci_bridge.h | 24 ++++++++--- hw/pci_internals.h | 15 +++++-- qemu-common.h | 1 + 6 files changed, 178 insertions(+), 84 deletions(-) (limited to 'hw/dec_pci.c') diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 88ee4a9d92..c619112b12 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -30,6 +30,7 @@ #include "pci.h" #include "pci_host.h" #include "pci_bridge.h" +#include "pci_internals.h" #include "rwhandler.h" #include "apb_pci.h" #include "sysemu.h" @@ -294,9 +295,17 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level) } } -static void apb_pci_bridge_init(PCIBus *b) +static int apb_pci_bridge_initfn(PCIDevice *dev) { - PCIDevice *dev = pci_bridge_get_device(b); + int rc; + + rc = pci_bridge_initfn(dev); + if (rc < 0) { + return rc; + } + + pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN); + pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA); /* * command register: @@ -313,6 +322,7 @@ static void apb_pci_bridge_init(PCIBus *b) PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); pci_set_byte(dev->config + PCI_REVISION_ID, 0x11); + return 0; } PCIBus *pci_apb_init(target_phys_addr_t special_base, @@ -323,6 +333,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, SysBusDevice *s; APBState *d; unsigned int i; + PCIDevice *pci_dev; + PCIBridge *br; /* Ultrasparc PBM main bus */ dev = qdev_create(NULL, "pbm"); @@ -348,17 +360,21 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, pci_create_simple(d->bus, 0, "pbm"); /* APB secondary busses */ - *bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0), true, - PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, - pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 1"); - apb_pci_bridge_init(*bus2); - - *bus3 = pci_bridge_init(d->bus, PCI_DEVFN(1, 1), true, - PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, - pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 2"); - apb_pci_bridge_init(*bus3); + pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true, + "pbm-bridge"); + br = DO_UPCAST(PCIBridge, dev, pci_dev); + pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1", + pci_apb_map_irq); + qdev_init_nofail(&pci_dev->qdev); + *bus2 = pci_bridge_get_sec_bus(br); + + pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true, + "pbm-bridge"); + br = DO_UPCAST(PCIBridge, dev, pci_dev); + pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2", + pci_apb_map_irq); + qdev_init_nofail(&pci_dev->qdev); + *bus3 = pci_bridge_get_sec_bus(br); return d->bus; } @@ -441,10 +457,23 @@ static SysBusDeviceInfo pbm_host_info = { .qdev.reset = pci_pbm_reset, .init = pci_pbm_init_device, }; + +static PCIDeviceInfo pbm_pci_bridge_info = { + .qdev.name = "pbm-bridge", + .qdev.size = sizeof(PCIBridge), + .qdev.vmsd = &vmstate_pci_device, + .qdev.reset = pci_bridge_reset, + .init = apb_pci_bridge_initfn, + .exit = pci_bridge_exitfn, + .config_write = pci_bridge_write_config, + .is_bridge = 1, +}; + static void pbm_register_devices(void) { sysbus_register_withprop(&pbm_host_info); pci_qdev_register(&pbm_pci_host_info); + pci_qdev_register(&pbm_pci_bridge_info); } device_init(pbm_register_devices) diff --git a/hw/dec_pci.c b/hw/dec_pci.c index f7a9cdcfc3..aa07ab7d84 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -28,6 +28,7 @@ #include "pci.h" #include "pci_host.h" #include "pci_bridge.h" +#include "pci_internals.h" /* debug DEC */ //#define DEBUG_DEC @@ -49,18 +50,43 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num) return irq_num; } -PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) +static int dec_21154_initfn(PCIDevice *dev) { - DeviceState *dev; - PCIBus *ret; + int rc; + + rc = pci_bridge_initfn(dev); + if (rc < 0) { + return rc; + } + + pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC); + pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154); + return 0; +} - dev = qdev_create(NULL, "dec-21154"); - qdev_init_nofail(dev); - ret = pci_bridge_init(parent_bus, devfn, false, - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154, - dec_map_irq, "DEC 21154 PCI-PCI bridge"); +static PCIDeviceInfo dec_21154_pci_bridge_info = { + .qdev.name = "dec-21154-p2p-bridge", + .qdev.desc = "DEC 21154 PCI-PCI bridge", + .qdev.size = sizeof(PCIBridge), + .qdev.vmsd = &vmstate_pci_device, + .qdev.reset = pci_bridge_reset, + .init = dec_21154_initfn, + .exit = pci_bridge_exitfn, + .config_write = pci_bridge_write_config, + .is_bridge = 1, +}; + +PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) +{ + PCIDevice *dev; + PCIBridge *br; - return ret; + dev = pci_create_multifunction(parent_bus, devfn, false, + "dec-21154-p2p-bridge"); + br = DO_UPCAST(PCIBridge, dev, dev); + pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq); + qdev_init_nofail(&dev->qdev); + return pci_bridge_get_sec_bus(br); } static int pci_dec_21154_init_device(SysBusDevice *dev) @@ -99,6 +125,7 @@ static void dec_register_devices(void) sysbus_register_dev("dec-21154", sizeof(DECState), pci_dec_21154_init_device); pci_qdev_register(&dec_21154_pci_host_info); + pci_qdev_register(&dec_21154_pci_bridge_info); } device_init(dec_register_devices) diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index 2f13c7dd5d..198c3c7908 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -32,12 +32,19 @@ #include "pci_bridge.h" #include "pci_internals.h" +/* Accessor function to get parent bridge device from pci bus. */ PCIDevice *pci_bridge_get_device(PCIBus *bus) { return bus->parent_dev; } -static uint32_t pci_config_get_io_base(PCIDevice *d, +/* Accessor function to get secondary bus from pci-to-pci bridge device */ +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) +{ + return &br->sec_bus; +} + +static uint32_t pci_config_get_io_base(const PCIDevice *d, uint32_t base, uint32_t base_upper16) { uint32_t val; @@ -49,13 +56,13 @@ static uint32_t pci_config_get_io_base(PCIDevice *d, return val; } -static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) +static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base) { return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) << 16; } -static pcibus_t pci_config_get_pref_base(PCIDevice *d, +static pcibus_t pci_config_get_pref_base(const PCIDevice *d, uint32_t base, uint32_t upper) { pcibus_t tmp; @@ -69,7 +76,8 @@ static pcibus_t pci_config_get_pref_base(PCIDevice *d, return val; } -pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type) +/* accessor function to get bridge filtering base address */ +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type) { pcibus_t base; if (type & PCI_BASE_ADDRESS_SPACE_IO) { @@ -87,7 +95,8 @@ pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type) return base; } -pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type) +/* accessor funciton to get bridge filtering limit */ +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) { pcibus_t limit; if (type & PCI_BASE_ADDRESS_SPACE_IO) { @@ -106,7 +115,8 @@ pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type) return limit; } -static void pci_bridge_write_config(PCIDevice *d, +/* default write_config function for PCI-to-PCI bridge */ +void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); @@ -122,12 +132,41 @@ static void pci_bridge_write_config(PCIDevice *d, } } -static int pci_bridge_initfn(PCIDevice *dev) +/* reset bridge specific configuration registers */ +void pci_bridge_reset_reg(PCIDevice *dev) +{ + uint8_t *conf = dev->config; + + conf[PCI_PRIMARY_BUS] = 0; + conf[PCI_SECONDARY_BUS] = 0; + conf[PCI_SUBORDINATE_BUS] = 0; + conf[PCI_SEC_LATENCY_TIMER] = 0; + + conf[PCI_IO_BASE] = 0; + conf[PCI_IO_LIMIT] = 0; + pci_set_word(conf + PCI_MEMORY_BASE, 0); + pci_set_word(conf + PCI_MEMORY_LIMIT, 0); + pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0); + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0); + pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0); + pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0); + + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0); +} + +/* default reset function for PCI-to-PCI bridge */ +void pci_bridge_reset(DeviceState *qdev) { - PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev); + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); + pci_bridge_reset_reg(dev); +} - pci_config_set_vendor_id(s->dev.config, s->vid); - pci_config_set_device_id(s->dev.config, s->did); +/* default qdev initialization function for PCI-to-PCI bridge */ +int pci_bridge_initfn(PCIDevice *dev) +{ + PCIBus *parent = dev->bus; + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); + PCIBus *sec_bus = &br->sec_bus; pci_set_word(dev->config + PCI_STATUS, PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); @@ -137,58 +176,35 @@ static int pci_bridge_initfn(PCIDevice *dev) PCI_HEADER_TYPE_BRIDGE; pci_set_word(dev->config + PCI_SEC_STATUS, PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); + + qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, + br->bus_name); + sec_bus->parent_dev = dev; + sec_bus->map_irq = br->map_irq; + + QLIST_INIT(&sec_bus->child); + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); return 0; } -static int pci_bridge_exitfn(PCIDevice *pci_dev) +/* default qdev clean up function for PCI-to-PCI bridge */ +int pci_bridge_exitfn(PCIDevice *pci_dev) { PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); QLIST_REMOVE(&s->sec_bus, sibling); + /* qbus_free() is called automatically by qdev_free() */ return 0; } -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction, - uint16_t vid, uint16_t did, - pci_map_irq_fn map_irq, const char *name) -{ - PCIDevice *dev; - PCIBridge *s; - PCIBus *sec_bus; - - dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge"); - qdev_prop_set_uint32(&dev->qdev, "vendorid", vid); - qdev_prop_set_uint32(&dev->qdev, "deviceid", did); - qdev_init_nofail(&dev->qdev); - - s = DO_UPCAST(PCIBridge, dev, dev); - sec_bus = &s->sec_bus; - qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, name); - sec_bus->parent_dev = dev; - sec_bus->map_irq = map_irq; - - QLIST_INIT(&sec_bus->child); - QLIST_INSERT_HEAD(&bus->child, sec_bus, sibling); - return &s->sec_bus; -} - -static PCIDeviceInfo bridge_info = { - .qdev.name = "pci-bridge", - .qdev.size = sizeof(PCIBridge), - .init = pci_bridge_initfn, - .exit = pci_bridge_exitfn, - .config_write = pci_bridge_write_config, - .is_bridge = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0), - DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0), - DEFINE_PROP_END_OF_LIST(), - } -}; - -static void pci_register_devices(void) +/* + * before qdev initialization(qdev_init()), this function sets bus_name and + * map_irq callback which are necessry for pci_bridge_initfn() to + * initialize bus. + */ +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, + pci_map_irq_fn map_irq) { - pci_qdev_register(&bridge_info); + br->map_irq = map_irq; + br->bus_name = bus_name; } - -device_init(pci_register_devices) diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h index ddb2c82e25..63ada199a5 100644 --- a/hw/pci_bridge.h +++ b/hw/pci_bridge.h @@ -29,13 +29,27 @@ #include "pci.h" PCIDevice *pci_bridge_get_device(PCIBus *bus); +PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); -pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type); -pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type); +pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type); +pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type); -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction, - uint16_t vid, uint16_t did, - pci_map_irq_fn map_irq, const char *name); +void pci_bridge_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +void pci_bridge_reset_reg(PCIDevice *dev); +void pci_bridge_reset(DeviceState *qdev); + +int pci_bridge_initfn(PCIDevice *pci_dev); +int pci_bridge_exitfn(PCIDevice *pci_dev); + + +/* + * before qdev initialization(qdev_init()), this function sets bus_name and + * map_irq callback which are necessry for pci_bridge_initfn() to + * initialize bus. + */ +void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, + pci_map_irq_fn map_irq); #endif /* QEMU_PCI_BRIDGE_H */ /* diff --git a/hw/pci_internals.h b/hw/pci_internals.h index fa844abee1..e3c93a3cc5 100644 --- a/hw/pci_internals.h +++ b/hw/pci_internals.h @@ -5,6 +5,11 @@ * This header files is private to pci.c and pci_bridge.c * So following structures are opaque to others and shouldn't be * accessed. + * + * For pci-to-pci bridge needs to include this header file to embed + * PCIBridge in its structure or to get sizeof(PCIBridge), + * However, they shouldn't access those following members directly. + * Use accessor function in pci.h, pci_bridge.h */ extern struct BusInfo pci_bus_info; @@ -30,11 +35,13 @@ struct PCIBus { int *irq_count; }; -typedef struct { +struct PCIBridge { PCIDevice dev; + + /* private member */ PCIBus sec_bus; - uint32_t vid; - uint32_t did; -} PCIBridge; + pci_map_irq_fn map_irq; + const char *bus_name; +}; #endif /* QEMU_PCI_INTERNALS_H */ diff --git a/qemu-common.h b/qemu-common.h index 3fb2f0b375..d735235f84 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -219,6 +219,7 @@ typedef struct PCIHostState PCIHostState; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; +typedef struct PCIBridge PCIBridge; typedef struct SerialState SerialState; typedef struct IRQState *qemu_irq; typedef struct PCMCIACardState PCMCIACardState; -- cgit v1.2.3-55-g7522