Message ID | 20240928085727.56883-10-phil@philjordan.eu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | macOS PV Graphics and new vmapple machine type | expand |
On 2024/09/28 17:57, Phil Dennis-Jordan wrote: > From: Alexander Graf <graf@amazon.com> > > Some boards such as vmapple don't do real legacy PCI IRQ swizzling. > Instead, they just keep allocating more board IRQ lines for each new > legacy IRQ. Let's support that mode by giving instantiators a new > "nr_irqs" property they can use to support more than 4 legacy IRQ lines. > In this mode, GPEX will export more IRQ lines, one for each device. > > Signed-off-by: Alexander Graf <graf@amazon.com> > Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu> > --- > hw/arm/sbsa-ref.c | 2 +- > hw/arm/virt.c | 2 +- > hw/i386/microvm.c | 2 +- > hw/loongarch/virt.c | 2 +- > hw/mips/loongson3_virt.c | 2 +- > hw/openrisc/virt.c | 12 ++++++------ > hw/pci-host/gpex.c | 36 +++++++++++++++++++++++++++++++----- > hw/riscv/virt.c | 12 ++++++------ > hw/xtensa/virt.c | 2 +- > include/hw/pci-host/gpex.h | 7 +++---- > 10 files changed, 52 insertions(+), 27 deletions(-) > > diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c > index e3195d54497..7e7322486c2 100644 > --- a/hw/arm/sbsa-ref.c > +++ b/hw/arm/sbsa-ref.c > @@ -673,7 +673,7 @@ static void create_pcie(SBSAMachineState *sms) > /* Map IO port space */ > sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, > qdev_get_gpio_in(sms->gic, irq + i)); > gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); > diff --git a/hw/arm/virt.c b/hw/arm/virt.c > index 8b2b991d978..bd3b17be2ea 100644 > --- a/hw/arm/virt.c > +++ b/hw/arm/virt.c > @@ -1547,7 +1547,7 @@ static void create_pcie(VirtMachineState *vms) > /* Map IO port space */ > sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, > qdev_get_gpio_in(vms->gic, irq + i)); > gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); > diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c > index 40edcee7af2..216a169c413 100644 > --- a/hw/i386/microvm.c > +++ b/hw/i386/microvm.c > @@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms) > mms->gpex.mmio64.base, mmio64_alias); > } > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, > x86ms->gsi[mms->gpex.irq + i]); > } > diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c > index 75980b6e3c7..8eb7277a8d1 100644 > --- a/hw/loongarch/virt.c > +++ b/hw/loongarch/virt.c > @@ -703,7 +703,7 @@ static void virt_devices_init(DeviceState *pch_pic, > memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, > pio_alias); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > sysbus_connect_irq(d, i, > qdev_get_gpio_in(pch_pic, 16 + i)); > gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); > diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c > index 2067b4fecb5..acafd73129d 100644 > --- a/hw/mips/loongson3_virt.c > +++ b/hw/mips/loongson3_virt.c > @@ -458,7 +458,7 @@ static inline void loongson3_virt_devices_init(MachineState *machine, > virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias); > sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i); > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); > gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i); > diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c > index f8a68a6a6b1..16a5676c4bb 100644 > --- a/hw/openrisc/virt.c > +++ b/hw/openrisc/virt.c > @@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, > { > int pin, dev; > uint32_t irq_map_stride = 0; > - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; > + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {}; > uint32_t *irq_map = full_irq_map; > > /* > @@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, > * possible slot) seeing the interrupt-map-mask will allow the table > * to wrap to any number of devices. > */ > - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { > + for (dev = 0; dev < PCI_NUM_PINS; dev++) { > int devfn = dev << 3; > > - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > - int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); > + for (pin = 0; pin < PCI_NUM_PINS; pin++) { > + int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); > int i = 0; > > /* Fill PCI address cells */ > @@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, > } > > qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, > - GPEX_NUM_IRQS * GPEX_NUM_IRQS * > + PCI_NUM_PINS * PCI_NUM_PINS * > irq_map_stride * sizeof(uint32_t)); > > qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > @@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *state, > memory_region_add_subregion(get_system_memory(), pio_base, alias); > > /* Connect IRQ lines. */ > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i); > > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq); > diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c > index e9cf455bf52..4aca0a95771 100644 > --- a/hw/pci-host/gpex.c > +++ b/hw/pci-host/gpex.c > @@ -32,6 +32,7 @@ > #include "qemu/osdep.h" > #include "qapi/error.h" > #include "hw/irq.h" > +#include "hw/pci/pci_bus.h" > #include "hw/pci-host/gpex.h" > #include "hw/qdev-properties.h" > #include "migration/vmstate.h" > @@ -50,7 +51,7 @@ static void gpex_set_irq(void *opaque, int irq_num, int level) > > int gpex_set_irq_num(GPEXHost *s, int index, int gsi) > { > - if (index >= GPEX_NUM_IRQS) { > + if (index >= s->nr_irqs) { > return -EINVAL; > } > > @@ -74,14 +75,29 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) > return route; > } > > +static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) > +{ > + PCIBus *bus = pci_device_root_bus(pci_dev); > + > + return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq; > +} > + > static void gpex_host_realize(DeviceState *dev, Error **errp) > { > PCIHostState *pci = PCI_HOST_BRIDGE(dev); > GPEXHost *s = GPEX_HOST(dev); > SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); > + pci_map_irq_fn map_irq_fn = pci_swizzle_map_irq_fn; > int i; > > + s->irq = g_malloc0(s->nr_irqs * sizeof(*s->irq)); > + s->irq_num = g_malloc0(s->nr_irqs * sizeof(*s->irq_num)); Use g_malloc0_n(). I also prefer to have one array of struct instead of allocating two arrays to save the number of allocations. > + > + if (s->nr_irqs != PCI_NUM_PINS) { I see little utlity with this conditional. There is no behavioral difference in these functions when s->nr_irqs == PCI_NUM_PINS. The nr_irqs property will not make sense if there is. > + map_irq_fn = gpex_swizzle_map_irq_fn; > + } > + > pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); > sysbus_init_mmio(sbd, &pex->mmio); > > @@ -128,19 +144,27 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) > sysbus_init_mmio(sbd, &s->io_ioport); > } > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < s->nr_irqs; i++) { > sysbus_init_irq(sbd, &s->irq[i]); > s->irq_num[i] = -1; > } > > - pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, > - pci_swizzle_map_irq_fn, s, &s->io_mmio, > - &s->io_ioport, 0, 4, TYPE_PCIE_BUS); > + pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, map_irq_fn, > + s, &s->io_mmio, &s->io_ioport, 0, > + s->nr_irqs, TYPE_PCIE_BUS); > > pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq); > qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal); > } > > +static void gpex_host_unrealize(DeviceState *dev) > +{ > + GPEXHost *s = GPEX_HOST(dev); > + > + g_free(s->irq); > + g_free(s->irq_num); > +} > + > static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, > PCIBus *rootbus) > { > @@ -166,6 +190,7 @@ static Property gpex_host_properties[] = { > gpex_cfg.mmio64.base, 0), > DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost, > gpex_cfg.mmio64.size, 0), > + DEFINE_PROP_UINT32("nr-irqs", GPEXHost, nr_irqs, PCI_NUM_PINS), UINT32 is too big for the number of IRQs. I find code in many places use int for IRQ, which will break for a too big value. Any IRQ value before swizzling fits in UINT8 so let's use it. > DEFINE_PROP_END_OF_LIST(), > }; > > @@ -176,6 +201,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data) > > hc->root_bus_path = gpex_host_root_bus_path; > dc->realize = gpex_host_realize; > + dc->unrealize = gpex_host_unrealize; > set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); > dc->fw_name = "pci"; > device_class_set_props(dc, gpex_host_properties); > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > index cef41c150aa..6c3ed4b3d9c 100644 > --- a/hw/riscv/virt.c > +++ b/hw/riscv/virt.c > @@ -167,7 +167,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, > { > int pin, dev; > uint32_t irq_map_stride = 0; > - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * > + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * > FDT_MAX_INT_MAP_WIDTH] = {}; > uint32_t *irq_map = full_irq_map; > > @@ -179,11 +179,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, > * possible slot) seeing the interrupt-map-mask will allow the table > * to wrap to any number of devices. > */ > - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { > + for (dev = 0; dev < PCI_NUM_PINS; dev++) { > int devfn = dev * 0x8; > > - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { > - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); > + for (pin = 0; pin < PCI_NUM_PINS; pin++) { > + int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); > int i = 0; > > /* Fill PCI address cells */ > @@ -209,7 +209,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, > } > > qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, > - GPEX_NUM_IRQS * GPEX_NUM_IRQS * > + PCI_NUM_PINS * PCI_NUM_PINS * > irq_map_stride * sizeof(uint32_t)); > > qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", > @@ -1157,7 +1157,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, > > sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i); > > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); > diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c > index 5310a888613..8f5c2009d29 100644 > --- a/hw/xtensa/virt.c > +++ b/hw/xtensa/virt.c > @@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState *env, int irq_base, > /* Connect IRQ lines. */ > extints = xtensa_get_extints(env); > > - for (i = 0; i < GPEX_NUM_IRQS; i++) { > + for (i = 0; i < PCI_NUM_PINS; i++) { > void *q = extints[irq_base + i]; > > sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q); > diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h > index dce883573ba..8f87a3872cb 100644 > --- a/include/hw/pci-host/gpex.h > +++ b/include/hw/pci-host/gpex.h > @@ -32,8 +32,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST) > #define TYPE_GPEX_ROOT_DEVICE "gpex-root" > OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE) > > -#define GPEX_NUM_IRQS 4 > - > struct GPEXRootState { > /*< private >*/ > PCIDevice parent_obj; > @@ -60,8 +58,9 @@ struct GPEXHost { > MemoryRegion io_mmio; > MemoryRegion io_ioport_window; > MemoryRegion io_mmio_window; > - qemu_irq irq[GPEX_NUM_IRQS]; > - int irq_num[GPEX_NUM_IRQS]; > + uint32_t nr_irqs; > + qemu_irq *irq; > + int *irq_num; > > bool allow_unmapped_accesses; >
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index e3195d54497..7e7322486c2 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -673,7 +673,7 @@ static void create_pcie(SBSAMachineState *sms) /* Map IO port space */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, qdev_get_gpio_in(sms->gic, irq + i)); gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8b2b991d978..bd3b17be2ea 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1547,7 +1547,7 @@ static void create_pcie(VirtMachineState *vms) /* Map IO port space */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, qdev_get_gpio_in(vms->gic, irq + i)); gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 40edcee7af2..216a169c413 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms) mms->gpex.mmio64.base, mmio64_alias); } - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, x86ms->gsi[mms->gpex.irq + i]); } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 75980b6e3c7..8eb7277a8d1 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -703,7 +703,7 @@ static void virt_devices_init(DeviceState *pch_pic, memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(d, i, qdev_get_gpio_in(pch_pic, 16 + i)); gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index 2067b4fecb5..acafd73129d 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -458,7 +458,7 @@ static inline void loongson3_virt_devices_init(MachineState *machine, virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i); sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i); diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index f8a68a6a6b1..16a5676c4bb 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, { int pin, dev; uint32_t irq_map_stride = 0; - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {}; uint32_t *irq_map = full_irq_map; /* @@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, * possible slot) seeing the interrupt-map-mask will allow the table * to wrap to any number of devices. */ - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + for (dev = 0; dev < PCI_NUM_PINS; dev++) { int devfn = dev << 3; - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { - int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + for (pin = 0; pin < PCI_NUM_PINS; pin++) { + int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); int i = 0; /* Fill PCI address cells */ @@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, } qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, - GPEX_NUM_IRQS * GPEX_NUM_IRQS * + PCI_NUM_PINS * PCI_NUM_PINS * irq_map_stride * sizeof(uint32_t)); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", @@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *state, memory_region_add_subregion(get_system_memory(), pio_base, alias); /* Connect IRQ lines. */ - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i); sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq); diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index e9cf455bf52..4aca0a95771 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -32,6 +32,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/irq.h" +#include "hw/pci/pci_bus.h" #include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -50,7 +51,7 @@ static void gpex_set_irq(void *opaque, int irq_num, int level) int gpex_set_irq_num(GPEXHost *s, int index, int gsi) { - if (index >= GPEX_NUM_IRQS) { + if (index >= s->nr_irqs) { return -EINVAL; } @@ -74,14 +75,29 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) return route; } +static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) +{ + PCIBus *bus = pci_device_root_bus(pci_dev); + + return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq; +} + static void gpex_host_realize(DeviceState *dev, Error **errp) { PCIHostState *pci = PCI_HOST_BRIDGE(dev); GPEXHost *s = GPEX_HOST(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); + pci_map_irq_fn map_irq_fn = pci_swizzle_map_irq_fn; int i; + s->irq = g_malloc0(s->nr_irqs * sizeof(*s->irq)); + s->irq_num = g_malloc0(s->nr_irqs * sizeof(*s->irq_num)); + + if (s->nr_irqs != PCI_NUM_PINS) { + map_irq_fn = gpex_swizzle_map_irq_fn; + } + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); sysbus_init_mmio(sbd, &pex->mmio); @@ -128,19 +144,27 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->io_ioport); } - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < s->nr_irqs; i++) { sysbus_init_irq(sbd, &s->irq[i]); s->irq_num[i] = -1; } - pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, - pci_swizzle_map_irq_fn, s, &s->io_mmio, - &s->io_ioport, 0, 4, TYPE_PCIE_BUS); + pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq, map_irq_fn, + s, &s->io_mmio, &s->io_ioport, 0, + s->nr_irqs, TYPE_PCIE_BUS); pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq); qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal); } +static void gpex_host_unrealize(DeviceState *dev) +{ + GPEXHost *s = GPEX_HOST(dev); + + g_free(s->irq); + g_free(s->irq_num); +} + static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { @@ -166,6 +190,7 @@ static Property gpex_host_properties[] = { gpex_cfg.mmio64.base, 0), DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost, gpex_cfg.mmio64.size, 0), + DEFINE_PROP_UINT32("nr-irqs", GPEXHost, nr_irqs, PCI_NUM_PINS), DEFINE_PROP_END_OF_LIST(), }; @@ -176,6 +201,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data) hc->root_bus_path = gpex_host_root_bus_path; dc->realize = gpex_host_realize; + dc->unrealize = gpex_host_unrealize; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "pci"; device_class_set_props(dc, gpex_host_properties); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index cef41c150aa..6c3ed4b3d9c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -167,7 +167,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, { int pin, dev; uint32_t irq_map_stride = 0; - uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * FDT_MAX_INT_MAP_WIDTH] = {}; uint32_t *irq_map = full_irq_map; @@ -179,11 +179,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, * possible slot) seeing the interrupt-map-mask will allow the table * to wrap to any number of devices. */ - for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + for (dev = 0; dev < PCI_NUM_PINS; dev++) { int devfn = dev * 0x8; - for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + for (pin = 0; pin < PCI_NUM_PINS; pin++) { + int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); int i = 0; /* Fill PCI address cells */ @@ -209,7 +209,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, } qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, - GPEX_NUM_IRQS * GPEX_NUM_IRQS * + PCI_NUM_PINS * PCI_NUM_PINS * irq_map_stride * sizeof(uint32_t)); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", @@ -1157,7 +1157,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i); sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index 5310a888613..8f5c2009d29 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState *env, int irq_base, /* Connect IRQ lines. */ extints = xtensa_get_extints(env); - for (i = 0; i < GPEX_NUM_IRQS; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { void *q = extints[irq_base + i]; sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q); diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h index dce883573ba..8f87a3872cb 100644 --- a/include/hw/pci-host/gpex.h +++ b/include/hw/pci-host/gpex.h @@ -32,8 +32,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(GPEXHost, GPEX_HOST) #define TYPE_GPEX_ROOT_DEVICE "gpex-root" OBJECT_DECLARE_SIMPLE_TYPE(GPEXRootState, GPEX_ROOT_DEVICE) -#define GPEX_NUM_IRQS 4 - struct GPEXRootState { /*< private >*/ PCIDevice parent_obj; @@ -60,8 +58,9 @@ struct GPEXHost { MemoryRegion io_mmio; MemoryRegion io_ioport_window; MemoryRegion io_mmio_window; - qemu_irq irq[GPEX_NUM_IRQS]; - int irq_num[GPEX_NUM_IRQS]; + uint32_t nr_irqs; + qemu_irq *irq; + int *irq_num; bool allow_unmapped_accesses;