Skip to content

Commit 2b5a440

Browse files
author
Mete Durlu
committed
s390/pci: Allow allocation of more than 1 MSI interrupt
JIRA: https://issues.redhat.com/browse/RHEL-69123 Build-Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=66090493 commit ab42fcb Author: Gerd Bayer <gbayer@linux.ibm.com> Date: Thu Jul 11 15:45:27 2024 +0200 s390/pci: Allow allocation of more than 1 MSI interrupt On a PCI adapter that provides up to 8 MSI interrupt sources the s390 implementation of PCI interrupts rejected to accommodate them, although the underlying hardware is able to support that. For MSI-X it is sufficient to allocate a single irq_desc per msi_desc, but for MSI multiple irq descriptors are attached to and controlled by a single msi descriptor. Add the appropriate loops to maintain multiple irq descriptors and tie/untie them to/from the appropriate AIBV bit, if a device driver allocates more than 1 MSI interrupt. Common PCI code passes on requests to allocate a number of interrupt vectors based on the device drivers' demand and the PCI functions' capabilities. However, the root-complex of s390 systems support just a limited number of interrupt vectors per PCI function. Produce a kernel log message to inform about any architecture-specific capping that might be done. With this change, we had a PCI adapter successfully raising interrupts to its device driver via all 8 sources. Fixes: a384c89 ("s390/PCI: Fix single MSI only check") Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com> Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Mete Durlu <mdurlu@redhat.com>
1 parent 0514572 commit 2b5a440

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

arch/s390/pci/pci_irq.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
298298

299299
int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
300300
{
301+
unsigned int hwirq, msi_vecs, irqs_per_msi, i, cpu;
301302
struct zpci_dev *zdev = to_zpci(pdev);
302-
unsigned int hwirq, msi_vecs, cpu;
303303
struct msi_desc *msi;
304304
struct msi_msg msg;
305305
unsigned long bit;
@@ -309,30 +309,46 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
309309
zdev->aisb = -1UL;
310310
zdev->msi_first_bit = -1U;
311311

312-
if (type == PCI_CAP_ID_MSI && nvec > 1)
313-
return 1;
314312
msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
313+
if (msi_vecs < nvec) {
314+
pr_info("%s requested %d irqs, allocate system limit of %d",
315+
pci_name(pdev), nvec, zdev->max_msi);
316+
}
315317

316318
rc = __alloc_airq(zdev, msi_vecs, &bit);
317319
if (rc < 0)
318320
return rc;
319321

320-
/* Request MSI interrupts */
322+
/*
323+
* Request MSI interrupts:
324+
* When using MSI, nvec_used interrupt sources and their irq
325+
* descriptors are controlled through one msi descriptor.
326+
* Thus the outer loop over msi descriptors shall run only once,
327+
* while two inner loops iterate over the interrupt vectors.
328+
* When using MSI-X, each interrupt vector/irq descriptor
329+
* is bound to exactly one msi descriptor (nvec_used is one).
330+
* So the inner loops are executed once, while the outer iterates
331+
* over the MSI-X descriptors.
332+
*/
321333
hwirq = bit;
322334
msi_for_each_desc(msi, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
323-
rc = -EIO;
324335
if (hwirq - bit >= msi_vecs)
325336
break;
326-
irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE,
327-
(irq_delivery == DIRECTED) ?
328-
msi->affinity : NULL);
337+
irqs_per_msi = min_t(unsigned int, msi_vecs, msi->nvec_used);
338+
irq = __irq_alloc_descs(-1, 0, irqs_per_msi, 0, THIS_MODULE,
339+
(irq_delivery == DIRECTED) ?
340+
msi->affinity : NULL);
329341
if (irq < 0)
330342
return -ENOMEM;
331-
rc = irq_set_msi_desc(irq, msi);
332-
if (rc)
333-
return rc;
334-
irq_set_chip_and_handler(irq, &zpci_irq_chip,
335-
handle_percpu_irq);
343+
344+
for (i = 0; i < irqs_per_msi; i++) {
345+
rc = irq_set_msi_desc_off(irq, i, msi);
346+
if (rc)
347+
return rc;
348+
irq_set_chip_and_handler(irq + i, &zpci_irq_chip,
349+
handle_percpu_irq);
350+
}
351+
336352
msg.data = hwirq - bit;
337353
if (irq_delivery == DIRECTED) {
338354
if (msi->affinity)
@@ -345,31 +361,35 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
345361
msg.address_lo |= (cpu_addr << 8);
346362

347363
for_each_possible_cpu(cpu) {
348-
airq_iv_set_data(zpci_ibv[cpu], hwirq, irq);
364+
for (i = 0; i < irqs_per_msi; i++)
365+
airq_iv_set_data(zpci_ibv[cpu],
366+
hwirq + i, irq + i);
349367
}
350368
} else {
351369
msg.address_lo = zdev->msi_addr & 0xffffffff;
352-
airq_iv_set_data(zdev->aibv, hwirq, irq);
370+
for (i = 0; i < irqs_per_msi; i++)
371+
airq_iv_set_data(zdev->aibv, hwirq + i, irq + i);
353372
}
354373
msg.address_hi = zdev->msi_addr >> 32;
355374
pci_write_msi_msg(irq, &msg);
356-
hwirq++;
375+
hwirq += irqs_per_msi;
357376
}
358377

359378
zdev->msi_first_bit = bit;
360-
zdev->msi_nr_irqs = msi_vecs;
379+
zdev->msi_nr_irqs = hwirq - bit;
361380

362381
rc = zpci_set_irq(zdev);
363382
if (rc)
364383
return rc;
365384

366-
return (msi_vecs == nvec) ? 0 : msi_vecs;
385+
return (zdev->msi_nr_irqs == nvec) ? 0 : zdev->msi_nr_irqs;
367386
}
368387

369388
void arch_teardown_msi_irqs(struct pci_dev *pdev)
370389
{
371390
struct zpci_dev *zdev = to_zpci(pdev);
372391
struct msi_desc *msi;
392+
unsigned int i;
373393
int rc;
374394

375395
/* Disable interrupts */
@@ -379,8 +399,10 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
379399

380400
/* Release MSI interrupts */
381401
msi_for_each_desc(msi, &pdev->dev, MSI_DESC_ASSOCIATED) {
382-
irq_set_msi_desc(msi->irq, NULL);
383-
irq_free_desc(msi->irq);
402+
for (i = 0; i < msi->nvec_used; i++) {
403+
irq_set_msi_desc(msi->irq + i, NULL);
404+
irq_free_desc(msi->irq + i);
405+
}
384406
msi->msg.address_lo = 0;
385407
msi->msg.address_hi = 0;
386408
msi->msg.data = 0;

0 commit comments

Comments
 (0)