* [PATCH v2 0/2] can: m_can: Fix suspend deinit() error path
@ 2026-10-16 9:57 Markus Schneider-Pargmann (TI)
2026-10-16 9:57 ` [PATCH v2 1/2] " Markus Schneider-Pargmann (TI)
2026-10-16 9:57 ` [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling Markus Schneider-Pargmann
0 siblings, 2 replies; 6+ messages in thread
From: Markus Schneider-Pargmann (TI) @ 2026-10-16 9:57 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Sean Nyekjaer,
Martin Hundebøll
Cc: Kendall Willis, linux-can, linux-kernel,
Markus Schneider-Pargmann (TI)
Hi,
this small series tries to make the suspend error path of m_can a bit
better.
Best,
Markus
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
Changes in v2:
- Add a patch for tcan suspend
- Start the hrtimer if coalescing is active and suspend is cancelled
instead of modifying active_interrupts
- Link to v1: https://patch.msgid.link/20260918-v7-3-topic-mcan-suspend-fix-fix-v1-1-e24fa70c754e@baylibre.com
To: Markus Schneider-Pargmann <msp@baylibre.com>
To: Marc Kleine-Budde <mkl@pengutronix.de>
To: Vincent Mailhol <mailhol@kernel.org>
To: Sean Nyekjaer <sean@geanix.com>
To: Martin Hundebøll <martin@geanix.com>
Cc: linux-can@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Markus Schneider-Pargmann (1):
can: tcan4x5x: Add suspend error handling
Markus Schneider-Pargmann (TI) (1):
can: m_can: Fix suspend deinit() error path
drivers/net/can/m_can/m_can.c | 25 ++++++++++++++++++++++++-
drivers/net/can/m_can/tcan4x5x-core.c | 11 ++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260914-v7-3-topic-mcan-suspend-fix-fix-b943929d8fef
Best regards,
--
Markus Schneider-Pargmann <msp@baylibre.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] can: m_can: Fix suspend deinit() error path
2026-10-16 9:57 [PATCH v2 0/2] can: m_can: Fix suspend deinit() error path Markus Schneider-Pargmann (TI)
@ 2026-10-16 9:57 ` Markus Schneider-Pargmann (TI)
2026-10-16 10:13 ` sashiko-bot
2026-10-16 9:57 ` [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling Markus Schneider-Pargmann
1 sibling, 1 reply; 6+ messages in thread
From: Markus Schneider-Pargmann (TI) @ 2026-10-16 9:57 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Sean Nyekjaer,
Martin Hundebøll
Cc: Kendall Willis, linux-can, linux-kernel,
Markus Schneider-Pargmann (TI)
When suspending mcan, deinit is called and its return value is returned,
but nothing is restored. Returning an error in the suspend function will
stop suspending and resume the system immediately. So on error the
device should be restored to its previous state. If coalescing is
active, the hrtimer is restarted.
Fixes: ad1ddb3bfb0c ("can: m_can: call deinit/init callback when going into suspend/resume")
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
drivers/net/can/m_can/m_can.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 16f80607e150..02a95a769a78 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -2612,8 +2612,14 @@ int m_can_class_suspend(struct device *dev)
hrtimer_cancel(&cdev->hrtimer);
m_can_write(cdev, M_CAN_IE, IR_RF0N);
- if (cdev->ops->deinit)
+ if (cdev->ops->deinit) {
ret = cdev->ops->deinit(cdev);
+ if (ret) {
+ netdev_err(cdev->net, "failed to deinit device while suspending %pe\n",
+ ERR_PTR(ret));
+ goto err_pm_wake_source;
+ }
+ }
} else {
m_can_stop(ndev);
}
@@ -2625,6 +2631,23 @@ int m_can_class_suspend(struct device *dev)
if (!m_can_class_wakeup_pinctrl_enabled(cdev))
pinctrl_pm_select_sleep_state(dev);
+ return 0;
+
+err_pm_wake_source:
+ if (netif_running(ndev)) {
+ if (cdev->pm_wake_source) {
+ bool coalescing_active = (cdev->active_interrupts & (IR_RF0N | IR_TEFN))
+ != (IR_RF0N | IR_TEFN);
+ m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
+ if (coalescing_active)
+ hrtimer_start(&cdev->hrtimer,
+ cdev->irq_timer_wait,
+ HRTIMER_MODE_REL);
+ }
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(m_can_class_suspend);
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling
2026-10-16 9:57 [PATCH v2 0/2] can: m_can: Fix suspend deinit() error path Markus Schneider-Pargmann (TI)
2026-10-16 9:57 ` [PATCH v2 1/2] " Markus Schneider-Pargmann (TI)
@ 2026-10-16 9:57 ` Markus Schneider-Pargmann
2026-10-16 10:04 ` Martin Hundebøll
2026-10-16 10:05 ` sashiko-bot
1 sibling, 2 replies; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2026-10-16 9:57 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Sean Nyekjaer,
Martin Hundebøll
Cc: Kendall Willis, linux-can, linux-kernel,
Markus Schneider-Pargmann (TI)
m_can_class_suspend() may return errors. On error we should first
restore the previous state and then pass the error code on. Otherwise we
keep the device in a misconfigured state for the running state.
Fixes: b6b640c04446 ("can: tcan4x5x: support resuming from rx interrupt signal")
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
---
drivers/net/can/m_can/tcan4x5x-core.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c
index a5b8829aa519..b69312413d62 100644
--- a/drivers/net/can/m_can/tcan4x5x-core.c
+++ b/drivers/net/can/m_can/tcan4x5x-core.c
@@ -575,11 +575,20 @@ static int __maybe_unused tcan4x5x_suspend(struct device *dev)
{
struct m_can_classdev *cdev = dev_get_drvdata(dev);
struct spi_device *spi = to_spi_device(dev);
+ int ret;
if (cdev->pm_wake_source)
enable_irq_wake(spi->irq);
- return m_can_class_suspend(dev);
+ ret = m_can_class_suspend(dev);
+ if (ret)
+ goto err_disable_irq;
+ return 0;
+
+err_disable_irq:
+ if (cdev->pm_wake_source)
+ disable_irq_wake(spi->irq);
+ return ret;
}
static int __maybe_unused tcan4x5x_resume(struct device *dev)
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling
2026-10-16 9:57 ` [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling Markus Schneider-Pargmann
@ 2026-10-16 10:04 ` Martin Hundebøll
2026-10-16 10:05 ` sashiko-bot
1 sibling, 0 replies; 6+ messages in thread
From: Martin Hundebøll @ 2026-10-16 10:04 UTC (permalink / raw)
To: Markus Schneider-Pargmann, Marc Kleine-Budde, Vincent Mailhol,
Sean Nyekjaer
Cc: Kendall Willis, linux-can, linux-kernel
Hi Markus,
On Fri, 2026-10-16 at 11:57 +0200, Markus Schneider-Pargmann wrote:
> diff --git a/drivers/net/can/m_can/tcan4x5x-core.c
> b/drivers/net/can/m_can/tcan4x5x-core.c
> index a5b8829aa519..b69312413d62 100644
> --- a/drivers/net/can/m_can/tcan4x5x-core.c
> +++ b/drivers/net/can/m_can/tcan4x5x-core.c
> @@ -575,11 +575,20 @@ static int __maybe_unused
> tcan4x5x_suspend(struct device *dev)
> {
> struct m_can_classdev *cdev = dev_get_drvdata(dev);
> struct spi_device *spi = to_spi_device(dev);
> + int ret;
>
> if (cdev->pm_wake_source)
> enable_irq_wake(spi->irq);
>
> - return m_can_class_suspend(dev);
> + ret = m_can_class_suspend(dev);
> + if (ret)
> + goto err_disable_irq;
> + return 0;
> +
> +err_disable_irq:
> + if (cdev->pm_wake_source)
> + disable_irq_wake(spi->irq);
> + return ret;
Wouldn't this be better written in the shorter form:
ret = m_can_class_suspend(dev);
if (ret && dev->pm_wake_source)
disable_irq_wake(spi->irq);
return ret;
?
// Martin
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling
2026-10-16 9:57 ` [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling Markus Schneider-Pargmann
2026-10-16 10:04 ` Martin Hundebøll
@ 2026-10-16 10:05 ` sashiko-bot
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-10-16 10:05 UTC (permalink / raw)
To: Markus Schneider-Pargmann
Cc: linux-can, Marc Kleine-Budde, Oliver Hartkopp, Vincent Mailhol,
Oleksij Rempel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] irq: unbalanced IRQ wake disable on suspend error path
--
commit 35cb9abaa9dd12aabf550562b5fe36f26129d629
Author: Markus Schneider-Pargmann <msp@baylibre.com>
can: tcan4x5x: Add suspend error handling
This commit adds error handling to tcan4x5x_suspend() by checking the
return value of m_can_class_suspend(). If the suspend fails, it restores
the IRQ wake state before returning the error.
> diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c
> index a5b8829aa5193..b69312413d627 100644
> --- a/drivers/net/can/m_can/tcan4x5x-core.c
> +++ b/drivers/net/can/m_can/tcan4x5x-core.c
> @@ -575,11 +575,20 @@ static int __maybe_unused tcan4x5x_suspend(struct device *dev)
> {
> struct m_can_classdev *cdev = dev_get_drvdata(dev);
> struct spi_device *spi = to_spi_device(dev);
> + int ret;
>
> if (cdev->pm_wake_source)
> enable_irq_wake(spi->irq);
>
> - return m_can_class_suspend(dev);
> + ret = m_can_class_suspend(dev);
> + if (ret)
> + goto err_disable_irq;
> + return 0;
> +
> +err_disable_irq:
> + if (cdev->pm_wake_source)
> + disable_irq_wake(spi->irq);
[Severity: Low]
Will this trigger an unbalanced IRQ wake disable warning if
enable_irq_wake() fails?
The original code calls enable_irq_wake() but ignores its return value.
If the underlying IRQ controller does not support wake settings (e.g.
returning -ENXIO), wake_depth is not incremented.
If m_can_class_suspend() subsequently fails, the new error path calls
disable_irq_wake() unconditionally. If enable_irq_wake() had previously
failed, wouldn't this underflow wake_depth and trigger a WARN from the IRQ
core?
Could we check the return value of enable_irq_wake() and only call
disable_irq_wake() if it actually succeeded?
> + return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261016-v7-3-topic-mcan-suspend-fix-fix-v2-0-7efa2b172cce@baylibre.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] can: m_can: Fix suspend deinit() error path
2026-10-16 9:57 ` [PATCH v2 1/2] " Markus Schneider-Pargmann (TI)
@ 2026-10-16 10:13 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-10-16 10:13 UTC (permalink / raw)
To: Markus Schneider-Pargmann (TI)
Cc: linux-can, Marc Kleine-Budde, Oliver Hartkopp, Vincent Mailhol,
Oleksij Rempel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] can: m_can: suspend error path permanently stalls polling mode
- [Medium] can: m_can: race in suspend error path leads to permanent rx stall
--
commit 483c34ecb4b606d88b805473f5b905d713840725
Author: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
can: m_can: Fix suspend deinit() error path
When suspending mcan, deinit is called and its return value is returned,
but nothing is restored. This commit adds an error path to restore the
device to its previous state, including restarting the coalescing hrtimer.
> diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
> index 16f80607e150e..02a95a769a784 100644
> --- a/drivers/net/can/m_can/m_can.c
> +++ b/drivers/net/can/m_can/m_can.c
[ ... ]
> @@ -2625,6 +2631,23 @@ int m_can_class_suspend(struct device *dev)
> if (!m_can_class_wakeup_pinctrl_enabled(cdev))
> pinctrl_pm_select_sleep_state(dev);
>
> + return 0;
> +
> +err_pm_wake_source:
> + if (netif_running(ndev)) {
> + if (cdev->pm_wake_source) {
> + bool coalescing_active = (cdev->active_interrupts & (IR_RF0N | IR_TEFN))
> + != (IR_RF0N | IR_TEFN);
[Severity: High]
If the device operates in polling mode (!cdev->net->irq) and acts as a wake
source (cdev->pm_wake_source == true), does this error path permanently
stall the polling mode?
The tcan4x5x driver allows pm_wake_source to be true even if spi->irq is 0
(polling mode). In polling mode, all active interrupt bits (IR_ALL_INT) are
retained, so coalescing_active will evaluate to false. As a result, the
polling timer cancelled earlier in suspend will never be restarted here.
Additionally, if the timer were to be restarted, would using the coalescing
parameters (cdev->irq_timer_wait, HRTIMER_MODE_REL) be correct, or should it
use the polling parameters (HRTIMER_POLL_INTERVAL_MS,
HRTIMER_MODE_REL_PINNED)?
> + m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
[Severity: Medium]
Could this non-atomic read and write introduce a race condition leading to
a permanent RX stall?
Earlier in m_can_class_suspend(), m_can_write(cdev, M_CAN_IE, IR_RF0N)
enables RX wakeups, which allows a concurrent threaded ISR to run if an
RX packet arrives.
If the ISR coalescing timer expires exactly between evaluating
coalescing_active (reading cdev->active_interrupts) and writing it to
M_CAN_IE here, the hardware could be overwritten with a stale mask that
leaves RX disabled.
If the error path then restarts the timer, the ISR's next execution
might see the software state already has RX enabled and skip updating the
hardware, leaving the hardware and software states permanently out of sync.
> + if (coalescing_active)
> + hrtimer_start(&cdev->hrtimer,
> + cdev->irq_timer_wait,
> + HRTIMER_MODE_REL);
> + }
> + netif_device_attach(ndev);
> + netif_start_queue(ndev);
> + }
> +
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261016-v7-3-topic-mcan-suspend-fix-fix-v2-0-7efa2b172cce@baylibre.com?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-16 10:13 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 9:57 [PATCH v2 0/2] can: m_can: Fix suspend deinit() error path Markus Schneider-Pargmann (TI)
2026-10-16 9:57 ` [PATCH v2 1/2] " Markus Schneider-Pargmann (TI)
2026-10-16 10:13 ` sashiko-bot
2026-10-16 9:57 ` [PATCH v2 2/2] can: tcan4x5x: Add suspend error handling Markus Schneider-Pargmann
2026-10-16 10:04 ` Martin Hundebøll
2026-10-16 10:05 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox