summaryrefslogtreecommitdiffstats
path: root/hw/pci-host
diff options
context:
space:
mode:
Diffstat (limited to 'hw/pci-host')
-rw-r--r--hw/pci-host/meson.build3
-rw-r--r--hw/pci-host/pnv_phb.c337
-rw-r--r--hw/pci-host/pnv_phb.h55
-rw-r--r--hw/pci-host/pnv_phb3.c152
-rw-r--r--hw/pci-host/pnv_phb4.c191
-rw-r--r--hw/pci-host/pnv_phb4_pec.c11
6 files changed, 546 insertions, 203 deletions
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index c07596d0d1..e832babc9d 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -35,5 +35,6 @@ specific_ss.add(when: 'CONFIG_PCI_POWERNV', if_true: files(
'pnv_phb3_msi.c',
'pnv_phb3_pbcq.c',
'pnv_phb4.c',
- 'pnv_phb4_pec.c'
+ 'pnv_phb4_pec.c',
+ 'pnv_phb.c',
))
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
new file mode 100644
index 0000000000..7b11f1e8dd
--- /dev/null
+++ b/hw/pci-host/pnv_phb.c
@@ -0,0 +1,337 @@
+/*
+ * QEMU PowerPC PowerNV Proxy PHB model
+ *
+ * Copyright (c) 2022, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/visitor.h"
+#include "qapi/error.h"
+#include "hw/pci-host/pnv_phb.h"
+#include "hw/pci-host/pnv_phb3.h"
+#include "hw/pci-host/pnv_phb4.h"
+#include "hw/ppc/pnv.h"
+#include "hw/qdev-properties.h"
+#include "qom/object.h"
+#include "sysemu/sysemu.h"
+
+
+/*
+ * Set the QOM parent and parent bus of an object child. If the device
+ * state associated with the child has an id, use it as QOM id.
+ * Otherwise use object_typename[index] as QOM id.
+ *
+ * This helper does both operations at the same time because seting
+ * a new QOM child will erase the bus parent of the device. This happens
+ * because object_unparent() will call object_property_del_child(),
+ * which in turn calls the property release callback prop->release if
+ * it's defined. In our case this callback is set to
+ * object_finalize_child_property(), which was assigned during the
+ * first object_property_add_child() call. This callback will end up
+ * calling device_unparent(), and this function removes the device
+ * from its parent bus.
+ *
+ * The QOM and parent bus to be set aren“t necessarily related, so
+ * let's receive both as arguments.
+ */
+static bool pnv_parent_fixup(Object *parent, BusState *parent_bus,
+ Object *child, int index,
+ Error **errp)
+{
+ g_autofree char *default_id =
+ g_strdup_printf("%s[%d]", object_get_typename(child), index);
+ const char *dev_id = DEVICE(child)->id;
+
+ if (child->parent == parent) {
+ return true;
+ }
+
+ object_ref(child);
+ object_unparent(child);
+ object_property_add_child(parent, dev_id ? dev_id : default_id, child);
+ object_unref(child);
+
+ if (!qdev_set_parent_bus(DEVICE(child), parent_bus, errp)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * User created devices won't have the initial setup that default
+ * devices have. This setup consists of assigning a parent device
+ * (chip for PHB3, PEC for PHB4/5) that will be the QOM/bus parent
+ * of the PHB.
+ */
+static bool pnv_phb_user_device_init(PnvPHB *phb, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvChip *chip = pnv_get_chip(pnv, phb->chip_id);
+ Object *parent = NULL;
+
+ if (!chip) {
+ error_setg(errp, "invalid chip id: %d", phb->chip_id);
+ return false;
+ }
+
+ parent = pnv_chip_add_phb(chip, phb, errp);
+ if (!parent) {
+ return false;
+ }
+
+ /*
+ * Reparent user created devices to the chip to build
+ * correctly the device tree. pnv_xscom_dt() needs every
+ * PHB to be a child of the chip to build the DT correctly.
+ */
+ if (!pnv_parent_fixup(parent, qdev_get_parent_bus(DEVICE(chip)),
+ OBJECT(phb), phb->phb_id, errp)) {
+ return false;
+ }
+
+ return true;
+}
+
+static void pnv_phb_realize(DeviceState *dev, Error **errp)
+{
+ PnvPHB *phb = PNV_PHB(dev);
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+ g_autofree char *phb_typename = NULL;
+
+ if (!phb->version) {
+ error_setg(errp, "version not specified");
+ return;
+ }
+
+ switch (phb->version) {
+ case 3:
+ phb_typename = g_strdup(TYPE_PNV_PHB3);
+ break;
+ case 4:
+ phb_typename = g_strdup(TYPE_PNV_PHB4);
+ break;
+ case 5:
+ phb_typename = g_strdup(TYPE_PNV_PHB5);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ phb->backend = object_new(phb_typename);
+ object_property_add_child(OBJECT(dev), "phb-backend", phb->backend);
+
+ /* Passthrough child device properties to the proxy device */
+ object_property_set_uint(phb->backend, "index", phb->phb_id, errp);
+ object_property_set_uint(phb->backend, "chip-id", phb->chip_id, errp);
+ object_property_set_link(phb->backend, "phb-base", OBJECT(phb), errp);
+
+ /*
+ * Handle user created devices. User devices will not have a
+ * pointer to a chip (PHB3) and a PEC (PHB4/5).
+ */
+ if (!phb->chip && !phb->pec) {
+ if (!pnv_phb_user_device_init(phb, errp)) {
+ return;
+ }
+ }
+
+ if (phb->version == 3) {
+ object_property_set_link(phb->backend, "chip",
+ OBJECT(phb->chip), errp);
+ } else {
+ object_property_set_link(phb->backend, "pec", OBJECT(phb->pec), errp);
+ }
+
+ if (!qdev_realize(DEVICE(phb->backend), NULL, errp)) {
+ return;
+ }
+
+ if (phb->version == 3) {
+ pnv_phb3_bus_init(dev, PNV_PHB3(phb->backend));
+ } else {
+ pnv_phb4_bus_init(dev, PNV_PHB4(phb->backend));
+ }
+
+ if (defaults_enabled()) {
+ PCIDevice *root = pci_new(PCI_DEVFN(0, 0), TYPE_PNV_PHB_ROOT_PORT);
+
+ pci_realize_and_unref(root, pci->bus, errp);
+ }
+}
+
+static const char *pnv_phb_root_bus_path(PCIHostState *host_bridge,
+ PCIBus *rootbus)
+{
+ PnvPHB *phb = PNV_PHB(host_bridge);
+
+ snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
+ phb->chip_id, phb->phb_id);
+ return phb->bus_path;
+}
+
+static Property pnv_phb_properties[] = {
+ DEFINE_PROP_UINT32("index", PnvPHB, phb_id, 0),
+ DEFINE_PROP_UINT32("chip-id", PnvPHB, chip_id, 0),
+ DEFINE_PROP_UINT32("version", PnvPHB, version, 0),
+
+ DEFINE_PROP_LINK("chip", PnvPHB, chip, TYPE_PNV_CHIP, PnvChip *),
+
+ DEFINE_PROP_LINK("pec", PnvPHB, pec, TYPE_PNV_PHB4_PEC,
+ PnvPhb4PecState *),
+
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_phb_class_init(ObjectClass *klass, void *data)
+{
+ PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ hc->root_bus_path = pnv_phb_root_bus_path;
+ dc->realize = pnv_phb_realize;
+ device_class_set_props(dc, pnv_phb_properties);
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->user_creatable = true;
+}
+
+static void pnv_phb_root_port_reset(DeviceState *dev)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+ PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
+ PCIDevice *d = PCI_DEVICE(dev);
+ uint8_t *conf = d->config;
+
+ rpc->parent_reset(dev);
+
+ if (phb_rp->version == 3) {
+ return;
+ }
+
+ /* PHB4 and later requires these extra reset steps */
+ pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+ PCI_IO_RANGE_MASK & 0xff);
+ pci_set_word(conf + PCI_MEMORY_BASE, 0);
+ pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
+ pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
+ pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
+ pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
+ pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
+ pci_config_set_interrupt_pin(conf, 0);
+}
+
+static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+ PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
+ PCIBus *bus = PCI_BUS(qdev_get_parent_bus(dev));
+ PCIDevice *pci = PCI_DEVICE(dev);
+ uint16_t device_id = 0;
+ Error *local_err = NULL;
+ int chip_id, index;
+
+ /*
+ * 'index' will be used both as a PCIE slot value and to calculate
+ * QOM id. 'chip_id' is going to be used as PCIE chassis for the
+ * root port.
+ */
+ chip_id = object_property_get_int(OBJECT(bus), "chip-id", &error_fatal);
+ index = object_property_get_int(OBJECT(bus), "phb-id", &error_fatal);
+
+ /* Set unique chassis/slot values for the root port */
+ qdev_prop_set_uint8(dev, "chassis", chip_id);
+ qdev_prop_set_uint16(dev, "slot", index);
+
+ /*
+ * User created root ports are QOM parented to one of
+ * the peripheral containers but it's already at the right
+ * parent bus. Change the QOM parent to be the same as the
+ * parent bus it's already assigned to.
+ */
+ if (!pnv_parent_fixup(OBJECT(bus), BUS(bus), OBJECT(dev),
+ index, errp)) {
+ return;
+ }
+
+ rpc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ switch (phb_rp->version) {
+ case 3:
+ device_id = PNV_PHB3_DEVICE_ID;
+ break;
+ case 4:
+ device_id = PNV_PHB4_DEVICE_ID;
+ break;
+ case 5:
+ device_id = PNV_PHB5_DEVICE_ID;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ pci_config_set_device_id(pci->config, device_id);
+ pci_config_set_interrupt_pin(pci->config, 0);
+}
+
+static Property pnv_phb_root_port_properties[] = {
+ DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
+
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
+
+ dc->desc = "IBM PHB PCIE Root Port";
+
+ device_class_set_props(dc, pnv_phb_root_port_properties);
+ device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
+ &rpc->parent_realize);
+ device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
+ &rpc->parent_reset);
+ dc->reset = &pnv_phb_root_port_reset;
+ dc->user_creatable = true;
+
+ k->vendor_id = PCI_VENDOR_ID_IBM;
+ /* device_id will be written during realize() */
+ k->device_id = 0;
+ k->revision = 0;
+
+ rpc->exp_offset = 0x48;
+ rpc->aer_offset = 0x100;
+}
+
+static const TypeInfo pnv_phb_type_info = {
+ .name = TYPE_PNV_PHB,
+ .parent = TYPE_PCIE_HOST_BRIDGE,
+ .instance_size = sizeof(PnvPHB),
+ .class_init = pnv_phb_class_init,
+};
+
+static const TypeInfo pnv_phb_root_port_info = {
+ .name = TYPE_PNV_PHB_ROOT_PORT,
+ .parent = TYPE_PCIE_ROOT_PORT,
+ .instance_size = sizeof(PnvPHBRootPort),
+ .class_init = pnv_phb_root_port_class_init,
+};
+
+static void pnv_phb_register_types(void)
+{
+ type_register_static(&pnv_phb_type_info);
+ type_register_static(&pnv_phb_root_port_info);
+}
+
+type_init(pnv_phb_register_types)
diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
new file mode 100644
index 0000000000..58ebd6dd0f
--- /dev/null
+++ b/hw/pci-host/pnv_phb.h
@@ -0,0 +1,55 @@
+/*
+ * QEMU PowerPC PowerNV Proxy PHB model
+ *
+ * Copyright (c) 2022, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PCI_HOST_PNV_PHB_H
+#define PCI_HOST_PNV_PHB_H
+
+#include "hw/pci/pcie_host.h"
+#include "hw/pci/pcie_port.h"
+#include "qom/object.h"
+
+typedef struct PnvChip PnvChip;
+typedef struct PnvPhb4PecState PnvPhb4PecState;
+
+struct PnvPHB {
+ PCIExpressHost parent_obj;
+
+ uint32_t chip_id;
+ uint32_t phb_id;
+ uint32_t version;
+ char bus_path[8];
+
+ PnvChip *chip;
+
+ PnvPhb4PecState *pec;
+
+ /* The PHB backend (PnvPHB3, PnvPHB4 ...) being used */
+ Object *backend;
+};
+
+#define TYPE_PNV_PHB "pnv-phb"
+OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
+
+/*
+ * PHB PCIe Root port
+ */
+#define PNV_PHB3_DEVICE_ID 0x03dc
+#define PNV_PHB4_DEVICE_ID 0x04c1
+#define PNV_PHB5_DEVICE_ID 0x0652
+
+typedef struct PnvPHBRootPort {
+ PCIESlot parent_obj;
+
+ uint32_t version;
+} PnvPHBRootPort;
+
+#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
+OBJECT_DECLARE_SIMPLE_TYPE(PnvPHBRootPort, PNV_PHB_ROOT_PORT)
+
+#endif /* PCI_HOST_PNV_PHB_H */
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index d58d3c1701..af8575c007 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -11,6 +11,7 @@
#include "qapi/visitor.h"
#include "qapi/error.h"
#include "hw/pci-host/pnv_phb3_regs.h"
+#include "hw/pci-host/pnv_phb.h"
#include "hw/pci-host/pnv_phb3.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pcie_port.h"
@@ -26,7 +27,7 @@
static PCIDevice *pnv_phb3_find_cfg_dev(PnvPHB3 *phb)
{
- PCIHostState *pci = PCI_HOST_BRIDGE(phb);
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3];
uint8_t bus, devfn;
@@ -590,7 +591,7 @@ void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size)
uint64_t pnv_phb3_reg_read(void *opaque, hwaddr off, unsigned size)
{
PnvPHB3 *phb = opaque;
- PCIHostState *pci = PCI_HOST_BRIDGE(phb);
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t val;
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
@@ -986,10 +987,36 @@ static void pnv_phb3_instance_init(Object *obj)
}
+void pnv_phb3_bus_init(DeviceState *dev, PnvPHB3 *phb)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+
+ /*
+ * PHB3 doesn't support IO space. However, qemu gets very upset if
+ * we don't have an IO region to anchor IO BARs onto so we just
+ * initialize one which we never hook up to anything
+ */
+ memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000);
+ memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio",
+ PCI_MMIO_TOTAL_SIZE);
+
+ pci->bus = pci_register_root_bus(dev,
+ dev->id ? dev->id : NULL,
+ pnv_phb3_set_irq, pnv_phb3_map_irq, phb,
+ &phb->pci_mmio, &phb->pci_io,
+ 0, 4, TYPE_PNV_PHB3_ROOT_BUS);
+
+ object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id,
+ &error_abort);
+ object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id,
+ &error_abort);
+
+ pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
+}
+
static void pnv_phb3_realize(DeviceState *dev, Error **errp)
{
PnvPHB3 *phb = PNV_PHB3(dev);
- PCIHostState *pci = PCI_HOST_BRIDGE(dev);
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
int i;
@@ -1034,26 +1061,6 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
/* Controller Registers */
memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb3_reg_ops, phb,
"phb3-regs", 0x1000);
-
- /*
- * PHB3 doesn't support IO space. However, qemu gets very upset if
- * we don't have an IO region to anchor IO BARs onto so we just
- * initialize one which we never hook up to anything
- */
- memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000);
- memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio",
- PCI_MMIO_TOTAL_SIZE);
-
- pci->bus = pci_register_root_bus(dev,
- dev->id ? dev->id : NULL,
- pnv_phb3_set_irq, pnv_phb3_map_irq, phb,
- &phb->pci_mmio, &phb->pci_io,
- 0, 4, TYPE_PNV_PHB3_ROOT_BUS);
-
- pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
-
- pnv_phb_attach_root_port(pci, TYPE_PNV_PHB3_ROOT_PORT,
- phb->phb_id, phb->chip_id);
}
void pnv_phb3_update_regions(PnvPHB3 *phb)
@@ -1078,105 +1085,96 @@ void pnv_phb3_update_regions(PnvPHB3 *phb)
pnv_phb3_check_all_m64s(phb);
}
-static const char *pnv_phb3_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- PnvPHB3 *phb = PNV_PHB3(host_bridge);
-
- snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
- phb->chip_id, phb->phb_id);
- return phb->bus_path;
-}
-
static Property pnv_phb3_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB3, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB3, chip_id, 0),
DEFINE_PROP_LINK("chip", PnvPHB3, chip, TYPE_PNV_CHIP, PnvChip *),
+ DEFINE_PROP_LINK("phb-base", PnvPHB3, phb_base, TYPE_PNV_PHB, PnvPHB *),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb3_class_init(ObjectClass *klass, void *data)
{
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- hc->root_bus_path = pnv_phb3_root_bus_path;
dc->realize = pnv_phb3_realize;
device_class_set_props(dc, pnv_phb3_properties);
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->user_creatable = false;
}
static const TypeInfo pnv_phb3_type_info = {
.name = TYPE_PNV_PHB3,
- .parent = TYPE_PCIE_HOST_BRIDGE,
+ .parent = TYPE_DEVICE,
.instance_size = sizeof(PnvPHB3),
.class_init = pnv_phb3_class_init,
.instance_init = pnv_phb3_instance_init,
};
-static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data)
+static void pnv_phb3_root_bus_get_prop(Object *obj, Visitor *v,
+ const char *name,
+ void *opaque, Error **errp)
{
- BusClass *k = BUS_CLASS(klass);
+ PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj);
+ uint64_t value = 0;
- /*
- * PHB3 has only a single root complex. Enforce the limit on the
- * parent bus
- */
- k->max_dev = 1;
+ if (strcmp(name, "phb-id") == 0) {
+ value = bus->phb_id;
+ } else {
+ value = bus->chip_id;
+ }
+
+ visit_type_size(v, name, &value, errp);
}
-static const TypeInfo pnv_phb3_root_bus_info = {
- .name = TYPE_PNV_PHB3_ROOT_BUS,
- .parent = TYPE_PCIE_BUS,
- .class_init = pnv_phb3_root_bus_class_init,
-};
+static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v,
+ const char *name,
+ void *opaque, Error **errp)
-static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp)
{
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
- PCIDevice *pci = PCI_DEVICE(dev);
- Error *local_err = NULL;
+ PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj);
+ uint64_t value;
- rpc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_size(v, name, &value, errp)) {
return;
}
- pci_config_set_interrupt_pin(pci->config, 0);
+
+ if (strcmp(name, "phb-id") == 0) {
+ bus->phb_id = value;
+ } else {
+ bus->chip_id = value;
+ }
}
-static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data)
+static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
-
- dc->desc = "IBM PHB3 PCIE Root Port";
+ BusClass *k = BUS_CLASS(klass);
- device_class_set_parent_realize(dc, pnv_phb3_root_port_realize,
- &rpc->parent_realize);
- dc->user_creatable = false;
+ object_class_property_add(klass, "phb-id", "int",
+ pnv_phb3_root_bus_get_prop,
+ pnv_phb3_root_bus_set_prop,
+ NULL, NULL);
- k->vendor_id = PCI_VENDOR_ID_IBM;
- k->device_id = 0x03dc;
- k->revision = 0;
+ object_class_property_add(klass, "chip-id", "int",
+ pnv_phb3_root_bus_get_prop,
+ pnv_phb3_root_bus_set_prop,
+ NULL, NULL);
- rpc->exp_offset = 0x48;
- rpc->aer_offset = 0x100;
+ /*
+ * PHB3 has only a single root complex. Enforce the limit on the
+ * parent bus
+ */
+ k->max_dev = 1;
}
-static const TypeInfo pnv_phb3_root_port_info = {
- .name = TYPE_PNV_PHB3_ROOT_PORT,
- .parent = TYPE_PCIE_ROOT_PORT,
- .instance_size = sizeof(PnvPHB3RootPort),
- .class_init = pnv_phb3_root_port_class_init,
+static const TypeInfo pnv_phb3_root_bus_info = {
+ .name = TYPE_PNV_PHB3_ROOT_BUS,
+ .parent = TYPE_PCIE_BUS,
+ .class_init = pnv_phb3_root_bus_class_init,
};
static void pnv_phb3_register_types(void)
{
type_register_static(&pnv_phb3_root_bus_info);
- type_register_static(&pnv_phb3_root_port_info);
type_register_static(&pnv_phb3_type_info);
type_register_static(&pnv_phb3_iommu_memory_region_info);
}
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 67ddde4a6e..824e1a73fb 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -33,7 +33,7 @@
static PCIDevice *pnv_phb4_find_cfg_dev(PnvPHB4 *phb)
{
- PCIHostState *pci = PCI_HOST_BRIDGE(phb);
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3];
uint8_t bus, devfn;
@@ -129,7 +129,7 @@ static uint64_t pnv_phb4_config_read(PnvPHB4 *phb, unsigned off,
static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off,
unsigned size, uint64_t val)
{
- PCIHostState *pci = PCI_HOST_BRIDGE(phb);
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
PCIDevice *pdev;
if (size != 4) {
@@ -150,7 +150,7 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off,
static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off,
unsigned size)
{
- PCIHostState *pci = PCI_HOST_BRIDGE(phb);
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
PCIDevice *pdev;
uint64_t val;
@@ -1528,30 +1528,16 @@ static void pnv_phb4_instance_init(Object *obj)
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
}
-static void pnv_phb4_realize(DeviceState *dev, Error **errp)
+void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
{
- PnvPHB4 *phb = PNV_PHB4(dev);
- PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(phb->pec);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
- XiveSource *xsrc = &phb->xsrc;
- int nr_irqs;
char name[32];
- /* Set the "big_phb" flag */
- phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3;
-
- /* Controller Registers */
- snprintf(name, sizeof(name), "phb4-%d.%d-regs", phb->chip_id,
- phb->phb_id);
- memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb4_reg_ops, phb,
- name, 0x2000);
-
/*
* PHB4 doesn't support IO space. However, qemu gets very upset if
* we don't have an IO region to anchor IO BARs onto so we just
* initialize one which we never hook up to anything
*/
-
snprintf(name, sizeof(name), "phb4-%d.%d-pci-io", phb->chip_id,
phb->phb_id);
memory_region_init(&phb->pci_io, OBJECT(phb), name, 0x10000);
@@ -1561,16 +1547,35 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
memory_region_init(&phb->pci_mmio, OBJECT(phb), name,
PCI_MMIO_TOTAL_SIZE);
- pci->bus = pci_register_root_bus(dev, dev->id,
+ pci->bus = pci_register_root_bus(dev, dev->id ? dev->id : NULL,
pnv_phb4_set_irq, pnv_phb4_map_irq, phb,
&phb->pci_mmio, &phb->pci_io,
0, 4, TYPE_PNV_PHB4_ROOT_BUS);
+
+ object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id,
+ &error_abort);
+ object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id,
+ &error_abort);
+
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
+}
+
+static void pnv_phb4_realize(DeviceState *dev, Error **errp)
+{
+ PnvPHB4 *phb = PNV_PHB4(dev);
+ XiveSource *xsrc = &phb->xsrc;
+ int nr_irqs;
+ char name[32];
+
+ /* Set the "big_phb" flag */
+ phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3;
- /* Add a single Root port if running with defaults */
- pnv_phb_attach_root_port(pci, pecc->rp_model,
- phb->phb_id, phb->chip_id);
+ /* Controller Registers */
+ snprintf(name, sizeof(name), "phb4-%d.%d-regs", phb->chip_id,
+ phb->phb_id);
+ memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb4_reg_ops, phb,
+ name, 0x2000);
/* Setup XIVE Source */
if (phb->big_phb) {
@@ -1591,16 +1596,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pnv_phb4_xscom_realize(phb);
}
-static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge,
- PCIBus *rootbus)
-{
- PnvPHB4 *phb = PNV_PHB4(host_bridge);
-
- snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
- phb->chip_id, phb->phb_id);
- return phb->bus_path;
-}
-
/*
* Address base trigger mode (POWER10)
*
@@ -1685,19 +1680,17 @@ static Property pnv_phb4_properties[] = {
DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0),
DEFINE_PROP_LINK("pec", PnvPHB4, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
+ DEFINE_PROP_LINK("phb-base", PnvPHB4, phb_base, TYPE_PNV_PHB, PnvPHB *),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb4_class_init(ObjectClass *klass, void *data)
{
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
- hc->root_bus_path = pnv_phb4_root_bus_path;
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->user_creatable = false;
xfc->notify = pnv_phb4_xive_notify;
@@ -1705,7 +1698,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data)
static const TypeInfo pnv_phb4_type_info = {
.name = TYPE_PNV_PHB4,
- .parent = TYPE_PCIE_HOST_BRIDGE,
+ .parent = TYPE_DEVICE,
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
.class_init = pnv_phb4_class_init,
@@ -1721,111 +1714,71 @@ static const TypeInfo pnv_phb5_type_info = {
.instance_size = sizeof(PnvPHB4),
};
-static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data)
+static void pnv_phb4_root_bus_get_prop(Object *obj, Visitor *v,
+ const char *name,
+ void *opaque, Error **errp)
{
- BusClass *k = BUS_CLASS(klass);
+ PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj);
+ uint64_t value = 0;
- /*
- * PHB4 has only a single root complex. Enforce the limit on the
- * parent bus
- */
- k->max_dev = 1;
-}
-
-static const TypeInfo pnv_phb4_root_bus_info = {
- .name = TYPE_PNV_PHB4_ROOT_BUS,
- .parent = TYPE_PCIE_BUS,
- .class_init = pnv_phb4_root_bus_class_init,
-};
+ if (strcmp(name, "phb-id") == 0) {
+ value = bus->phb_id;
+ } else {
+ value = bus->chip_id;
+ }
-static void pnv_phb4_root_port_reset(DeviceState *dev)
-{
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
- PCIDevice *d = PCI_DEVICE(dev);
- uint8_t *conf = d->config;
-
- rpc->parent_reset(dev);
-
- pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
- PCI_IO_RANGE_MASK & 0xff);
- pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
- PCI_IO_RANGE_MASK & 0xff);
- pci_set_word(conf + PCI_MEMORY_BASE, 0);
- pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
- pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
- pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
- pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
- pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
- pci_config_set_interrupt_pin(conf, 0);
+ visit_type_size(v, name, &value, errp);
}
-static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp)
+static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v,
+ const char *name,
+ void *opaque, Error **errp)
+
{
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
- Error *local_err = NULL;
+ PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj);
+ uint64_t value;
- rpc->parent_realize(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!visit_type_size(v, name, &value, errp)) {
return;
}
-}
-
-static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
-
- dc->desc = "IBM PHB4 PCIE Root Port";
- dc->user_creatable = false;
-
- device_class_set_parent_realize(dc, pnv_phb4_root_port_realize,
- &rpc->parent_realize);
- device_class_set_parent_reset(dc, pnv_phb4_root_port_reset,
- &rpc->parent_reset);
- k->vendor_id = PCI_VENDOR_ID_IBM;
- k->device_id = PNV_PHB4_DEVICE_ID;
- k->revision = 0;
-
- rpc->exp_offset = 0x48;
- rpc->aer_offset = 0x100;
-
- dc->reset = &pnv_phb4_root_port_reset;
+ if (strcmp(name, "phb-id") == 0) {
+ bus->phb_id = value;
+ } else {
+ bus->chip_id = value;
+ }
}
-static const TypeInfo pnv_phb4_root_port_info = {
- .name = TYPE_PNV_PHB4_ROOT_PORT,
- .parent = TYPE_PCIE_ROOT_PORT,
- .instance_size = sizeof(PnvPHB4RootPort),
- .class_init = pnv_phb4_root_port_class_init,
-};
-
-static void pnv_phb5_root_port_class_init(ObjectClass *klass, void *data)
+static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ BusClass *k = BUS_CLASS(klass);
+
+ object_class_property_add(klass, "phb-id", "int",
+ pnv_phb4_root_bus_get_prop,
+ pnv_phb4_root_bus_set_prop,
+ NULL, NULL);
- dc->desc = "IBM PHB5 PCIE Root Port";
- dc->user_creatable = false;
+ object_class_property_add(klass, "chip-id", "int",
+ pnv_phb4_root_bus_get_prop,
+ pnv_phb4_root_bus_set_prop,
+ NULL, NULL);
- k->vendor_id = PCI_VENDOR_ID_IBM;
- k->device_id = PNV_PHB5_DEVICE_ID;
+ /*
+ * PHB4 has only a single root complex. Enforce the limit on the
+ * parent bus
+ */
+ k->max_dev = 1;
}
-static const TypeInfo pnv_phb5_root_port_info = {
- .name = TYPE_PNV_PHB5_ROOT_PORT,
- .parent = TYPE_PNV_PHB4_ROOT_PORT,
- .instance_size = sizeof(PnvPHB4RootPort),
- .class_init = pnv_phb5_root_port_class_init,
+static const TypeInfo pnv_phb4_root_bus_info = {
+ .name = TYPE_PNV_PHB4_ROOT_BUS,
+ .parent = TYPE_PCIE_BUS,
+ .class_init = pnv_phb4_root_bus_class_init,
};
static void pnv_phb4_register_types(void)
{
type_register_static(&pnv_phb4_root_bus_info);
- type_register_static(&pnv_phb5_root_port_info);
- type_register_static(&pnv_phb4_root_port_info);
type_register_static(&pnv_phb4_type_info);
type_register_static(&pnv_phb5_type_info);
type_register_static(&pnv_phb4_iommu_memory_region_info);
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index c9aaf1c28e..9871f462cd 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -115,8 +115,7 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
int stack_no,
Error **errp)
{
- PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
- PnvPHB4 *phb = PNV_PHB4(qdev_new(pecc->phb_type));
+ PnvPHB *phb = PNV_PHB(qdev_new(TYPE_PNV_PHB));
int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no);
object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb));
@@ -147,8 +146,10 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp)
pec->num_phbs = pecc->num_phbs[pec->index];
/* Create PHBs if running with defaults */
- for (i = 0; i < pec->num_phbs; i++) {
- pnv_pec_default_phb_realize(pec, i, errp);
+ if (defaults_enabled()) {
+ for (i = 0; i < pec->num_phbs; i++) {
+ pnv_pec_default_phb_realize(pec, i, errp);
+ }
}
/* Initialize the XSCOM regions for the PEC registers */
@@ -261,7 +262,6 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data)
pecc->version = PNV_PHB4_VERSION;
pecc->phb_type = TYPE_PNV_PHB4;
pecc->num_phbs = pnv_pec_num_phbs;
- pecc->rp_model = TYPE_PNV_PHB4_ROOT_PORT;
}
static const TypeInfo pnv_pec_type_info = {
@@ -314,7 +314,6 @@ static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
pecc->version = PNV_PHB5_VERSION;
pecc->phb_type = TYPE_PNV_PHB5;
pecc->num_phbs = pnv_phb5_pec_num_stacks;
- pecc->rp_model = TYPE_PNV_PHB5_ROOT_PORT;
}
static const TypeInfo pnv_phb5_pec_type_info = {