Skip to content

Commit 8208d17

Browse files
author
Marc Zyngier
committed
irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
The way we allocate events works fine in most cases, except when multiple PCI devices share an ITS-visible DevID, and that one of them is trying to use MultiMSI allocation. In that case, our allocation is not guaranteed to be zero-based anymore, and we have to make sure we allocate it on a boundary that is compatible with the PCI Multi-MSI constraints. Fix this by allocating the full region upfront instead of iterating over the number of MSIs. MSI-X are always allocated one by one, so this shouldn't change anything on that front. Fixes: b48ac83 ("irqchip: GICv3: ITS: MSI support") Cc: stable@vger.kernel.org Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 8fa4e55 commit 8208d17

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,13 +2399,14 @@ static void its_free_device(struct its_device *its_dev)
23992399
kfree(its_dev);
24002400
}
24012401

2402-
static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
2402+
static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number_t *hwirq)
24032403
{
24042404
int idx;
24052405

2406-
idx = find_first_zero_bit(dev->event_map.lpi_map,
2407-
dev->event_map.nr_lpis);
2408-
if (idx == dev->event_map.nr_lpis)
2406+
idx = bitmap_find_free_region(dev->event_map.lpi_map,
2407+
dev->event_map.nr_lpis,
2408+
get_count_order(nvecs));
2409+
if (idx < 0)
24092410
return -ENOSPC;
24102411

24112412
*hwirq = dev->event_map.lpi_base + idx;
@@ -2501,21 +2502,21 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
25012502
int err;
25022503
int i;
25032504

2504-
for (i = 0; i < nr_irqs; i++) {
2505-
err = its_alloc_device_irq(its_dev, &hwirq);
2506-
if (err)
2507-
return err;
2505+
err = its_alloc_device_irq(its_dev, nr_irqs, &hwirq);
2506+
if (err)
2507+
return err;
25082508

2509-
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq);
2509+
for (i = 0; i < nr_irqs; i++) {
2510+
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
25102511
if (err)
25112512
return err;
25122513

25132514
irq_domain_set_hwirq_and_chip(domain, virq + i,
2514-
hwirq, &its_irq_chip, its_dev);
2515+
hwirq + i, &its_irq_chip, its_dev);
25152516
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i)));
25162517
pr_debug("ID:%d pID:%d vID:%d\n",
2517-
(int)(hwirq - its_dev->event_map.lpi_base),
2518-
(int) hwirq, virq + i);
2518+
(int)(hwirq + i - its_dev->event_map.lpi_base),
2519+
(int)(hwirq + i), virq + i);
25192520
}
25202521

25212522
return 0;

0 commit comments

Comments
 (0)