* [PATCHv2] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
@ 2026-07-06 23:22 Rosen Penev
2026-07-07 7:13 ` Uwe Kleine-König
0 siblings, 1 reply; 2+ messages in thread
From: Rosen Penev @ 2026-07-06 23:22 UTC (permalink / raw)
To: linux-gpio
Cc: Linus Walleij, Bartosz Golaszewski, Uwe Kleine-König,
Andy Shevchenko, 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.
Fixes: 644ee70267a9 ("gpio: mvebu: fix irq domain leak")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
v2: added Fixes tag
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] 2+ messages in thread* Re: [PATCHv2] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain
2026-07-06 23:22 [PATCHv2] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Rosen Penev
@ 2026-07-07 7:13 ` Uwe Kleine-König
0 siblings, 0 replies; 2+ messages in thread
From: Uwe Kleine-König @ 2026-07-07 7:13 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-gpio, Linus Walleij, Bartosz Golaszewski, Andy Shevchenko,
open list
[-- Attachment #1: Type: text/plain, Size: 1358 bytes --]
On Mon, Jul 06, 2026 at 04:22:23PM -0700, Rosen Penev 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().
Without having looked at your patch, I would expect that there is a
similar window during probe where calling gpiod_to_irq() between
devm_gpiochip_add_data() and IRQ domain creation results in an invalid
mvchip->domain being passed to irq_create_mapping(), right?
> 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.
>
> Fixes: 644ee70267a9 ("gpio: mvebu: fix irq domain leak")
If the above is right, the referenced commit only creates the issue at
driver detach. The issue at probe time exists since
fefe7b092345 ("gpio: introduce gpio-mvebu driver for Marvell SoCs")
which has `gpiochip_add(&mvchip->chip);` before coping for irqs.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-07 7:13 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 23:22 [PATCHv2] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Rosen Penev
2026-07-07 7:13 ` Uwe Kleine-König
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.