From nobody Mon May 12 10:13:51 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
ARC-Seal: i=1; a=rsa-sha256; t=1734553523; cv=none;
	d=zohomail.com; s=zohoarc;
	b=fbFdkUOFeI1RGa7o/KAQdftVwgmBeoJ6gBz2bpwBxDsEi37zxMbD4FfmQ9s04985N6v9O6jq7k1Hezgsetjkt9OuPsXZzv5dLySSM4CBddMKyCxhoLim5piwHMV9lADdcFO2g5E1QT0PIbYgAJX+OvZcuhmd1RgvSVsSthdfbnI=
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com;
 s=zohoarc;
	t=1734553523;
 h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To;
	bh=juvABJMH4GJBz/rUFaSWHd+oW7UvujM9HsIwiIL0DZ4=;
	b=OiOOklO05dRjpWNMrEeOVgLW7w/EjnBuJhwrtTC5i5gEJIn1T5WxhesBAPNWpuFDhDTEA66D77Vwc87b6nPNyJ8z9txL5FWu527LV1Z0ROlmC9YcjxI0DSe2GD1tQ95z/RTNuM0ZiCbBI5AZKCs2NikZj0aePiCPElR2OAdMuFc=
ARC-Authentication-Results: i=1; mx.zohomail.com;
	dkim=pass;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1734553523335596.6346682099669;
 Wed, 18 Dec 2024 12:25:23 -0800 (PST)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1tO0Xj-0001Vf-5V; Wed, 18 Dec 2024 15:21:15 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tO0Xf-0001Rg-CZ
 for qemu-devel@nongnu.org; Wed, 18 Dec 2024 15:21:11 -0500
Received: from mail-wr1-x434.google.com ([2a00:1450:4864:20::434])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <phil@philjordan.eu>)
 id 1tO0Xc-0000K9-G7
 for qemu-devel@nongnu.org; Wed, 18 Dec 2024 15:21:10 -0500
Received: by mail-wr1-x434.google.com with SMTP id
 ffacd0b85a97d-385ef8b64b3so71621f8f.0
 for <qemu-devel@nongnu.org>; Wed, 18 Dec 2024 12:21:08 -0800 (PST)
Received: from localhost.localdomain (h082218084190.host.wavenet.at.
 [82.218.84.190]) by smtp.gmail.com with ESMTPSA id
 ffacd0b85a97d-388c80120c7sm14842267f8f.13.2024.12.18.12.21.05
 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
 Wed, 18 Dec 2024 12:21:06 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1734553267;
 x=1735158067;
 darn=nongnu.org;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=juvABJMH4GJBz/rUFaSWHd+oW7UvujM9HsIwiIL0DZ4=;
 b=LjqQPHhhItlqHJSgjjmetCSAP2uvGCY1MbdekzngcCxCjyw0tq33ekFxjsJjYD0Rkt
 J72Jdo/aUaHb/fxh6V8bSylUrmiEd4pcXL9JsdP2RwMliuRJzSTfOfjSvlInYGO+mVrC
 yWOqNwZ1lNlFoZ/hJHrKI09fwQM1zOBJp+brSnRLwj7OzBPUexz454JHmOcIginUdGrW
 Wh4n0y5dxinMtcwgs4azV/FiTpipsN1v+FwxKCUchqbVnDge1b69I74/ytN0S41vKeT1
 TYfff4aUtFVoUay7hec+XyIqt6HtAEhJCiojQSmgN5sp23j456M+FIre1kWM99kC8qvW
 xsdQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1734553267; x=1735158067;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=juvABJMH4GJBz/rUFaSWHd+oW7UvujM9HsIwiIL0DZ4=;
 b=ZA1qzeXx6ERVhRqvbbUG8V5a++O5l0mfdj9nihg8pHqShGN73YY14VQrDKg2jbFYxI
 Lb0/oFdVnn87tUo+0JLOKVj1mrUl6oEMYmj1HGfgG2vIbJXlsaemCjVQMrU3SlVou+RX
 57g+L2hB60ZghL8h3jb0qTIa9mCznN8j15eYZqewJ8tNNxX7UQQM0IeCwPrZoqXOdV8d
 YfRwy6Q/nrOmJDhv0Ys1e+2HCqQIp5L5XTds1oNps10No8/GfQk7OeMgtR0whtQO34Sz
 Q1nStSuHEHN0oij25j7fo3+YuJRDj6P7g/A8RS+NPRyL4LdVRn3b9RN+scYPlhYi11iM
 3qPQ==
