This device works as a generic pnv-phb that redirects the control flow to one of the implemented PHB versions (PHB3 and PHB4 at this moment).
The control redirection happens in the instance_init() and realize() callbacks, where we check which powernv machine we're running and execute the PnvPHB3 callbacks if running powernv8 or PnvPHB4 if running powernv9/10. This will allow us to keep the existing PHB3 and PHB4 code as is, just changing their device type to PnvPHB3/PnvPHB4 to PnvPHB when we're ready. For now we're putting logic to handle the PHB3 version. We'll add PHB4 later on. Signed-off-by: Daniel Henrique Barboza <danielhb...@gmail.com> --- hw/pci-host/meson.build | 3 +- hw/pci-host/pnv_phb.c | 116 +++++++++++++++++++++++++++++++++ hw/pci-host/pnv_phb3.c | 4 +- include/hw/pci-host/pnv_phb3.h | 3 + 4 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 hw/pci-host/pnv_phb.c diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 4c4f39c15c..b4107b7a2a 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -32,5 +32,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..3dd08f768f --- /dev/null +++ b/hw/pci-host/pnv_phb.c @@ -0,0 +1,116 @@ +/* + * QEMU PowerPC PowerNV Unified 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/pcie_host.h" +#include "hw/pci/pcie_port.h" +#include "hw/ppc/pnv.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qom/object.h" +#include "sysemu/sysemu.h" + + +static char *pnv_phb_get_chip_typename(void) +{ + Object *qdev_machine = qdev_get_machine(); + PnvMachineState *pnv = PNV_MACHINE(qdev_machine); + MachineState *machine = MACHINE(pnv); + g_autofree char *chip_typename = NULL; + int i; + + if (!machine->cpu_type) { + return NULL; + } + + i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); + chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), + i, machine->cpu_type); + + return g_steal_pointer(&chip_typename); +} + +static void pnv_phb_instance_init(Object *obj) +{ + g_autofree char *chip_typename = pnv_phb_get_chip_typename(); + + /* + * When doing command line instrospection we won't have + * a valid machine->cpu_type value. + */ + if (!chip_typename) { + return; + } + + if (!strcmp(chip_typename, TYPE_PNV_CHIP_POWER8) || + !strcmp(chip_typename, TYPE_PNV_CHIP_POWER8E) || + !strcmp(chip_typename, TYPE_PNV_CHIP_POWER8NVL)) { + pnv_phb3_instance_init(obj); + } +} + +static void pnv_phb_realize(DeviceState *dev, Error **errp) +{ + g_autofree char *chip_typename = pnv_phb_get_chip_typename(); + + g_assert(chip_typename != NULL); + + if (!strcmp(chip_typename, TYPE_PNV_CHIP_POWER8) || + !strcmp(chip_typename, TYPE_PNV_CHIP_POWER8E) || + !strcmp(chip_typename, TYPE_PNV_CHIP_POWER8NVL)) { + /* PnvPHB3 */ + pnv_phb3_realize(dev, 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_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 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, + .instance_init = pnv_phb_instance_init, +}; + +static void pnv_phb_register_types(void) +{ + type_register_static(&pnv_phb_type_info); +} + +type_init(pnv_phb_register_types) diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 70d92edd94..8e31a69083 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -966,7 +966,7 @@ static AddressSpace *pnv_phb3_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &ds->dma_as; } -static void pnv_phb3_instance_init(Object *obj) +void pnv_phb3_instance_init(Object *obj) { PnvPHB3 *phb = PNV_PHB3(obj); @@ -986,7 +986,7 @@ static void pnv_phb3_instance_init(Object *obj) } -static void pnv_phb3_realize(DeviceState *dev, Error **errp) +void pnv_phb3_realize(DeviceState *dev, Error **errp) { PnvPHB3 *phb = PNV_PHB3(dev); PCIHostState *pci = PCI_HOST_BRIDGE(dev); diff --git a/include/hw/pci-host/pnv_phb3.h b/include/hw/pci-host/pnv_phb3.h index b6b5f91684..aba26f4f7c 100644 --- a/include/hw/pci-host/pnv_phb3.h +++ b/include/hw/pci-host/pnv_phb3.h @@ -102,4 +102,7 @@ void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size); void pnv_phb3_update_regions(PnvPHB3 *phb); void pnv_phb3_remap_irqs(PnvPHB3 *phb); +void pnv_phb3_instance_init(Object *obj); +void pnv_phb3_realize(DeviceState *dev, Error **errp); + #endif /* PCI_HOST_PNV_PHB3_H */ -- 2.32.0