Skip to content

Commit 7fb4f56

Browse files
JakeHamby-TDYgregkh
authored andcommitted
can: m_can: enable NAPI before enabling interrupts
[ Upstream commit 801ad2f ] If an interrupt (RX-complete or error flag) is set when bringing up the CAN device, e.g. due to CAN bus traffic before initializing the device, when m_can_start() is called and interrupts are enabled, m_can_isr() is called immediately, which disables all CAN interrupts and calls napi_schedule(). Because napi_enable() isn't called until later in m_can_open(), the call to napi_schedule() never schedules the m_can_poll() callback and the device is left with interrupts disabled and can't receive any CAN packets until rebooted. This can be verified by running "cansend" from another device before setting the bitrate and calling "ip link set up can0" on the test device. Adding debug lines to m_can_isr() shows it's called with flags (IR_EP | IR_EW | IR_CRCE), which calls m_can_disable_all_interrupts() and napi_schedule(), and then m_can_poll() is never called. Move the call to napi_enable() above the call to m_can_start() to enable any initial interrupt flags to be handled by m_can_poll() so that interrupts are reenabled. Add a call to napi_disable() in the error handling section of m_can_open(), to handle the case where later functions return errors. Also, in m_can_close(), move the call to napi_disable() below the call to m_can_stop() to ensure all interrupts are handled when bringing down the device. This race condition is much less likely to occur. Tested on a Microchip SAMA7G54 MPU. The fix should be applicable to any SoC with a Bosch M_CAN controller. Signed-off-by: Jake Hamby <Jake.Hamby@Teledyne.com> Fixes: e0d1f48 ("can: m_can: add Bosch M_CAN controller support") Link: https://patch.msgid.link/20240910-can-m_can-fix-ifup-v3-1-6c1720ba45ce@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent c3d941c commit 7fb4f56

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

drivers/net/can/m_can/m_can.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,9 +1599,6 @@ static int m_can_close(struct net_device *dev)
15991599

16001600
netif_stop_queue(dev);
16011601

1602-
if (!cdev->is_peripheral)
1603-
napi_disable(&cdev->napi);
1604-
16051602
m_can_stop(dev);
16061603
m_can_clk_stop(cdev);
16071604
free_irq(dev->irq, dev);
@@ -1611,6 +1608,8 @@ static int m_can_close(struct net_device *dev)
16111608
destroy_workqueue(cdev->tx_wq);
16121609
cdev->tx_wq = NULL;
16131610
can_rx_offload_disable(&cdev->offload);
1611+
} else {
1612+
napi_disable(&cdev->napi);
16141613
}
16151614

16161615
close_candev(dev);
@@ -1842,6 +1841,8 @@ static int m_can_open(struct net_device *dev)
18421841

18431842
if (cdev->is_peripheral)
18441843
can_rx_offload_enable(&cdev->offload);
1844+
else
1845+
napi_enable(&cdev->napi);
18451846

18461847
/* register interrupt handler */
18471848
if (cdev->is_peripheral) {
@@ -1873,9 +1874,6 @@ static int m_can_open(struct net_device *dev)
18731874
if (err)
18741875
goto exit_start_fail;
18751876

1876-
if (!cdev->is_peripheral)
1877-
napi_enable(&cdev->napi);
1878-
18791877
netif_start_queue(dev);
18801878

18811879
return 0;
@@ -1889,6 +1887,8 @@ static int m_can_open(struct net_device *dev)
18891887
out_wq_fail:
18901888
if (cdev->is_peripheral)
18911889
can_rx_offload_disable(&cdev->offload);
1890+
else
1891+
napi_disable(&cdev->napi);
18921892
close_candev(dev);
18931893
exit_disable_clks:
18941894
m_can_clk_stop(cdev);

0 commit comments

Comments
 (0)