X-Gm-Message-State: AOJu0YzV9jQpinBhccS34JnMLRvDuNXrXu418TOgGbb1ohUq1EuwMyHH
 gWHbpc9X+qyODePUjA/7JhCyQB+fqhz9v0f1Qe7S8IHZ1A7JqNx9oO+/iTngKAwx00WRCTZOYmT
 /ag==
X-Gm-Gg: ASbGncvQLJE+bsYrpUXsZgvJTfU0sDkDrEFkkqsmeN2drNLhZr7uG9t9XzrDVunIQ2w
 WMJt43mdoaEURaknn68E/H9AMLBCRJGbRZgh5wxzSfH1pQ68uCwRotKgwSZKf0d9FiDJ/a6Q6dR
 BdmLcoBJQ7oSQaEPUatNuGlRGWNlpazLV0aoFGmumyuK7Zy8xUSEPpa9PdQjK09zFNxFZOKmPEo
 3bs7XzgPUFdNlFYDTWX6zMD7PEYy/ExrdtwiqDVBFOjdkE6jHS5GUkEUdLxqZYMK7aW7GXXcE3t
 5yjlkZ2SvVJ5G4vFDZfRiSHhDFNGU+1w
X-Google-Smtp-Source: 
 AGHT+IHt3G3M9l8dcOJJ0B+Sg1nhcVBW1xssZUbiJ2mnTme4PRuEglOvcObieLfrgldkoktxlb1tXw==
X-Received: by 2002:a05:6000:1a8e:b0:385:f996:1bb9 with SMTP id
 ffacd0b85a97d-388e4d57fcdmr4036030f8f.23.1734553266753;
 Wed, 18 Dec 2024 12:21:06 -0800 (PST)
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: agraf@csgraf.de, phil@philjordan.eu, peter.maydell@linaro.org,
 pbonzini@redhat.com, rad@semihalf.com, quic_llindhol@quicinc.com,
 stefanha@redhat.com, mst@redhat.com, slp@redhat.com,
 richard.henderson@linaro.org, eduardo@habkost.net,
 marcel.apfelbaum@gmail.com, gaosong@loongson.cn, jiaxun.yang@flygoat.com,
 chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
 philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
 alistair.francis@wdc.com, bmeng.cn@gmail.com, liwei1518@gmail.com,
 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
 jcmvbkbc@gmail.com, marcandre.lureau@redhat.com, berrange@redhat.com,
 akihiko.odaki@daynix.com, qemu-arm@nongnu.org, qemu-block@nongnu.org,
 qemu-riscv@nongnu.org, balaton@eik.bme.hu, Alexander Graf <graf@amazon.com>
Subject: [PATCH v15 09/15] gpex: Allow more than 4 legacy IRQs
Date: Wed, 18 Dec 2024 21:20:30 +0100
Message-Id: <20241218202036.80064-10-phil@philjordan.eu>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20241218202036.80064-1-phil@philjordan.eu>
References: <20241218202036.80064-1-phil@philjordan.eu>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: neutral client-ip=2a00:1450:4864:20::434;
 envelope-from=phil@philjordan.eu; helo=mail-wr1-x434.google.com
X-Spam_score_int: -10
X-Spam_score: -1.1
X-Spam_bar: -
X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com)
X-ZM-MESSAGEID: 1734553524856116600
Content-Type: text/plain; charset="utf-8"

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>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daud=C3=A9 <philmd@linaro.org>
---

v4:

 * Turned pair of IRQ arrays into array of structs.
 * Simplified swizzling logic selection.

