Commit 702de2c2 authored by Biju Das's avatar Biju Das Committed by Marc Kleine-Budde

can: rcar_canfd: rcar_canfd_handle_global_receive(): fix IRQ storm on global FIFO receive

We are seeing an IRQ storm on the global receive IRQ line under heavy
CAN bus load conditions with both CAN channels enabled.

Conditions:

The global receive IRQ line is shared between can0 and can1, either of
the channels can trigger interrupt while the other channel's IRQ line
is disabled (RFIE).

When global a receive IRQ interrupt occurs, we mask the interrupt in
the IRQ handler. Clearing and unmasking of the interrupt is happening
in rx_poll(). There is a race condition where rx_poll() unmasks the
interrupt, but the next IRQ handler does not mask the IRQ due to
NAPIF_STATE_MISSED flag (e.g.: can0 RX FIFO interrupt is disabled and
can1 is triggering RX interrupt, the delay in rx_poll() processing
results in setting NAPIF_STATE_MISSED flag) leading to an IRQ storm.

This patch fixes the issue by checking IRQ active and enabled before
handling the IRQ on a particular channel.

Fixes: dd3bd23e ("can: rcar_canfd: Add Renesas R-Car CAN FD driver")
Suggested-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: default avatarBiju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/all/20221025155657.1426948-2-biju.das.jz@bp.renesas.com
Cc: stable@vger.kernel.org
[mkl: adjust commit message]
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 2871edb3
...@@ -1157,11 +1157,13 @@ static void rcar_canfd_handle_global_receive(struct rcar_canfd_global *gpriv, u3 ...@@ -1157,11 +1157,13 @@ static void rcar_canfd_handle_global_receive(struct rcar_canfd_global *gpriv, u3
{ {
struct rcar_canfd_channel *priv = gpriv->ch[ch]; struct rcar_canfd_channel *priv = gpriv->ch[ch];
u32 ridx = ch + RCANFD_RFFIFO_IDX; u32 ridx = ch + RCANFD_RFFIFO_IDX;
u32 sts; u32 sts, cc;
/* Handle Rx interrupts */ /* Handle Rx interrupts */
sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(gpriv, ridx)); sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(gpriv, ridx));
if (likely(sts & RCANFD_RFSTS_RFIF)) { cc = rcar_canfd_read(priv->base, RCANFD_RFCC(gpriv, ridx));
if (likely(sts & RCANFD_RFSTS_RFIF &&
cc & RCANFD_RFCC_RFIE)) {
if (napi_schedule_prep(&priv->napi)) { if (napi_schedule_prep(&priv->napi)) {
/* Disable Rx FIFO interrupts */ /* Disable Rx FIFO interrupts */
rcar_canfd_clear_bit(priv->base, rcar_canfd_clear_bit(priv->base,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment