Skip to content

Commit

Permalink
irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marc Zyngier committed Jan 18, 2019
1 parent 8fa4e55 commit 8208d17
Showing 1 changed file with 13 additions and 12 deletions.
25 changes: 13 additions & 12 deletions drivers/irqchip/irq-gic-v3-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -2399,13 +2399,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;
Expand Down Expand Up @@ -2501,21 +2502,21 @@ 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);
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i)));
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;
Expand Down

0 comments on commit 8208d17

Please sign in to comment.