* [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
@ 2026-07-02 23:18 Rosen Penev
2026-07-03 21:01 ` Linus Walleij
2026-07-06 8:59 ` Bartosz Golaszewski
0 siblings, 2 replies; 4+ messages in thread
From: Rosen Penev @ 2026-07-02 23:18 UTC (permalink / raw)
To: linux-gpio; +Cc: Linus Walleij, Bartosz Golaszewski, open list
During driver removal, devres cleans up in LIFO order. The IRQ domain
was created and its devm cleanup action registered after
devm_gpiochip_add_data(), so the domain was destroyed before the GPIO
chip was deregistered. If gpiod_to_irq() is called on a pin during
this window, mvebu_gpio_to_irq() passes the freed mvchip->domain to
irq_create_mapping().
Fix by moving the IRQ domain creation, devm cleanup action registration,
generic chip allocation, and chip type setup before
devm_gpiochip_add_data(). This ensures the GPIO chip is torn down
first (preventing new IRQ mappings), then the IRQ domain is removed,
and finally mvchip is freed.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/gpio/gpio-mvebu.c | 133 +++++++++++++++++++-------------------
1 file changed, 68 insertions(+), 65 deletions(-)
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 5b4408fcc10b..d8105a05d261 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1250,6 +1250,59 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
BUG();
}
+ /* Some gpio controllers do not provide irq support */
+ if (have_irqs) {
+ mvchip->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev),
+ ngpios,
+ &irq_generic_chip_ops,
+ NULL);
+ if (!mvchip->domain)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "couldn't allocate irq domain %s (DT).\n",
+ mvchip->chip.label);
+
+ err = devm_add_action_or_reset(&pdev->dev,
+ mvebu_gpio_remove_irq_domain,
+ mvchip->domain);
+ if (err)
+ return err;
+
+ err = irq_alloc_domain_generic_chips(
+ mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0,
+ IRQ_GC_INIT_NESTED_LOCK);
+ if (err)
+ return dev_err_probe(&pdev->dev, err,
+ "couldn't allocate irq chips %s (DT).\n",
+ mvchip->chip.label);
+
+ /*
+ * NOTE: The common accessors cannot be used because of the
+ * percpu access to the mask registers
+ */
+ gc = irq_get_domain_generic_chip(mvchip->domain, 0);
+ gc->private = mvchip;
+ ct = &gc->chip_types[0];
+ ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+ ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
+ ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
+ ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
+ ct->chip.name = mvchip->chip.label;
+
+ ct = &gc->chip_types[1];
+ ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ ct->chip.irq_ack = mvebu_gpio_irq_ack;
+ ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
+ ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
+ ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
+ ct->handler = handle_edge_irq;
+ ct->chip.name = mvchip->chip.label;
+ }
+
err = devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
if (err)
return dev_err_probe(&pdev->dev, err,
@@ -1262,71 +1315,21 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
return err;
}
- /* Some gpio controllers do not provide irq support */
- if (!have_irqs)
- return 0;
-
- mvchip->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), ngpios,
- &irq_generic_chip_ops, NULL);
- if (!mvchip->domain) {
- dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
- mvchip->chip.label);
- return -ENODEV;
- }
-
- err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain,
- mvchip->domain);
- if (err)
- return err;
-
- err = irq_alloc_domain_generic_chips(
- mvchip->domain, ngpios, 2, np->name, handle_level_irq,
- IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, IRQ_GC_INIT_NESTED_LOCK);
- if (err) {
- dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
- mvchip->chip.label);
- return err;
- }
-
- /*
- * NOTE: The common accessors cannot be used because of the percpu
- * access to the mask registers
- */
- gc = irq_get_domain_generic_chip(mvchip->domain, 0);
- gc->private = mvchip;
- ct = &gc->chip_types[0];
- ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
- ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
- ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
- ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
- ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
- ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
- ct->chip.name = mvchip->chip.label;
-
- ct = &gc->chip_types[1];
- ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
- ct->chip.irq_ack = mvebu_gpio_irq_ack;
- ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
- ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
- ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
- ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
- ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
- ct->handler = handle_edge_irq;
- ct->chip.name = mvchip->chip.label;
-
- /*
- * Setup the interrupt handlers. Each chip can have up to 4
- * interrupt handlers, with each handler dealing with 8 GPIO
- * pins.
- */
- for (i = 0; i < ARRAY_SIZE(mvchip->bank_irq); i++) {
- int irq = platform_get_irq_optional(pdev, i);
-
- if (irq < 0)
- continue;
- irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
- mvchip);
- mvchip->bank_irq[i] = irq;
+ if (have_irqs) {
+ /*
+ * Setup the interrupt handlers. Each chip can have up to 4
+ * interrupt handlers, with each handler dealing with 8 GPIO
+ * pins.
+ */
+ for (i = 0; i < ARRAY_SIZE(mvchip->bank_irq); i++) {
+ int irq = platform_get_irq_optional(pdev, i);
+
+ if (irq < 0)
+ continue;
+ irq_set_chained_handler_and_data(irq,
+ mvebu_gpio_irq_handler, mvchip);
+ mvchip->bank_irq[i] = irq;
+ }
}
return 0;
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
2026-07-02 23:18 [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Rosen Penev
@ 2026-07-03 21:01 ` Linus Walleij
2026-07-03 21:51 ` Rosen Penev
2026-07-06 8:59 ` Bartosz Golaszewski
1 sibling, 1 reply; 4+ messages in thread
From: Linus Walleij @ 2026-07-03 21:01 UTC (permalink / raw)
To: Rosen Penev; +Cc: linux-gpio, Bartosz Golaszewski, open list
Hi Rosen,
nice patch!!
On Fri, Jul 3, 2026 at 1:18 AM Rosen Penev <rosenp@gmail.com> wrote:
> During driver removal, devres cleans up in LIFO order. The IRQ domain
> was created and its devm cleanup action registered after
> devm_gpiochip_add_data(), so the domain was destroyed before the GPIO
> chip was deregistered. If gpiod_to_irq() is called on a pin during
> this window, mvebu_gpio_to_irq() passes the freed mvchip->domain to
> irq_create_mapping().
>
> Fix by moving the IRQ domain creation, devm cleanup action registration,
> generic chip allocation, and chip type setup before
> devm_gpiochip_add_data(). This ensures the GPIO chip is torn down
> first (preventing new IRQ mappings), then the IRQ domain is removed,
> and finally mvchip is freed.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Can someone from MVEBU test this on hardware?
From my PoV:
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
2026-07-03 21:01 ` Linus Walleij
@ 2026-07-03 21:51 ` Rosen Penev
0 siblings, 0 replies; 4+ messages in thread
From: Rosen Penev @ 2026-07-03 21:51 UTC (permalink / raw)
To: Linus Walleij; +Cc: linux-gpio, Bartosz Golaszewski, open list
On Fri, Jul 3, 2026 at 2:01 PM Linus Walleij <linusw@kernel.org> wrote:
>
> Hi Rosen,
>
> nice patch!!
>
> On Fri, Jul 3, 2026 at 1:18 AM Rosen Penev <rosenp@gmail.com> wrote:
>
> > During driver removal, devres cleans up in LIFO order. The IRQ domain
> > was created and its devm cleanup action registered after
> > devm_gpiochip_add_data(), so the domain was destroyed before the GPIO
> > chip was deregistered. If gpiod_to_irq() is called on a pin during
> > this window, mvebu_gpio_to_irq() passes the freed mvchip->domain to
> > irq_create_mapping().
> >
> > Fix by moving the IRQ domain creation, devm cleanup action registration,
> > generic chip allocation, and chip type setup before
> > devm_gpiochip_add_data(). This ensures the GPIO chip is torn down
> > first (preventing new IRQ mappings), then the IRQ domain is removed,
> > and finally mvchip is freed.
> >
> > Assisted-by: opencode:big-pickle
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
>
> Can someone from MVEBU test this on hardware?
> From my PoV:
I have 3 devices that use this. Tested on one. Works fine.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
>
> Yours,
> Linus Walleij
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
2026-07-02 23:18 [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Rosen Penev
2026-07-03 21:01 ` Linus Walleij
@ 2026-07-06 8:59 ` Bartosz Golaszewski
1 sibling, 0 replies; 4+ messages in thread
From: Bartosz Golaszewski @ 2026-07-06 8:59 UTC (permalink / raw)
To: Rosen Penev; +Cc: Linus Walleij, Bartosz Golaszewski, open list, linux-gpio
On Fri, 3 Jul 2026 01:18:38 +0200, Rosen Penev <rosenp@gmail.com> said:
> During driver removal, devres cleans up in LIFO order. The IRQ domain
> was created and its devm cleanup action registered after
> devm_gpiochip_add_data(), so the domain was destroyed before the GPIO
> chip was deregistered. If gpiod_to_irq() is called on a pin during
> this window, mvebu_gpio_to_irq() passes the freed mvchip->domain to
> irq_create_mapping().
>
> Fix by moving the IRQ domain creation, devm cleanup action registration,
> generic chip allocation, and chip type setup before
> devm_gpiochip_add_data(). This ensures the GPIO chip is torn down
> first (preventing new IRQ mappings), then the IRQ domain is removed,
> and finally mvchip is freed.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
Can you resend with the Fixes tag?
Bart
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-06 8:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-02 23:18 [PATCH] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Rosen Penev
2026-07-03 21:01 ` Linus Walleij
2026-07-03 21:51 ` Rosen Penev
2026-07-06 8:59 ` Bartosz Golaszewski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox