[PATCH v2 1/2] can: m_can: Fix suspend deinit() error path
From: Markus Schneider-Pargmann (TI)
Date: Fri Oct 16 2026 - 06:05:58 EST
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@xxxxxxxxxxxx>
---
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