summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2019-09-05 14:56:47 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-10-05 13:13:54 +0200
commit6e2056c4424cf006443bd26f3a208e851c0a6dc3 (patch)
treed7a22b3a1983011770b7aae43ae34aba7f2d9da8
parent74a94a7e0a01bb678db17282dfecb13d56984de5 (diff)
downloadlinux-stable-6e2056c4424cf006443bd26f3a208e851c0a6dc3.tar.gz
linux-stable-6e2056c4424cf006443bd26f3a208e851c0a6dc3.tar.bz2
linux-stable-6e2056c4424cf006443bd26f3a208e851c0a6dc3.zip
irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
[ Upstream commit c9c96e30ecaa0aafa225aa1a5392cb7db17c7a82 ] When allocating a range of LPIs for a Multi-MSI capable device, this allocation extended to the closest power of 2. But on the release path, the interrupts are released one by one. This results in not releasing the "extra" range, leaking the its_device. Trying to reprobe the device will then fail. Fix it by releasing the LPIs the same way we allocate them. Fixes: 8208d1708b88 ("irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size") Reported-by: Jiaxing Luo <luojiaxing@huawei.com> Tested-by: John Garry <john.garry@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/f5e948aa-e32f-3f74-ae30-31fee06c2a74@huawei.com Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 20e5482d91b9..fca8b9002852 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct its_node *its = its_dev->its;
int i;
+ bitmap_release_region(its_dev->event_map.lpi_map,
+ its_get_event_id(irq_domain_get_irq_data(domain, virq)),
+ get_count_order(nr_irqs));
+
for (i = 0; i < nr_irqs; i++) {
struct irq_data *data = irq_domain_get_irq_data(domain,
virq + i);
- u32 event = its_get_event_id(data);
-
- /* Mark interrupt index as unused */
- clear_bit(event, its_dev->event_map.lpi_map);
-
/* Nuke the entry in the domain */
irq_domain_reset_irq_data(data);
}