v12:

 * Fixed uses of deleted GPEX_NUM_IRQS constant that have been
   added to QEMU since this patch was originally written.

 hw/arm/sbsa-ref.c          |  2 +-
 hw/arm/virt.c              |  2 +-
 hw/i386/microvm.c          |  2 +-
 hw/loongarch/virt.c        | 12 +++++------
 hw/mips/loongson3_virt.c   |  2 +-
 hw/openrisc/virt.c         | 12 +++++------
 hw/pci-host/gpex.c         | 43 ++++++++++++++++++++++++++++++--------
 hw/riscv/virt.c            | 12 +++++------
 hw/xen/xen-pvh-common.c    |  2 +-
 hw/xtensa/virt.c           |  2 +-
 include/hw/pci-host/gpex.h |  7 +++----
 11 files changed, 61 insertions(+), 37 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);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 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 333eaf67ea3..543c47f101c 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);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 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 86637afa0f3..ce80596c239 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);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 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 9a635d1d3d3..1d71982c722 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -441,7 +441,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] =3D {};
     uint32_t *irq_map =3D full_irq_map;
     const MachineState *ms =3D MACHINE(lvms);
=20
@@ -454,11 +454,11 @@ static void fdt_add_pcie_irq_map_node(const LoongArch=
VirtMachineState *lvms,
      * to wrap to any number of devices.
      */
=20
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin  < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -482,7 +482,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchVi=
rtMachineState *lvms,
=20
=20
     qemu_fdt_setprop(ms->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(ms->fdt, nodename, "interrupt-map-mask",
                      0x1800, 0, 0, 0x7);
@@ -741,7 +741,7 @@ static void virt_devices_init(DeviceState *pch_pic,
     memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
                                 pio_alias);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 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 f3b6326cc59..884b5f23a99 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -458,7 +458,7 @@ static inline void loongson3_virt_devices_init(MachineS=
tate *machine,
                                 virt_memmap[VIRT_PCIE_PIO].base, s->pio_al=
ias);
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].bas=
e);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D 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 47d2c9bd3c7..6f053bf48e0 100644
--- a/hw/openrisc/virt.c
+++ b/hw/openrisc/virt.c
@@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 0;
-    uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] =3D {};
+    uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
     /*
@@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *node=
name, int irq_base,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev << 3;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodena=
me, int irq_base,
     }
=20
     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));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *stat=
e,
     memory_region_add_subregion(get_system_memory(), pio_base, alias);
=20
     /* Connect IRQ lines. */
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         pcie_irq =3D get_per_cpu_irq(cpus, num_cpus, irq_base + i);
=20
         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 8a955ca1305..39679c5e9f2 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"
@@ -41,20 +42,25 @@
  * GPEX host
  */
=20
+struct GPEXIrq {
+    qemu_irq irq;
+    int irq_num;
+};
+
 static void gpex_set_irq(void *opaque, int irq_num, int level)
 {
     GPEXHost *s =3D opaque;
=20
-    qemu_set_irq(s->irq[irq_num], level);
+    qemu_set_irq(s->irq[irq_num].irq, level);
 }
=20
 int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
 {
-    if (index >=3D GPEX_NUM_IRQS) {
+    if (index >=3D s->num_irqs) {
         return -EINVAL;
     }
=20
-    s->irq_num[index] =3D gsi;
+    s->irq[index].irq_num =3D gsi;
     return 0;
 }
=20
@@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaq=
ue, int pin)
 {
     PCIINTxRoute route;
     GPEXHost *s =3D opaque;
-    int gsi =3D s->irq_num[pin];
+    int gsi =3D s->irq[pin].irq_num;
=20
     route.irq =3D gsi;
     if (gsi < 0) {
@@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opa=
que, int pin)
     return route;
 }
=20
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
+{
+    PCIBus *bus =3D 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 =3D PCI_HOST_BRIDGE(dev);
@@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **e=
rrp)
     PCIExpressHost *pex =3D PCIE_HOST_BRIDGE(dev);
     int i;
=20
+    s->irq =3D g_malloc0_n(s->num_irqs, sizeof(*s->irq));
+
     pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
     sysbus_init_mmio(sbd, &pex->mmio);
