public inbox for linux-s390@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/2] genirq: s390/pci: Migrate MSI interrupts to irqdomain API
@ 2025-12-03 14:36 Tobias Schumacher
  2025-12-03 14:36 ` [PATCH v8 1/2] genirq: Change hwirq parameter to irq_hw_number_t Tobias Schumacher
  2025-12-03 14:36 ` [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API Tobias Schumacher
  0 siblings, 2 replies; 5+ messages in thread
From: Tobias Schumacher @ 2025-12-03 14:36 UTC (permalink / raw)
  To: Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Niklas Schnelle,
	Gerald Schaefer, Gerd Bayer, Halil Pasic, Matthew Rosato,
	Thomas Gleixner
  Cc: linux-kernel, linux-s390, Tobias Schumacher, Farhan Ali

This patch series reworks the PCIe interrupt handling on s390 by
migrating it to use a proper MSI parent domain. Introducing a dedicated
MSI domain hierarchy aligns s390 PCIe support with the generic Linux IRQ
domain model. Currently s390 is one of the last architectures still using
the legacy API.

The migration splits the existing code in the legacy functions
arch_setup_msi_irqs() and arch_teardown_msi_irqs() into different
callbacks of the newly created MSI parent domain:

- zpci_msi_prepare(): prepare the allocation of per-device MSI IRQs.
      will be called once for each device before allocating individual
      IRQs and sets up for example the adapter aisb and aibv.
- zpci_msi_teardown(): reverts the effects of zpci_msi_prepare() and is
      called after all MSI IRQs are freed.
- zpci_msi_domain_alloc(): the allocation function for interrupts
- zpci_msi_domain_free(): revert the effects of zpci_msi_domain_alloc()
- zpci_compose_msi_msg(): create the MSI message to be written into the
      corresponding PCI config space.

* Patch 1 fixes an inconsistency in the irqdomain API. Internally, hw
  irqs are represented by an unsigned long int (irq_hw_number_t) while
  the external API in some cases takes an unsigned int as parameter.
  This fix was required in V2 of the patchset. Due to conceptual changes
  in patch 2 it is not required anymore for s390, but still seems
  sensible.
* Patch 2 implements IRQ domains for s390 PCI

Since patch 1 changes common APIs, some build tests were done for x86_64
and arm64. 

Signed-off-by: Tobias Schumacher <ts@linux.ibm.com>
---
Changes in v8:
- Change parameter of zpci_decode_hwirq_msi_index to irq_hw_number_t 
- clear airq data and ptr field in zpci_msi_domain_free()
- Collect R-b from Niklas and Farhan since there are only minor changes
- Link to v7: https://lore.kernel.org/r/20251127-implement-msi-domain-v7-0-86c9a4837e8c@linux.ibm.com

Changes in v7:
- call zpci_set_irq() in zpci_reenable_device() to fix recovery after
  zpcictl --reset-fw
- add commas at end of initializers
- remove unused variables in free()
- removed R-b for patch 2 because of bug fixes
- Link to v6: https://lore.kernel.org/r/20251121-implement-msi-domain-v6-0-444f4a6479c3@linux.ibm.com

Changes in v6:
- removed obsolete function zpci_decode_hwirq_msi_index()
- removed some code duplication
- fixed some coding style issues
- corrected hwirq encoding in commit message
- Link to v5: https://lore.kernel.org/r/20251121-implement-msi-domain-v5-0-d7e717dfd3f7@linux.ibm.com

Changes in v5:
- removed two lines of superfluous code
- Link to v4: https://lore.kernel.org/r/20251120-implement-msi-domain-v4-0-a01be58e158a@linux.ibm.com

Changes in v4:
- remove flag MSI_FLAG_PCI_MSI_MASK_PARENT and mask/unmask callbacks
- use goto statements in zpci_bus_create_pci_bus()
- Link to v3: https://lore.kernel.org/r/20251118-implement-msi-domain-v3-0-6fe8feb2a93f@linux.ibm.com

Changes in v3:
- implement one MSI parent domain per PCI domain to further align the
  implementation with other architectures.
- Link to v2: https://lore.kernel.org/r/20251117-implement-msi-domain-v2-0-a110ea0721fe@linux.ibm.com

Changes in v2:
- fix directed interrupt setup and handling
- add flag MSI_FLAG_NO_AFFINITY in case of floating interrupts
- style adjustments according to review comments
- Link to v1: https://lore.kernel.org/r/20251112-implement-msi-domain-v1-0-103dd123de14@linux.ibm.com

---
Tobias Schumacher (2):
      genirq: Change hwirq parameter to irq_hw_number_t
      s390/pci: Migrate s390 IRQ logic to IRQ domain API

 arch/s390/Kconfig           |   1 +
 arch/s390/include/asm/pci.h |   5 +
 arch/s390/pci/pci.c         |   6 +
 arch/s390/pci/pci_bus.c     |  18 ++-
 arch/s390/pci/pci_irq.c     | 329 +++++++++++++++++++++++++++++---------------
 include/linux/irqdesc.h     |   6 +-
 kernel/irq/irqdesc.c        |   6 +-
 7 files changed, 250 insertions(+), 121 deletions(-)
---
base-commit: 82ef9f0fac73cca3e7d776b095b5a7de1b0b88fc
change-id: 20251104-implement-msi-domain-dc1ea014580e

Best regards,
-- 
Tobias Schumacher <ts@linux.ibm.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v8 1/2] genirq: Change hwirq parameter to irq_hw_number_t
  2025-12-03 14:36 [PATCH v8 0/2] genirq: s390/pci: Migrate MSI interrupts to irqdomain API Tobias Schumacher
