irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
commit 8208d1708b88b412ca97f50a6d951242c88cbbac upstream. 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: b48ac83d6bbc2 ("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> [ardb: rebased onto v4.9.153, should apply cleanly onto v4.4.y as well] Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
This commit is contained in:
parent
2cbf0a6c9a
commit
1b284d7846
@ -1230,13 +1230,14 @@ static void its_free_device(struct its_device *its_dev)
|
||||
kfree(its_dev);
|
||||
}
|
||||
|
||||
static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
|
||||
static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number_t *hwirq)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = find_first_zero_bit(dev->event_map.lpi_map,
|
||||
dev->event_map.nr_lpis);
|
||||
if (idx == dev->event_map.nr_lpis)
|
||||
idx = bitmap_find_free_region(dev->event_map.lpi_map,
|
||||
dev->event_map.nr_lpis,
|
||||
get_count_order(nvecs));
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
*hwirq = dev->event_map.lpi_base + idx;
|
||||
@ -1317,20 +1318,20 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
err = its_alloc_device_irq(its_dev, &hwirq);
|
||||
if (err)
|
||||
return err;
|
||||
err = its_alloc_device_irq(its_dev, nr_irqs, &hwirq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq);
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_domain_set_hwirq_and_chip(domain, virq + i,
|
||||
hwirq, &its_irq_chip, its_dev);
|
||||
hwirq + i, &its_irq_chip, its_dev);
|
||||
pr_debug("ID:%d pID:%d vID:%d\n",
|
||||
(int)(hwirq - its_dev->event_map.lpi_base),
|
||||
(int) hwirq, virq + i);
|
||||
(int)(hwirq + i - its_dev->event_map.lpi_base),
|
||||
(int)(hwirq + i), virq + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user