blob: 2d55cb9401f6e5b47187229864032af9160dde76 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 59876225748221d7ebbdb9c892a2086420ddd80d Mon Sep 17 00:00:00 2001
2From: Sean Nyekjaer <sean@geanix.com>
3Date: Thu, 14 Nov 2019 19:56:28 +0800
4Subject: [PATCH] can: flexcan: fix deadlock when using self wakeup
5
6When suspending, when there is still can traffic on the interfaces the
7flexcan immediately wakes the platform again. As it should :-). But it
8throws this error msg:
9[ 3169.378661] PM: noirq suspend of devices failed
10
11On the way down to suspend the interface that throws the error message does
12call flexcan_suspend but fails to call flexcan_noirq_suspend. That means the
13flexcan_enter_stop_mode is called, but on the way out of suspend the driver
14only calls flexcan_resume and skips flexcan_noirq_resume, thus it doesn't call
15flexcan_exit_stop_mode. This leaves the flexcan in stop mode, and with the
16current driver it can't recover from this even with a soft reboot, it requires
17a hard reboot.
18
19This patch can fix deadlock when using self wakeup, it happenes to be
20able to fix another issue that frames out-of-order in first IRQ handler
21run after wakeup.
22
23In wakeup case, after system resume, frames received out-of-order,the
24problem is wakeup latency from frame reception to IRQ handler is much
25bigger than the counter overflow. This means it's impossible to sort the
26CAN frames by timestamp. The reason is that controller exits stop mode
27during noirq resume, then it can receive the frame immediately. If
28noirq reusme stage consumes much time, it will extend interrupt response
29time.
30
31Fixes: de3578c198c6 ("can: flexcan: add self wakeup support")
32Signed-off-by: Sean Nyekjaer <sean@geanix.com>
33Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
34---
35 drivers/net/can/flexcan.c | 9 +++++++--
36 1 file changed, 7 insertions(+), 2 deletions(-)
37
38--- a/drivers/net/can/flexcan.c
39+++ b/drivers/net/can/flexcan.c
40@@ -137,8 +137,7 @@
41 (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
42 #define FLEXCAN_ESR_ALL_INT \
43 (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
44- FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
45- FLEXCAN_ESR_WAK_INT)
46+ FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
47
48 /* FLEXCAN Bit Timing register (CBT) bits */
49 #define FLEXCAN_CBT_BTF BIT(31)
50@@ -1062,6 +1061,12 @@ static irqreturn_t flexcan_irq(int irq,
51
52 reg_esr = priv->read(&regs->esr);
53
54+ /* ACK wakeup interrupt */
55+ if (reg_esr & FLEXCAN_ESR_WAK_INT) {
56+ handled = IRQ_HANDLED;
57+ priv->write(reg_esr & FLEXCAN_ESR_WAK_INT, &regs->esr);
58+ }
59+
60 /* ACK all bus error and state change IRQ sources */
61 if (reg_esr & FLEXCAN_ESR_ALL_INT) {
62 handled = IRQ_HANDLED;