@ 2025-12-03 14:36 ` Tobias Schumacher
  2025-12-03 14:36 ` [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API Tobias Schumacher
  1 sibling, 0 replies; 5+ messages in thread
From: Tobias Schumacher @ 2025-12-03 14:36 UTC (permalink / raw)
  To: Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Niklas Schnelle,
	Gerald Schaefer, Gerd Bayer, Halil Pasic, Matthew Rosato,
	Thomas Gleixner
  Cc: linux-kernel, linux-s390, Tobias Schumacher, Farhan Ali

The irqdomain implementation internally represents hardware IRQs as
irq_hw_number_t, which is defined as unsigned long int. When providing
an irq_hw_number_t to the generic_handle_domain() functions that expect
and unsigned int hwirq, this can lead to a loss of information. Change
the hwirq parameter to irq_hw_number_t to support the full range of
hwirqs.

Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Signed-off-by: Tobias Schumacher <ts@linux.ibm.com>
---
 include/linux/irqdesc.h | 6 +++---
 kernel/irq/irqdesc.c    | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index fd091c35d5721eee37a2fd3d5526559671d5048d..03b63aea73bb21ae1456910afa534d60f9cfa94d 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -183,9 +183,9 @@ int generic_handle_irq_safe(unsigned int irq);
  * and handle the result interrupt number. Return -EINVAL if
  * conversion failed.
  */
-int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
-int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq);
-int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
+int generic_handle_domain_irq(struct irq_domain *domain, irq_hw_number_t hwirq);
+int generic_handle_domain_irq_safe(struct irq_domain *domain, irq_hw_number_t hwirq);
+int generic_handle_domain_nmi(struct irq_domain *domain, irq_hw_number_t hwirq);
 #endif
 
 /* Test to see if a driver has successfully requested an irq */
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index db714d3014b5f7b62403ea04b80331ec6b1dc642..0cd3198496bc0766c81c353c3ff80ea184793d6a 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -720,7 +720,7 @@ EXPORT_SYMBOL_GPL(generic_handle_irq_safe);
  * 		This function must be called from an IRQ context with irq regs
  * 		initialized.
  */
-int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_irq(struct irq_domain *domain, irq_hw_number_t hwirq)
 {
 	return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
 }
@@ -738,7 +738,7 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
  * context). If the interrupt is marked as 'enforce IRQ-context only' then
  * the function must be invoked from hard interrupt context.
  */
-int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_irq_safe(struct irq_domain *domain, irq_hw_number_t hwirq)
 {
 	unsigned long flags;
 	int ret;
@@ -761,7 +761,7 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq_safe);
  * 		This function must be called from an NMI context with irq regs
  * 		initialized.
  **/
