diff options
Diffstat (limited to 'hw/pci-host/pnv_phb3.c')
-rw-r--r-- | hw/pci-host/pnv_phb3.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index c78084cce7..7fb35dc031 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -19,6 +19,7 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "qom/object.h" +#include "sysemu/sysemu.h" #define phb3_error(phb, fmt, ...) \ qemu_log_mask(LOG_GUEST_ERROR, "phb3[%d:%d]: " fmt "\n", \ @@ -981,10 +982,6 @@ static void pnv_phb3_instance_init(Object *obj) /* Power Bus Common Queue */ object_initialize_child(obj, "pbcq", &phb->pbcq, TYPE_PNV_PBCQ); - /* Root Port */ - object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB3_ROOT_PORT); - qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0)); - qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false); } static void pnv_phb3_realize(DeviceState *dev, Error **errp) @@ -994,6 +991,30 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; + /* User created devices */ + if (!phb->chip) { + Error *local_err = NULL; + BusState *s; + + phb->chip = pnv_get_chip(pnv, phb->chip_id); + if (!phb->chip) { + error_setg(errp, "invalid chip id: %d", phb->chip_id); + return; + } + + /* + * Reparent user created devices to the chip to build + * correctly the device tree. + */ + pnv_chip_parent_fixup(phb->chip, OBJECT(phb), phb->phb_id); + + s = qdev_get_parent_bus(DEVICE(phb->chip)); + if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) { + error_propagate(errp, local_err); + return; + } + } + if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) { error_setg(errp, "invalid PHB index: %d", phb->phb_id); return; @@ -1053,10 +1074,10 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); - /* Add a single Root port */ - qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); - qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id); - qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal); + if (defaults_enabled()) { + pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), + TYPE_PNV_PHB3_ROOT_PORT); + } } void pnv_phb3_update_regions(PnvPHB3 *phb) @@ -1107,7 +1128,7 @@ static void pnv_phb3_class_init(ObjectClass *klass, void *data) dc->realize = pnv_phb3_realize; device_class_set_props(dc, pnv_phb3_properties); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->user_creatable = false; + dc->user_creatable = true; } static const TypeInfo pnv_phb3_type_info = { @@ -1142,8 +1163,24 @@ static const TypeInfo pnv_phb3_root_bus_info = { static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp) { PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + PCIDevice *pci = PCI_DEVICE(dev); + PCIBus *bus = pci_get_bus(pci); + PnvPHB3 *phb = NULL; Error *local_err = NULL; + phb = (PnvPHB3 *) object_dynamic_cast(OBJECT(bus->qbus.parent), + TYPE_PNV_PHB3); + + if (!phb) { + error_setg(errp, +"pnv_phb3_root_port devices must be connected to pnv-phb3 buses"); + return; + } + + /* Set unique chassis/slot values for the root port */ + qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id); + qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id); + rpc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1161,7 +1198,7 @@ static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data) device_class_set_parent_realize(dc, pnv_phb3_root_port_realize, &rpc->parent_realize); - dc->user_creatable = false; + dc->user_creatable = true; k->vendor_id = PCI_VENDOR_ID_IBM; k->device_id = 0x03dc; |