diff options
Diffstat (limited to 'hw/pci-host')
-rw-r--r-- | hw/pci-host/meson.build | 3 | ||||
-rw-r--r-- | hw/pci-host/pnv_phb.c | 337 | ||||
-rw-r--r-- | hw/pci-host/pnv_phb.h | 55 | ||||
-rw-r--r-- | hw/pci-host/pnv_phb3.c | 152 | ||||
-rw-r--r-- | hw/pci-host/pnv_phb4.c | 191 | ||||
-rw-r--r-- | hw/pci-host/pnv_phb4_pec.c | 11 |
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 = { |