Skip to content

Commit 30bfec4

Browse files
can: rx-offload: can_rx_offload_threaded_irq_finish(): add new function 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 kernel-patches#8!!! 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/[email protected] Suggested-by: Daniel Glöckner <[email protected]> Tested-by: Oleksij Rempel <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 1e0d8e5 commit 30bfec4

File tree

4 files changed

+27
-3
lines changed

4 files changed

+27
-3
lines changed

drivers/net/can/dev/rx-offload.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,29 @@ void can_rx_offload_irq_finish(struct can_rx_offload *offload)
299299
}
300300
EXPORT_SYMBOL_GPL(can_rx_offload_irq_finish);
301301

302+
void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload)
303+
{
304+
unsigned long flags;
305+
int queue_len;
306+
307+
if (skb_queue_empty_lockless(&offload->skb_irq_queue))
308+
return;
309+
310+
spin_lock_irqsave(&offload->skb_queue.lock, flags);
311+
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
312+
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
313+
314+
queue_len = skb_queue_len(&offload->skb_queue);
315+
if (queue_len > offload->skb_queue_len_max / 8)
316+
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
317+
__func__, queue_len);
318+
319+
local_bh_disable();
320+
napi_schedule(&offload->napi);
321+
local_bh_enable();
322+
}
323+
EXPORT_SYMBOL_GPL(can_rx_offload_threaded_irq_finish);
324+
302325
static int can_rx_offload_init_queue(struct net_device *dev,
303326
struct can_rx_offload *offload,
304327
unsigned int weight)

drivers/net/can/m_can/m_can.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
10591059
}
10601060

10611061
if (cdev->is_peripheral)
1062-
can_rx_offload_irq_finish(&cdev->offload);
1062+
can_rx_offload_threaded_irq_finish(&cdev->offload);
10631063

10641064
return IRQ_HANDLED;
10651065
}

drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,7 +2196,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
21962196
priv->regs_status.intf);
21972197

21982198
if (!(intf_pending)) {
2199-
can_rx_offload_irq_finish(&priv->offload);
2199+
can_rx_offload_threaded_irq_finish(&priv->offload);
22002200
return handled;
22012201
}
22022202

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

23002300
out_fail:
2301-
can_rx_offload_irq_finish(&priv->offload);
2301+
can_rx_offload_threaded_irq_finish(&priv->offload);
23022302

23032303
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
23042304
err, priv->regs_status.intf);

include/linux/can/rx-offload.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
5050
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
5151
struct sk_buff *skb);
5252
void can_rx_offload_irq_finish(struct can_rx_offload *offload);
53+
void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload);
5354
void can_rx_offload_del(struct can_rx_offload *offload);
5455
void can_rx_offload_enable(struct can_rx_offload *offload);
5556

0 commit comments

Comments
 (0)