| From 2d77bd61a2927be8f4e00d9478fe6996c47e8d45 Mon Sep 17 00:00:00 2001 |
| From: Florian Faber <faber@faberman.de> |
| Date: Thu, 26 Dec 2019 19:51:24 +0100 |
| Subject: can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling to irq mode |
| |
| From: Florian Faber <faber@faberman.de> |
| |
| commit 2d77bd61a2927be8f4e00d9478fe6996c47e8d45 upstream. |
| |
| Under load, the RX side of the mscan driver can get stuck while TX still |
| works. Restarting the interface locks up the system. This behaviour |
| could be reproduced reliably on a MPC5121e based system. |
| |
| The patch fixes the return value of the NAPI polling function (should be |
| the number of processed packets, not constant 1) and the condition under |
| which IRQs are enabled again after polling is finished. |
| |
| With this patch, no more lockups were observed over a test period of ten |
| days. |
| |
| Fixes: afa17a500a36 ("net/can: add driver for mscan family & mpc52xx_mscan") |
| Signed-off-by: Florian Faber <faber@faberman.de> |
| Cc: linux-stable <stable@vger.kernel.org> |
| Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/can/mscan/mscan.c | 21 ++++++++++----------- |
| 1 file changed, 10 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/net/can/mscan/mscan.c |
| +++ b/drivers/net/can/mscan/mscan.c |
| @@ -412,13 +412,12 @@ static int mscan_rx_poll(struct napi_str |
| struct net_device *dev = napi->dev; |
| struct mscan_regs __iomem *regs = priv->reg_base; |
| struct net_device_stats *stats = &dev->stats; |
| - int npackets = 0; |
| - int ret = 1; |
| + int work_done = 0; |
| struct sk_buff *skb; |
| struct can_frame *frame; |
| u8 canrflg; |
| |
| - while (npackets < quota) { |
| + while (work_done < quota) { |
| canrflg = in_8(®s->canrflg); |
| if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) |
| break; |
| @@ -439,18 +438,18 @@ static int mscan_rx_poll(struct napi_str |
| |
| stats->rx_packets++; |
| stats->rx_bytes += frame->can_dlc; |
| - npackets++; |
| + work_done++; |
| netif_receive_skb(skb); |
| } |
| |
| - if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { |
| - napi_complete(&priv->napi); |
| - clear_bit(F_RX_PROGRESS, &priv->flags); |
| - if (priv->can.state < CAN_STATE_BUS_OFF) |
| - out_8(®s->canrier, priv->shadow_canrier); |
| - ret = 0; |
| + if (work_done < quota) { |
| + if (likely(napi_complete_done(&priv->napi, work_done))) { |
| + clear_bit(F_RX_PROGRESS, &priv->flags); |
| + if (priv->can.state < CAN_STATE_BUS_OFF) |
| + out_8(®s->canrier, priv->shadow_canrier); |
| + } |
| } |
| - return ret; |
| + return work_done; |
| } |
| |
| static irqreturn_t mscan_isr(int irq, void *dev_id) |