Skip to content

Commit ea07c79

Browse files
committed
Merge: s390/pci: fix allocation of more than 1 MSI IRQ
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/5929 JIRA: https://issues.redhat.com/browse/RHEL-69123 Build-Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=66090493 Tested: by IBM Commits: ``` 5fd11b9 ab42fcb ``` Signed-off-by: Mete Durlu <mdurlu@redhat.com> Approved-by: Steve Best <sbest@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Rado Vrbovsky <rvrbovsk@redhat.com>
2 parents d90939d + 2b5a440 commit ea07c79

File tree

1 file changed

+71
-39
lines changed

1 file changed

+71
-39
lines changed

arch/s390/pci/pci_irq.c

Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -268,61 +268,87 @@ static void zpci_floating_irq_handler(struct airq_struct *airq,
268268
}
269269
}
270270

271-
int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
271+
static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
272+
unsigned long *bit)
272273
{
273-
struct zpci_dev *zdev = to_zpci(pdev);
274-
unsigned int hwirq, msi_vecs, cpu;
275-
unsigned long bit;
276-
struct msi_desc *msi;
277-
struct msi_msg msg;
278-
int cpu_addr;
279-
int rc, irq;
280-
281-
zdev->aisb = -1UL;
282-
zdev->msi_first_bit = -1U;
283-
if (type == PCI_CAP_ID_MSI && nvec > 1)
284-
return 1;
285-
msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
286-
287274
if (irq_delivery == DIRECTED) {
288275
/* Allocate cpu vector bits */
289-
bit = airq_iv_alloc(zpci_ibv[0], msi_vecs);
290-
if (bit == -1UL)
276+
*bit = airq_iv_alloc(zpci_ibv[0], msi_vecs);
277+
if (*bit == -1UL)
291278
return -EIO;
292279
} else {
293280
/* Allocate adapter summary indicator bit */
294-
bit = airq_iv_alloc_bit(zpci_sbv);
295-
if (bit == -1UL)
281+
*bit = airq_iv_alloc_bit(zpci_sbv);
282+
if (*bit == -1UL)
296283
return -EIO;
297-
zdev->aisb = bit;
284+
zdev->aisb = *bit;
298285

299286
/* Create adapter interrupt vector */
300287
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL);
301288
if (!zdev->aibv)
302289
return -ENOMEM;
303290

304291
/* Wire up shortcut pointer */
305-
zpci_ibv[bit] = zdev->aibv;
292+
zpci_ibv[*bit] = zdev->aibv;
306293
/* Each function has its own interrupt vector */
307-
bit = 0;
294+
*bit = 0;
308295
}
296+
return 0;
297+
}
309298

310-
/* Request MSI interrupts */
299+
int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
300+
{
301+
unsigned int hwirq, msi_vecs, irqs_per_msi, i, cpu;
302+
struct zpci_dev *zdev = to_zpci(pdev);
303+
struct msi_desc *msi;
304+
struct msi_msg msg;
305+
unsigned long bit;
306+
int cpu_addr;
307+
int rc, irq;
308+
309+
zdev->aisb = -1UL;
310+
zdev->msi_first_bit = -1U;
311+
312+
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+
}
317+
318+
rc = __alloc_airq(zdev, msi_vecs, &bit);
319+
if (rc < 0)
320+
return rc;
321+
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+
*/
311333
hwirq = bit;
312334
msi_for_each_desc(msi, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
313-
rc = -EIO;
314335
if (hwirq - bit >= msi_vecs)
315336
break;
316-
irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE,
317-
(irq_delivery == DIRECTED) ?
318-
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);
319341
if (irq < 0)
320342
return -ENOMEM;
321-
rc = irq_set_msi_desc(irq, msi);
322-
if (rc)
323-
return rc;
324-
irq_set_chip_and_handler(irq, &zpci_irq_chip,
325-
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+
326352
msg.data = hwirq - bit;
327353
if (irq_delivery == DIRECTED) {
328354
if (msi->affinity)
@@ -335,31 +361,35 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
335361
msg.address_lo |= (cpu_addr << 8);
336362

337363
for_each_possible_cpu(cpu) {
338-
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);
339367
}
340368
} else {
341369
msg.address_lo = zdev->msi_addr & 0xffffffff;
342-
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);
343372
}
344373
msg.address_hi = zdev->msi_addr >> 32;
345374
pci_write_msi_msg(irq, &msg);
346-
hwirq++;
375+
hwirq += irqs_per_msi;
347376
}
348377

349378
zdev->msi_first_bit = bit;
350-
zdev->msi_nr_irqs = msi_vecs;
379+
zdev->msi_nr_irqs = hwirq - bit;
351380

352381
rc = zpci_set_irq(zdev);
353382
if (rc)
354383
return rc;
355384

356-
return (msi_vecs == nvec) ? 0 : msi_vecs;
385+
return (zdev->msi_nr_irqs == nvec) ? 0 : zdev->msi_nr_irqs;
357386
}
358387

359388
void arch_teardown_msi_irqs(struct pci_dev *pdev)
360389
{
361390
struct zpci_dev *zdev = to_zpci(pdev);
362391
struct msi_desc *msi;
392+
unsigned int i;
363393
int rc;
364394

365395
/* Disable interrupts */
@@ -369,8 +399,10 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
369399

370400
/* Release MSI interrupts */
371401
msi_for_each_desc(msi, &pdev->dev, MSI_DESC_ASSOCIATED) {
372-
irq_set_msi_desc(msi->irq, NULL);
373-
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+
}
374406
msi->msg.address_lo = 0;
375407
msi->msg.address_hi = 0;
376408
msi->msg.data = 0;

0 commit comments

Comments
 (0)