[PATCH 3/3] can: rcar_canfd: Fix interrupt registration order
From: Biju
Date: Tue Jun 30 2026 - 09:53:55 EST
From: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
In rcar_canfd_probe(), global interrupts are requested via
devm_request_irq() before rcar_canfd_global_init() enables the clocks
and before the per-channel structures in gpriv->ch[] are allocated.
If the interrupt is shared and fires immediately, the handler
rcar_canfd_global_err_interrupt() will invoke
rcar_canfd_handle_global_err(), leading to a NULL pointer
dereference.
Move the rcar_canfd_global_init() and per-channel probe calls ahead
of the devm_request_irq() calls so that clocks are enabled and
gpriv->ch[] is fully populated before any global interrupt can be
delivered. The IRQ failure paths now jump to fail_channel instead of
fail_dev, since channels are allocated earlier and must be torn down
on this path too.
Fixes: dd3bd23eb438 ("can: rcar_canfd: Add Renesas R-Car CAN FD driver")
Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
---
drivers/net/can/rcar/rcar_canfd.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index e88554388553..4ee108abffb8 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2216,6 +2216,17 @@ static int rcar_canfd_probe(struct platform_device *pdev)
gpriv->base = addr;
gpriv->fcbase = addr + gpriv->info->regs->coffset;
+ err = rcar_canfd_global_init(gpriv);
+ if (err)
+ goto fail_dev;
+
+ for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
+ err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
+ transceivers[ch]);
+ if (err)
+ goto fail_channel;
+ }
+
/* Request IRQ that's common for both channels */
if (info->shared_global_irqs) {
err = devm_request_irq(dev, ch_irq,
@@ -2224,7 +2235,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
if (err) {
dev_err(dev, "devm_request_irq %d failed: %pe\n",
ch_irq, ERR_PTR(err));
- goto fail_dev;
+ goto fail_channel;
}
err = devm_request_irq(dev, g_irq, rcar_canfd_global_interrupt,
@@ -2232,7 +2243,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
if (err) {
dev_err(dev, "devm_request_irq %d failed: %pe\n",
g_irq, ERR_PTR(err));
- goto fail_dev;
+ goto fail_channel;
}
} else {
err = devm_request_irq(dev, g_recc_irq,
@@ -2242,7 +2253,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
if (err) {
dev_err(dev, "devm_request_irq %d failed: %pe\n",
g_recc_irq, ERR_PTR(err));
- goto fail_dev;
+ goto fail_channel;
}
err = devm_request_irq(dev, g_err_irq,
@@ -2251,19 +2262,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
if (err) {
dev_err(dev, "devm_request_irq %d failed: %pe\n",
g_err_irq, ERR_PTR(err));
- goto fail_dev;
- }
- }
-
- err = rcar_canfd_global_init(gpriv);
- if (err)
- goto fail_dev;
-
- for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
- err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
- transceivers[ch]);
- if (err)
goto fail_channel;
+ }
}
platform_set_drvdata(pdev, gpriv);
--
2.43.0