On Thu, Jun 17, 2010 at 03:15:46PM +0900, Isaku Yamahata wrote: > introduce pci bridge layer. > export pci_bridge_write_config() for generic use. > support device reset and bus reset of bridge control. > convert apb bridge and dec p2p bridge to use new pci bridge layer. > save/restore is supported as a side effect. > > This might be a bit over engineering, but this is also preparation > for pci express root/upstream/downstream port. > > Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp>
Well, preparations are easier to judge with patches that use them. > --- > hw/apb_pci.c | 38 +++++++++----- > hw/dec_pci.c | 28 +++++++--- > hw/pci_bridge.c | 146 > +++++++++++++++++++++++++++++++++++++------------------ > hw/pci_bridge.h | 35 ++++++++++++- > qemu-common.h | 1 + > 5 files changed, 177 insertions(+), 71 deletions(-) > > diff --git a/hw/apb_pci.c b/hw/apb_pci.c > index c11d9b5..cb9051b 100644 > --- a/hw/apb_pci.c > +++ b/hw/apb_pci.c > @@ -31,6 +31,7 @@ > #include "pci_host.h" > #include "pci_bridge.h" > #include "rwhandler.h" > +#include "pci_bridge.h" > #include "apb_pci.h" > #include "sysemu.h" > > @@ -294,9 +295,12 @@ 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_init(PCIBridge *br) > { > - PCIDevice *dev = pci_bridge_get_device(b); > + PCIDevice *dev = &br->dev; > + > + 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: > @@ -316,6 +320,8 @@ static void apb_pci_bridge_init(PCIBus *b) > pci_set_byte(dev->config + PCI_HEADER_TYPE, > pci_get_byte(dev->config + PCI_HEADER_TYPE) | > PCI_HEADER_TYPE_MULTI_FUNCTION); > + > + return 0; > } > > PCIBus *pci_apb_init(target_phys_addr_t special_base, > @@ -326,6 +332,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, > SysBusDevice *s; > APBState *d; > unsigned int i; > + PCIBridge *br; > > /* Ultrasparc PBM main bus */ > dev = qdev_create(NULL, "pbm"); > @@ -351,17 +358,13 @@ 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), > - 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), > - PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, > - pci_apb_map_irq, > - "Advanced PCI Bus secondary bridge 2"); > - apb_pci_bridge_init(*bus3); > + br = pci_bridge_create_simple(d->bus, PCI_DEVFN(1, 0), "pbm-bridge", > + "Advanced PCI Bus secondary bridge 1"); > + *bus2 = pci_bridge_get_sec_bus(br); > + > + br = pci_bridge_create_simple(d->bus, PCI_DEVFN(1, 1), "pbm-bridge", > + "Advanced PCI Bus secondary bridge 2"); > + *bus3 = pci_bridge_get_sec_bus(br); > > return d->bus; > } > @@ -446,10 +449,19 @@ static SysBusDeviceInfo pbm_host_info = { > .qdev.reset = pci_pbm_reset, > .init = pci_pbm_init_device, > }; > + > +static PCIBridgeInfo pbm_pci_bridge_info = { > + .pci.qdev.name = "pbm-bridge", > + .pci.qdev.vmsd = &vmstate_pci_device, > + .init = apb_pci_bridge_init, > + .map_irq = pci_apb_map_irq, > +}; > + > static void pbm_register_devices(void) > { > sysbus_register_withprop(&pbm_host_info); > pci_qdev_register(&pbm_pci_host_info); > + pci_bridge_qdev_register(&pbm_pci_bridge_info); > } > > device_init(pbm_register_devices) > diff --git a/hw/dec_pci.c b/hw/dec_pci.c > index b2759dd..45b5c28 100644 > --- a/hw/dec_pci.c > +++ b/hw/dec_pci.c > @@ -49,18 +49,27 @@ 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(PCIBridge *br) > { > - DeviceState *dev; > - PCIBus *ret; > + pci_config_set_vendor_id(br->dev.config, PCI_VENDOR_ID_DEC); > + pci_config_set_device_id(br->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, > - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154, > - dec_map_irq, "DEC 21154 PCI-PCI bridge"); > +static PCIBridgeInfo dec_21154_pci_bridge_info = { > + .pci.qdev.name = "dec-21154-p2p-bridge", > + .pci.qdev.desc = "DEC 21154 PCI-PCI bridge", > + .pci.qdev.vmsd = &vmstate_pci_device, > + .init = dec_21154_initfn, > + .map_irq = dec_map_irq, > +}; > > - return ret; > +PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) > +{ > + PCIBridge *br; > + br = pci_bridge_create_simple(parent_bus, devfn, "dec-21154-p2p-bridge", > + "DEC 21154 PCI-PCI bridge"); > + return pci_bridge_get_sec_bus(br); > } > > static int pci_dec_21154_init_device(SysBusDevice *dev) > @@ -99,6 +108,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_bridge_qdev_register(&dec_21154_pci_bridge_info); > } > > device_init(dec_register_devices) Please document the APIs. For example, what is pci_bridge_create_simple and how does it differ from pci_bridge_create? > diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c > index bf746f1..43c21d4 100644 > --- a/hw/pci_bridge.c > +++ b/hw/pci_bridge.c > @@ -29,16 +29,10 @@ > > #include "pci_bridge.h" > > -typedef struct { > - PCIDevice dev; > - PCIBus *bus; > - uint32_t vid; > - uint32_t did; > -} PCIBridge; > - > -static void pci_bridge_write_config(PCIDevice *d, > - uint32_t address, uint32_t val, int len) > +void pci_bridge_write_config(PCIDevice *d, > + uint32_t address, uint32_t val, int len) > { > + uint16_t bridge_control = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > pci_default_write_config(d, address, val, len); > > if (/* io base/limit */ > @@ -49,64 +43,122 @@ static void pci_bridge_write_config(PCIDevice *d, > ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { > pci_bridge_update_mappings(d->bus); > } > + > + if (ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) { > + uint16_t new = pci_get_word(d->config + PCI_BRIDGE_CONTROL); > + if (!(bridge_control & PCI_BRIDGE_CTL_BUS_RESET) && > + (new & PCI_BRIDGE_CTL_BUS_RESET)) { > + /* 0 -> 1 */ > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, d); > + pci_bus_reset(br->bus); > + } > + } > } > > -static int pci_bridge_initfn(PCIDevice *dev) > +void pci_bridge_reset_reg(PCIDevice *dev) > { > - PCIBridge *s = DO_UPCAST(PCIBridge, dev, 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; > > - pci_config_set_vendor_id(s->dev.config, s->vid); > - pci_config_set_device_id(s->dev.config, s->did); > + 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); > +} > + > +void pci_bridge_reset(DeviceState *qdev) > +{ > + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > + > + pci_bus_reset(br->bus); > + pci_bridge_reset_reg(dev); > + pci_device_reset_default(dev); > +} > + > +static int pci_bridge_initfn(PCIDevice *dev) > +{ > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > + PCIDeviceInfo *pci_info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info); > + PCIBridgeInfo *info = DO_UPCAST(PCIBridgeInfo, pci, pci_info); > + int rc = 0; > > pci_set_word(dev->config + PCI_STATUS, > PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); > - dev->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE; > pci_set_word(dev->config + PCI_SEC_STATUS, > PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); > - return 0; > + > + br->bus = pci_register_secondary_bus(dev->bus, dev, > + info->map_irq, br->bus_name); > + if (!br->bus) { > + return -1; > + } > + if (info->init) { > + rc = info->init(br); > + } > + return rc; > } > > -static int pci_bridge_exitfn(PCIDevice *pci_dev) > +static int pci_bridge_exitfn(PCIDevice *dev) > { > - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); > - pci_unregister_secondary_bus(s->bus); > + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); > + PCIDeviceInfo *pci_info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info); > + PCIBridgeInfo *info = DO_UPCAST(PCIBridgeInfo, pci, pci_info); > + > + if (info->exit) { > + int rc = info->exit(br); > + if (rc){ > + return rc; > + } > + } > + pci_unregister_secondary_bus(br->bus); > return 0; > } > > -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, > - pci_map_irq_fn map_irq, const char *name) > +void pci_bridge_qdev_register(PCIBridgeInfo *info) > { > - PCIDevice *dev; > - PCIBridge *s; > - > - dev = pci_create(bus, devfn, "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); > - s->bus = pci_register_secondary_bus(bus, &s->dev, map_irq, name); > - return s->bus; > + if (!info->pci.qdev.size) { > + info->pci.qdev.size = sizeof(PCIBridge); > + } > + info->pci.init = pci_bridge_initfn; > + info->pci.exit = pci_bridge_exitfn; > + info->pci.header_type = PCI_HEADER_TYPE_BRIDGE; > + if (!info->pci.config_write) { > + info->pci.config_write = pci_bridge_write_config; > + } > + if (!info->pci.qdev.reset) { > + info->pci.qdev.reset = pci_bridge_reset; > + } > + pci_qdev_register(&info->pci); > } > > -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, > - .header_type = PCI_HEADER_TYPE_BRIDGE, > - .qdev.props = (Property[]) { > - DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0), > - DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0), > - DEFINE_PROP_END_OF_LIST(), > - } > -}; > +PCIBridge *pci_bridge_create(PCIBus *bus, int devfn, const char *name) > +{ > + PCIDevice *dev = pci_create(bus, devfn, name); > + return DO_UPCAST(PCIBridge, dev, dev); > +} > > -static void pci_register_devices(void) > +void pci_bridge_set_bus_name(PCIBridge *br, const char *bus_name) > { > - pci_qdev_register(&bridge_info); > + br->bus_name = bus_name; > } > > -device_init(pci_register_devices) > +PCIBridge *pci_bridge_create_simple(PCIBus *bus, int devfn, > + const char *name, const char *bus_name) > +{ > + PCIBridge *br = pci_bridge_create(bus, devfn, name); > + pci_bridge_set_bus_name(br, bus_name); > + qdev_init_nofail(&br->dev.qdev); > + return br; > +} > diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h > index 1d46abf..2747e7f 100644 > --- a/hw/pci_bridge.h > +++ b/hw/pci_bridge.h > @@ -23,8 +23,39 @@ > > #include "pci.h" > > -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, > - pci_map_irq_fn map_irq, const char *name); > +struct PCIBridge { > + PCIDevice dev; > + > + /* private member */ > + PCIBus *bus; > + const char *bus_name; > +}; > + > +static inline PCIBus *pci_bridge_get_sec_bus(PCIBridge *br) > +{ > + return br->bus; > +} > + > +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); > + > +typedef int (*pci_bridge_qdev_initfn)(PCIBridge *br); > +typedef int (*pci_bridge_qdev_exitfn)(PCIBridge *br); > +typedef struct struct PCIBridgeInfo, so we can later forward declare if we need to. > +{ > + PCIDeviceInfo pci; > + pci_bridge_qdev_initfn init; > + pci_bridge_qdev_exitfn exit; > + pci_map_irq_fn map_irq; > +} PCIBridgeInfo; > + > +void pci_bridge_qdev_register(PCIBridgeInfo *info); > +PCIBridge *pci_bridge_create(PCIBus *bus, int devfn, const char *name); > +void pci_bridge_set_bus_name(PCIBridge *br, const char *bus_name); > +PCIBridge *pci_bridge_create_simple(PCIBus *bus, int devfn, > + const char *name, const char *bus_name); > > #endif /* QEMU_PCI_BRIDGE_H */ > /* > diff --git a/qemu-common.h b/qemu-common.h > index d133f35..8257311 100644 > --- a/qemu-common.h > +++ b/qemu-common.h > @@ -221,6 +221,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; > -- > 1.6.6.1