Skip to content

Commit

Permalink
can: rx-offload: can_rx_offload_threaded_irq_finish(): add new functi…
Browse files Browse the repository at this point in the history
…on to be called from threaded interrupt

After reading all CAN frames from the controller in the IRQ handler
and storing them into a skb_queue, the driver calls napi_schedule().
In the napi poll function the skb from the skb_queue are then pushed
into the networking stack.

However if napi_schedule() is called from a threaded IRQ handler this
triggers the following error:

| NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #08!!!

To avoid this, create a new rx-offload
function (can_rx_offload_threaded_irq_finish()) with a call to
local_bh_disable()/local_bh_enable() around the napi_schedule() call.

Convert all drivers that call can_rx_offload_irq_finish() from
threaded IRQ context to can_rx_offload_threaded_irq_finish().

Link: https://lore.kernel.org/r/20210724204745.736053-4-mkl@pengutronix.de
Suggested-by: Daniel Glöckner <dg@emlix.com>
Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
  • Loading branch information
Marc Kleine-Budde committed Jul 25, 2021
1 parent 1e0d8e5 commit 30bfec4
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 3 deletions.
23 changes: 23 additions & 0 deletions drivers/net/can/dev/rx-offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,29 @@ void can_rx_offload_irq_finish(struct can_rx_offload *offload)
}
EXPORT_SYMBOL_GPL(can_rx_offload_irq_finish);

void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload)
{
unsigned long flags;
int queue_len;

if (skb_queue_empty_lockless(&offload->skb_irq_queue))
return;

spin_lock_irqsave(&offload->skb_queue.lock, flags);
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);

queue_len = skb_queue_len(&offload->skb_queue);
if (queue_len > offload->skb_queue_len_max / 8)
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
__func__, queue_len);

local_bh_disable();
napi_schedule(&offload->napi);
local_bh_enable();
}
EXPORT_SYMBOL_GPL(can_rx_offload_threaded_irq_finish);

static int can_rx_offload_init_queue(struct net_device *dev,
struct can_rx_offload *offload,
unsigned int weight)
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/can/m_can/m_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
}

if (cdev->is_peripheral)
can_rx_offload_irq_finish(&cdev->offload);
can_rx_offload_threaded_irq_finish(&cdev->offload);

return IRQ_HANDLED;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2196,7 +2196,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
priv->regs_status.intf);

if (!(intf_pending)) {
can_rx_offload_irq_finish(&priv->offload);
can_rx_offload_threaded_irq_finish(&priv->offload);
return handled;
}

Expand Down Expand Up @@ -2298,7 +2298,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
} while (1);

out_fail:
can_rx_offload_irq_finish(&priv->offload);
can_rx_offload_threaded_irq_finish(&priv->offload);

netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
err, priv->regs_status.intf);
Expand Down
1 change: 1 addition & 0 deletions include/linux/can/rx-offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
struct sk_buff *skb);
void can_rx_offload_irq_finish(struct can_rx_offload *offload);
void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload);
void can_rx_offload_del(struct can_rx_offload *offload);
void can_rx_offload_enable(struct can_rx_offload *offload);

Expand Down

0 comments on commit 30bfec4

Please sign in to comment.