[PATCH 04/16] irqchip/crossbar: fix allocation and init cleanup
From: Haofeng Li
Date: Tue Jul 14 2026 - 09:33:08 EST
From: Haofeng Li <lihaofeng@xxxxxxxxxx>
crossbar_domain_alloc() returns in the middle of a multi-IRQ
allocation without freeing IRQs and crossbar slots allocated by
earlier iterations.
If irq_domain_create_hierarchy() fails after crossbar_of_init(), the
global crossbar object and its maps and MMIO mapping are also leaked.
Roll back prior IRQs through crossbar_domain_free(), and release all
crossbar resources when domain creation fails.
Fixes: 783d31863fb8 ("irqchip: crossbar: Convert dra7 crossbar to stacked domains")
Signed-off-by: Haofeng Li <lihaofeng@xxxxxxxxxx>
---
drivers/irqchip/irq-crossbar.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c
index 033b08782119..0ac5268aa8e4 100644
--- a/drivers/irqchip/irq-crossbar.c
+++ b/drivers/irqchip/irq-crossbar.c
@@ -42,6 +42,9 @@ struct crossbar_device {
static struct crossbar_device *cb;
+static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs);
+
static void crossbar_writel(int irq_no, int cb_no)
{
writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
@@ -127,11 +130,14 @@ static int crossbar_domain_alloc(struct irq_domain *d, unsigned int virq,
for (i = 0; i < nr_irqs; i++) {
int err = allocate_gic_irq(d, virq + i, hwirq + i);
- if (err)
+ if (err) {
+ if (i)
+ crossbar_domain_free(d, virq, i);
return err;
+ }
irq_domain_set_hwirq_and_chip(d, virq + i, hwirq + i,
- &crossbar_chip, NULL);
+ &crossbar_chip, NULL);
}
return 0;
@@ -336,6 +342,18 @@ static int __init crossbar_of_init(struct device_node *node)
return ret;
}
+static void __init crossbar_free(void)
+{
+ if (!cb)
+ return;
+
+ kfree(cb->register_offsets);
+ kfree(cb->irq_map);
+ iounmap(cb->crossbar_base);
+ kfree(cb);
+ cb = NULL;
+}
+
static int __init irqcrossbar_init(struct device_node *node,
struct device_node *parent)
{
@@ -361,6 +379,7 @@ static int __init irqcrossbar_init(struct device_node *node,
of_fwnode_handle(node), &crossbar_domain_ops, NULL);
if (!domain) {
pr_err("%pOF: failed to allocated domain\n", node);
+ crossbar_free();
return -ENOMEM;
}
--
2.25.1