[PATCH v3 4/7] gpio: gpiolib: fix allocation order in hierarchical IRQ domains

From: Oleksij Rempel

Date: Mon Mar 09 2026 - 09:50:17 EST


In gpiochip_hierarchy_irq_domain_alloc(), calling irq_domain_set_info()
before irq_domain_alloc_irqs_parent() causes a NULL pointer dereference
for slow-bus (SPI/I2C) IRQ chips.

irq_domain_set_info() locks the child descriptor, triggering .irq_bus_lock.
If the child proxies this lock to the parent, it crashes because
parent->chip is not yet allocated.

Fix this by allocating the parent IRQs first, ensuring parent->chip is
populated before the child's .irq_bus_lock is invoked.

Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
---
changes v3
- new patch
---
drivers/gpio/gpiolib.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ada572aaebd6..1ea9531934cc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1628,19 +1628,6 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
}
gpiochip_dbg(gc, "found parent hwirq %u\n", parent_hwirq);

- /*
- * We set handle_bad_irq because the .set_type() should
- * always be invoked and set the right type of handler.
- */
- irq_domain_set_info(d,
- irq,
- hwirq,
- gc->irq.chip,
- gc,
- girq->handler,
- NULL, NULL);
- irq_set_probe(irq);
-
/* This parent only handles asserted level IRQs */
ret = girq->populate_parent_alloc_arg(gc, &gpio_parent_fwspec,
parent_hwirq, parent_type);
@@ -1657,12 +1644,27 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
*/
if (irq_domain_is_msi(d->parent) && (ret == -EEXIST))
ret = 0;
- if (ret)
+ if (ret) {
gpiochip_err(gc,
"failed to allocate parent hwirq %d for hwirq %lu\n",
parent_hwirq, hwirq);
+ return ret;
+ }

- return ret;
+ /*
+ * We set handle_bad_irq because the .set_type() should
+ * always be invoked and set the right type of handler.
+ */
+ irq_domain_set_info(d,
+ irq,
+ hwirq,
+ gc->irq.chip,
+ gc,
+ girq->handler,
+ NULL, NULL);
+ irq_set_probe(irq);
+
+ return 0;
}

static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *gc,
--
2.47.3