Skip to content

Commit e707180

Browse files
sknseanmarckleinebudde
authored andcommitted
can: flexcan: fix possible deadlock and out-of-order reception after wakeup
When suspending, and there is still CAN traffic on the interfaces the flexcan immediately wakes the platform again. As it should :-). But it throws this error msg: [ 3169.378661] PM: noirq suspend of devices failed On the way down to suspend the interface that throws the error message calls flexcan_suspend() but fails to call flexcan_noirq_suspend(). That means flexcan_enter_stop_mode() is called, but on the way out of suspend the driver only calls flexcan_resume() and skips flexcan_noirq_resume(), thus it doesn't call flexcan_exit_stop_mode(). This leaves the flexcan in stop mode, and with the current driver it can't recover from this even with a soft reboot, it requires a hard reboot. This patch fixes the deadlock when using self wakeup, by calling flexcan_exit_stop_mode() from flexcan_resume() instead of flexcan_noirq_resume(). This also fixes another issue: CAN frames are received out-of-order in first IRQ handler run after wakeup. The problem is that the wakeup latency from frame reception to the IRQ handler (where the CAN frames are sorted by timestamp) is much bigger than the time stamp counter wrap around time. This means it's impossible to sort the CAN frames by timestamp. The reason is that the controller exits stop mode during noirq resume, which means it receives frames immediately, but interrupt handling is still not possible. So exit stop mode during resume stage instead of noirq resume fixes this issue. Fixes: de3578c ("can: flexcan: add self wakeup support") Signed-off-by: Sean Nyekjaer <[email protected]> Tested-by: Sean Nyekjaer <[email protected]> Signed-off-by: Joakim Zhang <[email protected]> Cc: linux-stable <[email protected]> # >= v5.0 Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 9ab79b0 commit e707180

File tree

1 file changed

+4
-6
lines changed

1 file changed

+4
-6
lines changed

drivers/net/can/flexcan.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,9 @@ static int __maybe_unused flexcan_resume(struct device *device)
17221722
netif_start_queue(dev);
17231723
if (device_may_wakeup(device)) {
17241724
disable_irq_wake(dev->irq);
1725+
err = flexcan_exit_stop_mode(priv);
1726+
if (err)
1727+
return err;
17251728
} else {
17261729
err = pm_runtime_force_resume(device);
17271730
if (err)
@@ -1767,14 +1770,9 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
17671770
{
17681771
struct net_device *dev = dev_get_drvdata(device);
17691772
struct flexcan_priv *priv = netdev_priv(dev);
1770-
int err;
17711773

1772-
if (netif_running(dev) && device_may_wakeup(device)) {
1774+
if (netif_running(dev) && device_may_wakeup(device))
17731775
flexcan_enable_wakeup_irq(priv, false);
1774-
err = flexcan_exit_stop_mode(priv);
1775-
if (err)
1776-
return err;
1777-
}
17781776

17791777
return 0;
17801778
}

0 commit comments

Comments
 (0)