=20
@@ -128,19 +143,27 @@ static void gpex_host_realize(DeviceState *dev, Error=
 **errp)
         sysbus_init_mmio(sbd, &s->io_ioport);
     }
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
-        sysbus_init_irq(sbd, &s->irq[i]);
-        s->irq_num[i] =3D -1;
+    for (i =3D 0; i < s->num_irqs; i++) {
+        sysbus_init_irq(sbd, &s->irq[i].irq);
+        s->irq[i].irq_num =3D -1;
     }
=20
     pci->bus =3D pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
-                                     pci_swizzle_map_irq_fn, s, &s->io_mmi=
o,
-                                     &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
+                                     gpex_swizzle_map_irq_fn,
+                                     s, &s->io_mmio, &s->io_ioport, 0,
+                                     s->num_irqs, TYPE_PCIE_BUS);
=20
     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);
 }
=20
+static void gpex_host_unrealize(DeviceState *dev)
+{
+    GPEXHost *s =3D GPEX_HOST(dev);
+
+    g_free(s->irq);
+}
+
 static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
                                           PCIBus *rootbus)
 {
@@ -166,6 +189,7 @@ static const Property gpex_host_properties[] =3D {
                        gpex_cfg.mmio64.base, 0),
     DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
                      gpex_cfg.mmio64.size, 0),
+    DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS),
     DEFINE_PROP_END_OF_LIST(),
 };
=20
@@ -176,6 +200,7 @@ static void gpex_host_class_init(ObjectClass *klass, vo=
id *data)
=20
     hc->root_bus_path =3D gpex_host_root_bus_path;
     dc->realize =3D gpex_host_realize;
+    dc->unrealize =3D gpex_host_unrealize;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->fw_name =3D "pci";
     device_class_set_props(dc, gpex_host_properties);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 2feb851f159..36656a7173c 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -168,7 +168,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
 {
     int pin, dev;
     uint32_t irq_map_stride =3D 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] =3D {};
     uint32_t *irq_map =3D full_irq_map;
=20
@@ -180,11 +180,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, vo=
id *fdt, char *nodename,
      * possible slot) seeing the interrupt-map-mask will allow the table
      * to wrap to any number of devices.
      */
-    for (dev =3D 0; dev < GPEX_NUM_IRQS; dev++) {
+    for (dev =3D 0; dev < PCI_NUM_PINS; dev++) {
         int devfn =3D dev * 0x8;
=20
-        for (pin =3D 0; pin < GPEX_NUM_IRQS; pin++) {
-            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_=
IRQS);
+        for (pin =3D 0; pin < PCI_NUM_PINS; pin++) {
+            int irq_nr =3D PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_P=
INS);
             int i =3D 0;
=20
             /* Fill PCI address cells */
@@ -210,7 +210,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void=
 *fdt, char *nodename,
     }
=20
     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));
=20
     qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -1180,7 +1180,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegio=
n *sys_mem,
=20
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         irq =3D qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
=20
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
index 218ac851cf7..9143b54d826 100644
--- a/hw/xen/xen-pvh-common.c
+++ b/hw/xen/xen-pvh-common.c
@@ -169,7 +169,7 @@ static inline void xenpvh_gpex_init(XenPVHMachineState =
*s,
      */
     assert(xpc->set_pci_intx_irq);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         qemu_irq irq =3D qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
=20
         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 =3D xtensa_get_extints(env);
=20
-    for (i =3D 0; i < GPEX_NUM_IRQS; i++) {
+    for (i =3D 0; i < PCI_NUM_PINS; i++) {
         void *q =3D extints[irq_base + i];
=20
         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..84471533af0 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)
=20
-#define GPEX_NUM_IRQS 4
-
 struct GPEXRootState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -49,6 +47,7 @@ struct GPEXConfig {
     PCIBus      *bus;
 };
=20
+typedef struct GPEXIrq GPEXIrq;
 struct GPEXHost {
     /*< private >*/
     PCIExpressHost parent_obj;
@@ -60,8 +59,8 @@ 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];
+    GPEXIrq *irq;
+    uint8_t num_irqs;
=20
     bool allow_unmapped_accesses;
=20
--=20
2.39.5 (Apple Git-154)