[PATCH 2/2] irqchip/gic-v3-its: Release the allocated but unmapped bits in LPI maps

From: Liao Chang
Date: Thu Aug 25 2022 - 02:11:59 EST


If one hwirq allocated in ITS domain followed by some unmapped bits, the
number of unmapped bits will be recorded, so that this hwirq and
following unmapped bits could be released both.

Reported-by: John Garry <john.garry@xxxxxxxxxx>
Signed-off-by: Liao Chang <liaochang1@xxxxxxxxxx>
Link: https://lore.kernel.org/lkml/3d3d0155e66429968cb4f6b4feeae4b3@xxxxxxxxxx/
---
drivers/irqchip/irq-gic-v3-its.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 5ff09de6c48f..36a1bc88e832 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3572,11 +3572,19 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
irqd = irq_get_irq_data(virq + i);
irqd_set_single_target(irqd);
irqd_set_affinity_on_activate(irqd);
+ irqd_set_dangling(irqd, 0);
pr_debug("ID:%d pID:%d vID:%d\n",
(int)(hwirq + i - its_dev->event_map.lpi_base),
(int)(hwirq + i), virq + i);
}

+ /*
+ * In order to free dangling hwirq bits, kernel uses the irq_data
+ * of hwirq which is followed by dangling bits to record dangling
+ * number.
+ */
+ irqd_set_dangling(irqd, (1 << get_count_order(nr_irqs)) - nr_irqs);
+
return 0;
}

@@ -3617,12 +3625,16 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
struct its_node *its = its_dev->its;
+ unsigned int pos = its_get_event_id(d);
int i;

- bitmap_release_region(its_dev->event_map.lpi_map,
- its_get_event_id(irq_domain_get_irq_data(domain, virq)),
+ bitmap_release_region(its_dev->event_map.lpi_map, pos,
get_count_order(nr_irqs));

+ for (i = 0; i < d->dangling; i++)
+ bitmap_release_region(its_dev->event_map.lpi_map,
+ pos + nr_irqs + i, get_count_order(1));
+
for (i = 0; i < nr_irqs; i++) {
struct irq_data *data = irq_domain_get_irq_data(domain,
virq + i);
--
2.17.1