summaryrefslogtreecommitdiffstats
path: root/hw/pci-host/pnv_phb3.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/pci-host/pnv_phb3.c')
-rw-r--r--hw/pci-host/pnv_phb3.c57
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;