Skip to content

Commit f770950

Browse files
Tobias Schumacherhcahca
authored andcommitted
s390/pci: Migrate s390 IRQ logic to IRQ domain API
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> Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
1 parent 455a652 commit f770950

5 files changed

Lines changed: 247 additions & 115 deletions

File tree

arch/s390/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ config S390
255255
select HOTPLUG_SMT
256256
select IOMMU_HELPER if PCI
257257
select IOMMU_SUPPORT if PCI
258+
select IRQ_MSI_LIB if PCI
258259
select KASAN_VMALLOC if KASAN
259260
select LOCK_MM_AND_FIND_VMA
260261
select MMU_GATHER_MERGE_VMAS

arch/s390/include/asm/pci.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/pci.h>
66
#include <linux/mutex.h>
77
#include <linux/iommu.h>
8+
#include <linux/irqdomain.h>
89
#include <linux/pci_hotplug.h>
910
#include <asm/pci_clp.h>
1011
#include <asm/pci_debug.h>
@@ -109,6 +110,7 @@ struct zpci_bus {
109110
struct list_head resources;
110111
struct list_head bus_next;
111112
struct resource bus_resource;
113+
struct irq_domain *msi_parent_domain;
112114
int topo; /* TID if topo_is_tid, PCHID otherwise */
113115
int domain_nr;
114116
u8 multifunction : 1;
@@ -310,6 +312,9 @@ int zpci_dma_exit_device(struct zpci_dev *zdev);
310312
/* IRQ */
311313
int __init zpci_irq_init(void);
312314
void __init zpci_irq_exit(void);
315+
int zpci_set_irq(struct zpci_dev *zdev);
316+
int zpci_create_parent_msi_domain(struct zpci_bus *zbus);
317+
void zpci_remove_parent_msi_domain(struct zpci_bus *zbus);
313318

314319
/* FMB */
315320
int zpci_fmb_enable_device(struct zpci_dev *);

arch/s390/pci/pci.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,12 @@ int zpci_reenable_device(struct zpci_dev *zdev)
708708
if (rc)
709709
return rc;
710710

711+
if (zdev->msi_nr_irqs > 0) {
712+
rc = zpci_set_irq(zdev);
713+
if (rc)
714+
return rc;
715+
}
716+
711717
rc = zpci_iommu_register_ioat(zdev, &status);
712718
if (rc)
713719
zpci_disable_device(zdev);

arch/s390/pci/pci_bus.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/err.h>
1515
#include <linux/delay.h>
1616
#include <linux/seq_file.h>
17+
#include <linux/irqdomain.h>
1718
#include <linux/jump_label.h>
1819
#include <linux/pci.h>
1920
#include <linux/printk.h>
@@ -198,19 +199,27 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s
198199
zbus->multifunction = zpci_bus_is_multifunction_root(fr);
199200
zbus->max_bus_speed = fr->max_bus_speed;
200201

202+
if (zpci_create_parent_msi_domain(zbus))
203+
goto out_free_domain;
204+
201205
/*
202206
* Note that the zbus->resources are taken over and zbus->resources
203207
* is empty after a successful call
204208
*/
205209
bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources);
206-
if (!bus) {
207-
zpci_free_domain(zbus->domain_nr);
208-
return -EFAULT;
209-
}
210+
if (!bus)
211+
goto out_remove_msi_domain;
210212

211213
zbus->bus = bus;
214+
dev_set_msi_domain(&zbus->bus->dev, zbus->msi_parent_domain);
212215

213216
return 0;
217+
218+
out_remove_msi_domain:
219+
zpci_remove_parent_msi_domain(zbus);
220+
out_free_domain:
221+
zpci_free_domain(zbus->domain_nr);
222+
return -ENOMEM;
214223
}
215224

216225
static void zpci_bus_release(struct kref *kref)
@@ -231,6 +240,7 @@ static void zpci_bus_release(struct kref *kref)
231240
mutex_lock(&zbus_list_lock);
232241
list_del(&zbus->bus_next);
233242
mutex_unlock(&zbus_list_lock);
243+
zpci_remove_parent_msi_domain(zbus);
234244
kfree(zbus);
235245
}
236246

0 commit comments

Comments
 (0)