-int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_nmi(struct irq_domain *domain, irq_hw_number_t hwirq)
 {
 	WARN_ON_ONCE(!in_nmi());
 	return handle_irq_desc(irq_resolve_mapping(domain, hwirq));

-- 
2.51.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API
  2025-12-03 14:36 [PATCH v8 0/2] genirq: s390/pci: Migrate MSI interrupts to irqdomain API Tobias Schumacher
  2025-12-03 14:36 ` [PATCH v8 1/2] genirq: Change hwirq parameter to irq_hw_number_t Tobias Schumacher
@ 2025-12-03 14:36 ` Tobias Schumacher
  2025-12-03 16:14   ` Gerd Bayer
  1 sibling, 1 reply; 5+ messages in thread
From: Tobias Schumacher @ 2025-12-03 14:36 UTC (permalink / raw)
  To: Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Niklas Schnelle,
	Gerald Schaefer, Gerd Bayer, Halil Pasic, Matthew Rosato,
	Thomas Gleixner
  Cc: linux-kernel, linux-s390, Tobias Schumacher, Farhan Ali

s390 is one of the last architectures using the legacy API for setup and
teardown of PCI MSI IRQs. Migrate the s390 IRQ allocation and teardown
to the MSI parent domain API. For details, see:

https://lore.kernel.org/lkml/20221111120501.026511281@linutronix.de

In detail, create an MSI parent domain for each PCI domain. When a PCI
device sets up MSI or MSI-X IRQs, the library creates a per-device IRQ
domain for this device, which is used by the device for allocating and
freeing IRQs.

The per-device domain delegates this allocation and freeing to the
parent-domain. In the end, the corresponding callbacks of the parent
domain are responsible for allocating and freeing the IRQs.

The allocation is split into two parts:
- zpci_msi_prepare() is called once for each device and allocates the
  required resources. On s390, each PCI function has its own airq
  vector and a summary bit, which must be configured once per function.
  This is done in prepare().
- zpci_msi_alloc() can be called multiple times for allocating one or
  more MSI/MSI-X IRQs. This creates a mapping between the virtual IRQ
  number in the kernel and the hardware IRQ number.

Freeing is split into two counterparts:
- zpci_msi_free() reverts the effects of zpci_msi_alloc() and
- zpci_msi_teardown() reverts the effects of zpci_msi_prepare(). This is
  called once when all IRQs are freed before a device is removed.

Since the parent domain in the end allocates the IRQs, the hwirq
encoding must be unambiguous for all IRQs of all devices. This is
achieved by encoding the hwirq using the devfn and the MSI index.

Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Signed-off-by: Tobias Schumacher <ts@linux.ibm.com>
---
 arch/s390/Kconfig           |   1 +
 arch/s390/include/asm/pci.h |   5 +
 arch/s390/pci/pci.c         |   6 +
 arch/s390/pci/pci_bus.c     |  18 ++-
 arch/s390/pci/pci_irq.c     | 329 +++++++++++++++++++++++++++++---------------
 5 files changed, 244 insertions(+), 115 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 778ce20d34046cad84dd4ef57cab5a662e5796d9..fc82dd4f893d78f12837f36ab82a05f2c52e0501 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -251,6 +251,7 @@ config S390
 	select HOTPLUG_SMT
 	select IOMMU_HELPER		if PCI
 	select IOMMU_SUPPORT		if PCI
+	select IRQ_MSI_LIB		if PCI
 	select KASAN_VMALLOC if KASAN
 	select LOCK_MM_AND_FIND_VMA
 	select MMU_GATHER_MERGE_VMAS
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index a32f465ecf73a5cc3408a312d94ec888d62848cc..0aa6915346a50077f22868cef39638919979d478 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -5,6 +5,7 @@
 #include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/iommu.h>
+#include <linux/irqdomain.h>
 #include <linux/pci_hotplug.h>
 #include <asm/pci_clp.h>
 #include <asm/pci_debug.h>
@@ -109,6 +110,7 @@ struct zpci_bus {
 	struct list_head	resources;
 	struct list_head	bus_next;
 	struct resource		bus_resource;
+	struct irq_domain       *msi_parent_domain;
 	int			topo;		/* TID if topo_is_tid, PCHID otherwise */
 	int			domain_nr;
 	u8			multifunction	: 1;
@@ -310,6 +312,9 @@ int zpci_dma_exit_device(struct zpci_dev *zdev);
 /* IRQ */
 int __init zpci_irq_init(void);
 void __init zpci_irq_exit(void);
+int zpci_set_irq(struct zpci_dev *zdev);
+int zpci_create_parent_msi_domain(struct zpci_bus *zbus);
+void zpci_remove_parent_msi_domain(struct zpci_bus *zbus);
 
 /* FMB */
 int zpci_fmb_enable_device(struct zpci_dev *);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index c82c577db2bcd2143476cb8189fd89b9a4dc9836..2e47bf6a3289615307c71cae7b04ef77d964144a 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -709,6 +709,12 @@ int zpci_reenable_device(struct zpci_dev *zdev)
 	if (rc)
 		return rc;
 
+	if (zdev->msi_nr_irqs > 0) {
+		rc = zpci_set_irq(zdev);
+		if (rc)
+			return rc;
+	}
+
 	rc = zpci_iommu_register_ioat(zdev, &status);
 	if (rc)
 		zpci_disable_device(zdev);
diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c
index be8c697fea0cc755cfdb4fb0a9e3b95183bec0dc..2d7b389f36e8682c3f0a10befe87698751596584 100644
--- a/arch/s390/pci/pci_bus.c
+++ b/arch/s390/pci/pci_bus.c
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
+#include <linux/irqdomain.h>
 #include <linux/jump_label.h>
 #include <linux/pci.h>
 #include <linux/printk.h>
@@ -199,19 +200,27 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s
 	zbus->multifunction = zpci_bus_is_multifunction_root(fr);
 	zbus->max_bus_speed = fr->max_bus_speed;
 
+	if (zpci_create_parent_msi_domain(zbus))
+		goto out_free_domain;
+
 	/*
 	 * Note that the zbus->resources are taken over and zbus->resources
 	 * is empty after a successful call
 	 */
 	bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources);
-	if (!bus) {
-		zpci_free_domain(zbus->domain_nr);
-		return -EFAULT;
-	}
+	if (!bus)
+		goto out_remove_msi_domain;
 
 	zbus->bus = bus;
+	dev_set_msi_domain(&zbus->bus->dev, zbus->msi_parent_domain);
 
 	return 0;
+
+out_remove_msi_domain:
+	zpci_remove_parent_msi_domain(zbus);
+out_free_domain:
+	zpci_free_domain(zbus->domain_nr);
+	return -ENOMEM;
 }
 
 static void zpci_bus_release(struct kref *kref)
@@ -232,6 +241,7 @@ static void zpci_bus_release(struct kref *kref)
 	mutex_lock(&zbus_list_lock);
 	list_del(&zbus->bus_next);
 	mutex_unlock(&zbus_list_lock);
+	zpci_remove_parent_msi_domain(zbus);
 	kfree(zbus);
 }
 
diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c
index e73be96ce5fe6473fc193d65b8f0ff635d6a98ba..e1c5e683c2a6eef1806284adb433a3cdf4c69b9a 100644
--- a/arch/s390/pci/pci_irq.c
+++ b/arch/s390/pci/pci_irq.c
@@ -7,6 +7,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
+#include <linux/irqchip/irq-msi-lib.h>
 #include <linux/smp.h>
 
 #include <asm/isc.h>
@@ -98,7 +99,7 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev)
 }
 
 /* Register adapter interruptions */
-static int zpci_set_irq(struct zpci_dev *zdev)
+int zpci_set_irq(struct zpci_dev *zdev)
 {
 	int rc;
 
@@ -126,27 +127,53 @@ static int zpci_clear_irq(struct zpci_dev *zdev)
 static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest,
 				 bool force)
 {
-	struct msi_desc *entry = irq_data_get_msi_desc(data);
-	struct msi_msg msg = entry->msg;
-	int cpu_addr = smp_cpu_get_cpu_address(cpumask_first(dest));
+	irq_data_update_affinity(data, dest);
+	return IRQ_SET_MASK_OK;
+}
 
-	msg.address_lo &= 0xff0000ff;
-	msg.address_lo |= (cpu_addr << 8);
-	pci_write_msi_msg(data->irq, &msg);
+/*
+ * Encode the hwirq number for the parent domain. The encoding must be unique
+ * for each IRQ of each device in the parent domain, so it uses the devfn to
+ * identify the device and the msi_index to identify the IRQ within that device.
+ */
+static inline u32 zpci_encode_hwirq(u8 devfn, u16 msi_index)
+{
+	return (devfn << 16) | msi_index;
+}
 
-	return IRQ_SET_MASK_OK;
+static inline u16 zpci_decode_hwirq_msi_index(irq_hw_number_t hwirq)
+{
+	return hwirq & 0xffff;
+}
+
+static void zpci_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct msi_desc *desc = irq_data_get_msi_desc(data);
+	struct zpci_dev *zdev = to_zpci_dev(desc->dev);
+
+	if (irq_delivery == DIRECTED) {
+		int cpu = cpumask_first(irq_data_get_affinity_mask(data));
+
+		msg->address_lo = zdev->msi_addr & 0xff0000ff;
+		msg->address_lo |= (smp_cpu_get_cpu_address(cpu) << 8);
+	} else {
+		msg->address_lo = zdev->msi_addr & 0xffffffff;
+	}
+	msg->address_hi = zdev->msi_addr >> 32;
+	msg->data = zpci_decode_hwirq_msi_index(data->hwirq);
 }
 
 static struct irq_chip zpci_irq_chip = {
 	.name = "PCI-MSI",
-	.irq_unmask = pci_msi_unmask_irq,
-	.irq_mask = pci_msi_mask_irq,
+	.irq_compose_msi_msg = zpci_compose_msi_msg,
 };
 
 static void zpci_handle_cpu_local_irq(bool rescan)
 {
 	struct airq_iv *dibv = zpci_ibv[smp_processor_id()];
 	union zpci_sic_iib iib = {{0}};
+	struct irq_domain *msi_domain;
+	irq_hw_number_t hwirq;
 	unsigned long bit;
 	int irqs_on = 0;
 
@@ -164,7 +191,9 @@ static void zpci_handle_cpu_local_irq(bool rescan)
 			continue;
 		}
 		inc_irq_stat(IRQIO_MSI);
-		generic_handle_irq(airq_iv_get_data(dibv, bit));
+		hwirq = airq_iv_get_data(dibv, bit);
+		msi_domain = (struct irq_domain *)airq_iv_get_ptr(dibv, bit);
+		generic_handle_domain_irq(msi_domain, hwirq);
 	}
 }
 
@@ -229,6 +258,8 @@ static void zpci_floating_irq_handler(struct airq_struct *airq,
 				      struct tpi_info *tpi_info)
 {
 	union zpci_sic_iib iib = {{0}};
+	struct irq_domain *msi_domain;
+	irq_hw_number_t hwirq;
 	unsigned long si, ai;
 	struct airq_iv *aibv;
 	int irqs_on = 0;
@@ -256,7 +287,9 @@ static void zpci_floating_irq_handler(struct airq_struct *airq,
 				break;
 			inc_irq_stat(IRQIO_MSI);
 			airq_iv_lock(aibv, ai);
-			generic_handle_irq(airq_iv_get_data(aibv, ai));
+			hwirq = airq_iv_get_data(aibv, ai);
+			msi_domain = (struct irq_domain *)airq_iv_get_ptr(aibv, ai);
+			generic_handle_domain_irq(msi_domain, hwirq);
 			airq_iv_unlock(aibv, ai);
 		}
 	}
@@ -278,7 +311,9 @@ static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
 		zdev->aisb = *bit;
 
 		/* Create adapter interrupt vector */
-		zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL);
+		zdev->aibv = airq_iv_create(msi_vecs,
+					    AIRQ_IV_PTR | AIRQ_IV_DATA | AIRQ_IV_BITLOCK,
+					    NULL);
 		if (!zdev->aibv)
 			return -ENOMEM;
 
@@ -290,146 +325,217 @@ static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
 	return 0;
 }
 
-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+bool arch_restore_msi_irqs(struct pci_dev *pdev)
 {
-	unsigned int hwirq, msi_vecs, irqs_per_msi, i, cpu;
 	struct zpci_dev *zdev = to_zpci(pdev);
-	struct msi_desc *msi;
-	struct msi_msg msg;
-	unsigned long bit;
-	int cpu_addr;
-	int rc, irq;
 
+	zpci_set_irq(zdev);
+	return true;
+}
+
+static struct airq_struct zpci_airq = {
+	.handler = zpci_floating_irq_handler,
+	.isc = PCI_ISC,
+};
+
+static void zpci_msi_teardown_directed(struct zpci_dev *zdev)
+{
+	airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->max_msi);
+	zdev->msi_first_bit = -1U;
+	zdev->msi_nr_irqs = 0;
+}
+
+static void zpci_msi_teardown_floating(struct zpci_dev *zdev)
+{
+	airq_iv_release(zdev->aibv);
+	zdev->aibv = NULL;
+	airq_iv_free_bit(zpci_sbv, zdev->aisb);
 	zdev->aisb = -1UL;
 	zdev->msi_first_bit = -1U;
+	zdev->msi_nr_irqs = 0;
+}
+
+static void zpci_msi_teardown(struct irq_domain *domain, msi_alloc_info_t *arg)
+{
+	struct zpci_dev *zdev = to_zpci_dev(domain->dev);
+
+	zpci_clear_irq(zdev);
+	if (irq_delivery == DIRECTED)
+		zpci_msi_teardown_directed(zdev);
+	else
+		zpci_msi_teardown_floating(zdev);
+}
+
+static int zpci_msi_prepare(struct irq_domain *domain,
+			    struct device *dev, int nvec,
+			    msi_alloc_info_t *info)
+{
+	struct zpci_dev *zdev = to_zpci_dev(dev);
+	struct pci_dev *pdev = to_pci_dev(dev);
+	unsigned long bit;
+	int msi_vecs, rc;
 
 	msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
 	if (msi_vecs < nvec) {
-		pr_info("%s requested %d irqs, allocate system limit of %d",
+		pr_info("%s requested %d IRQs, allocate system limit of %d\n",
 			pci_name(pdev), nvec, zdev->max_msi);
 	}
 
 	rc = __alloc_airq(zdev, msi_vecs, &bit);
-	if (rc < 0)
+	if (rc) {
+		pr_err("Allocating adapter IRQs for %s failed\n", pci_name(pdev));
 		return rc;
+	}
 
-	/*
-	 * Request MSI interrupts:
-	 * When using MSI, nvec_used interrupt sources and their irq
-	 * descriptors are controlled through one msi descriptor.
-	 * Thus the outer loop over msi descriptors shall run only once,
-	 * while two inner loops iterate over the interrupt vectors.
-	 * When using MSI-X, each interrupt vector/irq descriptor
-	 * is bound to exactly one msi descriptor (nvec_used is one).
-	 * So the inner loops are executed once, while the outer iterates
-	 * over the MSI-X descriptors.
-	 */
-	hwirq = bit;
-	msi_for_each_desc(msi, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
-		if (hwirq - bit >= msi_vecs)
-			break;
-		irqs_per_msi = min_t(unsigned int, msi_vecs, msi->nvec_used);
-		irq = __irq_alloc_descs(-1, 0, irqs_per_msi, 0, THIS_MODULE,
-					(irq_delivery == DIRECTED) ?
-					msi->affinity : NULL);
-		if (irq < 0)
-			return -ENOMEM;
+	zdev->msi_first_bit = bit;
+	zdev->msi_nr_irqs = msi_vecs;
+	rc = zpci_set_irq(zdev);
+	if (rc) {
+		pr_err("Registering adapter IRQs for %s failed\n",
+		       pci_name(pdev));
+
+		if (irq_delivery == DIRECTED)
+			zpci_msi_teardown_directed(zdev);
+		else
+			zpci_msi_teardown_floating(zdev);
+		return rc;
+	}
+	return 0;
+}
 
-		for (i = 0; i < irqs_per_msi; i++) {
-			rc = irq_set_msi_desc_off(irq, i, msi);
-			if (rc)
-				return rc;
-			irq_set_chip_and_handler(irq + i, &zpci_irq_chip,
-						 handle_percpu_irq);
-		}
+static int zpci_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs, void *args)
+{
+	struct msi_desc *desc = ((msi_alloc_info_t *)args)->desc;
+	struct zpci_dev *zdev = to_zpci_dev(desc->dev);
+	struct zpci_bus *zbus = zdev->zbus;
+	unsigned int cpu, hwirq;
+	unsigned long bit;
+	int i;
+
+	bit = zdev->msi_first_bit + desc->msi_index;
+	hwirq = zpci_encode_hwirq(zdev->devfn, desc->msi_index);
+
+	if (desc->msi_index + nr_irqs > zdev->max_msi)
+		return -EINVAL;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_info(domain, virq + i, hwirq + i,
+				    &zpci_irq_chip, zdev,
+				    handle_percpu_irq, NULL, NULL);
 
-		msg.data = hwirq - bit;
 		if (irq_delivery == DIRECTED) {
-			if (msi->affinity)
-				cpu = cpumask_first(&msi->affinity->mask);
-			else
-				cpu = 0;
-			cpu_addr = smp_cpu_get_cpu_address(cpu);
+			for_each_possible_cpu(cpu) {
+				airq_iv_set_ptr(zpci_ibv[cpu], bit + i,
+						(unsigned long)zbus->msi_parent_domain);
+				airq_iv_set_data(zpci_ibv[cpu], bit + i, hwirq + i);
+			}
+		} else {
+			airq_iv_set_ptr(zdev->aibv, bit + i,
+					(unsigned long)zbus->msi_parent_domain);
+			airq_iv_set_data(zdev->aibv, bit + i, hwirq + i);
+		}
+	}
 
-			msg.address_lo = zdev->msi_addr & 0xff0000ff;
-			msg.address_lo |= (cpu_addr << 8);
+	return 0;
+}
+
+static void zpci_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+				 unsigned int nr_irqs)
+{
+	struct zpci_dev *zdev;
+	struct msi_desc *desc;
+	struct irq_data *d;
+	unsigned long bit;
+	unsigned int cpu;
+	u16 msi_index;
+	int i;
+
+	for (i = 0; i < nr_irqs; i++) {
+		d = irq_domain_get_irq_data(domain, virq + i);
+		msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
+		desc = irq_data_get_msi_desc(d);
+		zdev = to_zpci_dev(desc->dev);
+		bit = zdev->msi_first_bit + msi_index;
 
+		if (irq_delivery == DIRECTED) {
 			for_each_possible_cpu(cpu) {
-				for (i = 0; i < irqs_per_msi; i++)
-					airq_iv_set_data(zpci_ibv[cpu],
-							 hwirq + i, irq + i);
+				airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
+				airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
 			}
 		} else {
-			msg.address_lo = zdev->msi_addr & 0xffffffff;
-			for (i = 0; i < irqs_per_msi; i++)
-				airq_iv_set_data(zdev->aibv, hwirq + i, irq + i);
+			airq_iv_set_ptr(zdev->aibv, bit + i, 0);
+			airq_iv_set_data(zdev->aibv, bit + i, 0);
 		}
-		msg.address_hi = zdev->msi_addr >> 32;
-		pci_write_msi_msg(irq, &msg);
-		hwirq += irqs_per_msi;
+
+		irq_domain_reset_irq_data(d);
 	}
+}
 
-	zdev->msi_first_bit = bit;
-	zdev->msi_nr_irqs = hwirq - bit;
+static const struct irq_domain_ops zpci_msi_domain_ops = {
+	.alloc = zpci_msi_domain_alloc,
+	.free  = zpci_msi_domain_free,
+};
 
-	rc = zpci_set_irq(zdev);
-	if (rc)
-		return rc;
+static bool zpci_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+				   struct irq_domain *real_parent,
+				   struct msi_domain_info *info)
+{
+	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+		return false;
+
+	info->ops->msi_prepare = zpci_msi_prepare;
+	info->ops->msi_teardown = zpci_msi_teardown;
 
-	return (zdev->msi_nr_irqs == nvec) ? 0 : zdev->msi_nr_irqs;
+	return true;
 }
 
-void arch_teardown_msi_irqs(struct pci_dev *pdev)
+static struct msi_parent_ops zpci_msi_parent_ops = {
+	.supported_flags   = MSI_GENERIC_FLAGS_MASK	|
+			     MSI_FLAG_PCI_MSIX		|
+			     MSI_FLAG_MULTI_PCI_MSI,
+	.required_flags	   = MSI_FLAG_USE_DEF_DOM_OPS  |
+			     MSI_FLAG_USE_DEF_CHIP_OPS,
+	.init_dev_msi_info = zpci_init_dev_msi_info,
+};
+
+int zpci_create_parent_msi_domain(struct zpci_bus *zbus)
 {
-	struct zpci_dev *zdev = to_zpci(pdev);
-	struct msi_desc *msi;
-	unsigned int i;
-	int rc;
+	char fwnode_name[18];
 
-	/* Disable interrupts */
-	rc = zpci_clear_irq(zdev);
-	if (rc)
-		return;
+	snprintf(fwnode_name, sizeof(fwnode_name), "ZPCI_MSI_DOM_%04x", zbus->domain_nr);
+	struct irq_domain_info info = {
+		.fwnode		= irq_domain_alloc_named_fwnode(fwnode_name),
+		.ops		= &zpci_msi_domain_ops,
+	};
 
-	/* Release MSI interrupts */
-	msi_for_each_desc(msi, &pdev->dev, MSI_DESC_ASSOCIATED) {
-		for (i = 0; i < msi->nvec_used; i++) {
-			irq_set_msi_desc(msi->irq + i, NULL);
-			irq_free_desc(msi->irq + i);
-		}
-		msi->msg.address_lo = 0;
-		msi->msg.address_hi = 0;
-		msi->msg.data = 0;
-		msi->irq = 0;
+	if (!info.fwnode) {
+		pr_err("Failed to allocate fwnode for MSI IRQ domain\n");
+		return -ENOMEM;
 	}
 
-	if (zdev->aisb != -1UL) {
-		zpci_ibv[zdev->aisb] = NULL;
-		airq_iv_free_bit(zpci_sbv, zdev->aisb);
-		zdev->aisb = -1UL;
-	}
-	if (zdev->aibv) {
-		airq_iv_release(zdev->aibv);
-		zdev->aibv = NULL;
+	if (irq_delivery == FLOATING)
+		zpci_msi_parent_ops.required_flags |= MSI_FLAG_NO_AFFINITY;
+
+	zbus->msi_parent_domain = msi_create_parent_irq_domain(&info, &zpci_msi_parent_ops);
+	if (!zbus->msi_parent_domain) {
+		irq_domain_free_fwnode(info.fwnode);
+		pr_err("Failed to create MSI IRQ domain\n");
+		return -ENOMEM;
 	}
 
-	if ((irq_delivery == DIRECTED) && zdev->msi_first_bit != -1U)
-		airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->msi_nr_irqs);
+	return 0;
 }
 
-bool arch_restore_msi_irqs(struct pci_dev *pdev)
+void zpci_remove_parent_msi_domain(struct zpci_bus *zbus)
 {
-	struct zpci_dev *zdev = to_zpci(pdev);
+	struct fwnode_handle *fn;
 
-	zpci_set_irq(zdev);
-	return true;
+	fn = zbus->msi_parent_domain->fwnode;
+	irq_domain_remove(zbus->msi_parent_domain);
+	irq_domain_free_fwnode(fn);
 }
 
-static struct airq_struct zpci_airq = {
-	.handler = zpci_floating_irq_handler,
-	.isc = PCI_ISC,
-};
-
 static void __init cpu_enable_directed_irq(void *unused)
 {
 	union zpci_sic_iib iib = {{0}};
@@ -466,6 +572,7 @@ static int __init zpci_directed_irq_init(void)
 		 * is only done on the first vector.
 		 */
 		zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE,
+					       AIRQ_IV_PTR |
 					       AIRQ_IV_DATA |
 					       AIRQ_IV_CACHELINE |
 					       (!cpu ? AIRQ_IV_ALLOC : 0), NULL);

-- 
2.51.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API
  2025-12-03 14:36 ` [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API Tobias Schumacher
@ 2025-12-03 16:14   ` Gerd Bayer
  2025-12-04  4:54     ` Tobias Schumacher
  0 siblings, 1 reply; 5+ messages in thread
From: Gerd Bayer @ 2025-12-03 16:14 UTC (permalink / raw)
  To: Tobias Schumacher, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Niklas Schnelle, Gerald Schaefer, Halil Pasic, Matthew Rosato,
	Thomas Gleixner
  Cc: linux-kernel, linux-s390, Farhan Ali

On Wed, 2025-12-03 at 15:36 +0100, Tobias Schumacher wrote:
> s390 is one of the last architectures using the legacy API for setup and
> teardown of PCI MSI IRQs. Migrate the s390 IRQ allocation and teardown
> to the MSI parent domain API. For details, see:
> 
> https://lore.kernel.org/lkml/20221111120501.026511281@linutronix.de
> 

  [ ... snip ... ]

> +static void zpci_msi_domain_free(struct irq_domain *domain, unsigned int virq,
> +				 unsigned int nr_irqs)
> +{
> +	struct zpci_dev *zdev;
> +	struct msi_desc *desc;
> +	struct irq_data *d;
> +	unsigned long bit;
> +	unsigned int cpu;
> +	u16 msi_index;
> +	int i;
> +
> +	for (i = 0; i < nr_irqs; i++) {
> +		d = irq_domain_get_irq_data(domain, virq + i);
> +		msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
> +		desc = irq_data_get_msi_desc(d);
> +		zdev = to_zpci_dev(desc->dev);
> +		bit = zdev->msi_first_bit + msi_index;
>  
> +		if (irq_delivery == DIRECTED) {
>  			for_each_possible_cpu(cpu) {
> -				for (i = 0; i < irqs_per_msi; i++)
> -					airq_iv_set_data(zpci_ibv[cpu],
> -							 hwirq + i, irq + i);
> +				airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
> +				airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
>  			}
>  		} else {
> -			msg.address_lo = zdev->msi_addr & 0xffffffff;
> -			for (i = 0; i < irqs_per_msi; i++)
> -				airq_iv_set_data(zdev->aibv, hwirq + i, irq + i);
> +			airq_iv_set_ptr(zdev->aibv, bit + i, 0);
> +			airq_iv_set_data(zdev->aibv, bit + i, 0);
>  		}
> -		msg.address_hi = zdev->msi_addr >> 32;
> -		pci_write_msi_msg(irq, &msg);
> -		hwirq += irqs_per_msi;
> +
> +		irq_domain_reset_irq_data(d);
>  	}
> +} 

Thanks for addressing my concern about clearing the airq data!

FWIW, what you thing about abstracting out the airq clearing stuff with
something like this diff on top, so the loop body remains somewhat
short and zpci_msi_domain_free() keeps its working set of local
variables.


diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c
index 5639789dc58f..3322d8c9aff1 100644
--- a/arch/s390/pci/pci_irq.c
+++ b/arch/s390/pci/pci_irq.c
@@ -439,34 +439,37 @@ static int zpci_msi_domain_alloc(struct
irq_domain *domain, unsigned int virq,
        return 0;
 }
 
-static void zpci_msi_domain_free(struct irq_domain *domain, unsigned
int virq,
-                                unsigned int nr_irqs)
+static void zpci_msi_clear_airq(struct irq_data *d, int i)
 {
-       struct zpci_dev *zdev;
-       struct msi_desc *desc;
-       struct irq_data *d;
+       struct msi_desc *desc = irq_data_get_msi_desc(d);
+       struct zpci_dev *zdev = to_zpci_dev(desc->dev);
        unsigned long bit;
        unsigned int cpu;
        u16 msi_index;
-       int i;
 
-       for (i = 0; i < nr_irqs; i++) {
-               d = irq_domain_get_irq_data(domain, virq + i);
-               msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
-               desc = irq_data_get_msi_desc(d);
-               zdev = to_zpci_dev(desc->dev);
-               bit = zdev->msi_first_bit + msi_index;
+       msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
+       bit = zdev->msi_first_bit + msi_index;
 
-               if (irq_delivery == DIRECTED) {
-                       for_each_possible_cpu(cpu) {
-                               airq_iv_set_ptr(zpci_ibv[cpu], bit + i,
0);
-                               airq_iv_set_data(zpci_ibv[cpu], bit +
i, 0);
-                       }
-               } else {
-                       airq_iv_set_ptr(zdev->aibv, bit + i, 0);
-                       airq_iv_set_data(zdev->aibv, bit + i, 0);
+       if (irq_delivery == DIRECTED) {
+               for_each_possible_cpu(cpu) {
+                       airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
+                       airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
                }
+       } else {
+               airq_iv_set_ptr(zdev->aibv, bit + i, 0);
+               airq_iv_set_data(zdev->aibv, bit + i, 0);
+       }
+}
 
+static void zpci_msi_domain_free(struct irq_domain *domain, unsigned
int virq,
+                                unsigned int nr_irqs)
+{
+       struct irq_data *d;
+       int i;
+
+       for (i = 0; i < nr_irqs; i++) {
+               d = irq_domain_get_irq_data(domain, virq + i);
+               zpci_msi_clear_airq(d, i);
                irq_domain_reset_irq_data(d);
        }
 }

Sorry for me keeping nagging...
Gerd

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API
  2025-12-03 16:14   ` Gerd Bayer
@ 2025-12-04  4:54     ` Tobias Schumacher
  0 siblings, 0 replies; 5+ messages in thread
From: Tobias Schumacher @ 2025-12-04  4:54 UTC (permalink / raw)
  To: Gerd Bayer, Tobias Schumacher, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	Niklas Schnelle, Gerald Schaefer, Halil Pasic, Matthew Rosato,
	Thomas Gleixner
  Cc: linux-kernel, linux-s390, Farhan Ali

On Wed Dec 3, 2025 at 5:14 PM CET, Gerd Bayer wrote:
> On Wed, 2025-12-03 at 15:36 +0100, Tobias Schumacher wrote:
>> s390 is one of the last architectures using the legacy API for setup and
>> teardown of PCI MSI IRQs. Migrate the s390 IRQ allocation and teardown
>> to the MSI parent domain API. For details, see:
>> 
>> https://lore.kernel.org/lkml/20221111120501.026511281@linutronix.de
>> 
>
>   [ ... snip ... ]
>
>> +static void zpci_msi_domain_free(struct irq_domain *domain, unsigned int virq,
>> +				 unsigned int nr_irqs)
>> +{
>> +	struct zpci_dev *zdev;
>> +	struct msi_desc *desc;
>> +	struct irq_data *d;
>> +	unsigned long bit;
>> +	unsigned int cpu;
>> +	u16 msi_index;
>> +	int i;
>> +
>> +	for (i = 0; i < nr_irqs; i++) {
>> +		d = irq_domain_get_irq_data(domain, virq + i);
>> +		msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
>> +		desc = irq_data_get_msi_desc(d);
>> +		zdev = to_zpci_dev(desc->dev);
>> +		bit = zdev->msi_first_bit + msi_index;
>>  
>> +		if (irq_delivery == DIRECTED) {
>>  			for_each_possible_cpu(cpu) {
>> -				for (i = 0; i < irqs_per_msi; i++)
>> -					airq_iv_set_data(zpci_ibv[cpu],
>> -							 hwirq + i, irq + i);
>> +				airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
>> +				airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
>>  			}
>>  		} else {
>> -			msg.address_lo = zdev->msi_addr & 0xffffffff;
>> -			for (i = 0; i < irqs_per_msi; i++)
>> -				airq_iv_set_data(zdev->aibv, hwirq + i, irq + i);
>> +			airq_iv_set_ptr(zdev->aibv, bit + i, 0);
>> +			airq_iv_set_data(zdev->aibv, bit + i, 0);
>>  		}
>> -		msg.address_hi = zdev->msi_addr >> 32;
>> -		pci_write_msi_msg(irq, &msg);
>> -		hwirq += irqs_per_msi;
>> +
>> +		irq_domain_reset_irq_data(d);
>>  	}
>> +} 
>
> Thanks for addressing my concern about clearing the airq data!
>
> FWIW, what you thing about abstracting out the airq clearing stuff with
> something like this diff on top, so the loop body remains somewhat
> short and zpci_msi_domain_free() keeps its working set of local
> variables.

Sounds good, will do.

> diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c
> index 5639789dc58f..3322d8c9aff1 100644
> --- a/arch/s390/pci/pci_irq.c
> +++ b/arch/s390/pci/pci_irq.c
> @@ -439,34 +439,37 @@ static int zpci_msi_domain_alloc(struct
> irq_domain *domain, unsigned int virq,
>         return 0;
>  }
>  
> -static void zpci_msi_domain_free(struct irq_domain *domain, unsigned
> int virq,
> -                                unsigned int nr_irqs)
> +static void zpci_msi_clear_airq(struct irq_data *d, int i)
>  {
> -       struct zpci_dev *zdev;
> -       struct msi_desc *desc;
> -       struct irq_data *d;
> +       struct msi_desc *desc = irq_data_get_msi_desc(d);
> +       struct zpci_dev *zdev = to_zpci_dev(desc->dev);
>         unsigned long bit;
>         unsigned int cpu;
>         u16 msi_index;
> -       int i;
>  
> -       for (i = 0; i < nr_irqs; i++) {
> -               d = irq_domain_get_irq_data(domain, virq + i);
> -               msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
> -               desc = irq_data_get_msi_desc(d);
> -               zdev = to_zpci_dev(desc->dev);
> -               bit = zdev->msi_first_bit + msi_index;
> +       msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
> +       bit = zdev->msi_first_bit + msi_index;
>  
> -               if (irq_delivery == DIRECTED) {
> -                       for_each_possible_cpu(cpu) {
> -                               airq_iv_set_ptr(zpci_ibv[cpu], bit + i,
> 0);
> -                               airq_iv_set_data(zpci_ibv[cpu], bit +
> i, 0);
> -                       }
> -               } else {
> -                       airq_iv_set_ptr(zdev->aibv, bit + i, 0);
> -                       airq_iv_set_data(zdev->aibv, bit + i, 0);
> +       if (irq_delivery == DIRECTED) {
> +               for_each_possible_cpu(cpu) {
> +                       airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
> +                       airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
>                 }
> +       } else {
> +               airq_iv_set_ptr(zdev->aibv, bit + i, 0);
> +               airq_iv_set_data(zdev->aibv, bit + i, 0);
> +       }
> +}
>  
> +static void zpci_msi_domain_free(struct irq_domain *domain, unsigned
> int virq,
> +                                unsigned int nr_irqs)
> +{
> +       struct irq_data *d;
> +       int i;
> +
> +       for (i = 0; i < nr_irqs; i++) {
> +               d = irq_domain_get_irq_data(domain, virq + i);
> +               zpci_msi_clear_airq(d, i);
>                 irq_domain_reset_irq_data(d);
>         }
>  }
>
> Sorry for me keeping nagging...

No worries :-)

Thanks
Tobias

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-12-04  4:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-03 14:36 [PATCH v8 0/2] genirq: s390/pci: Migrate MSI interrupts to irqdomain API Tobias Schumacher
2025-12-03 14:36 ` [PATCH v8 1/2] genirq: Change hwirq parameter to irq_hw_number_t Tobias Schumacher
2025-12-03 14:36 ` [PATCH v8 2/2] s390/pci: Migrate s390 IRQ logic to IRQ domain API Tobias Schumacher
2025-12-03 16:14   ` Gerd Bayer
2025-12-04  4:54     ` Tobias Schumacher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox