Message ID | 20240910-can-m_can-fix-ifup-v3-1-6c1720ba45ce@pengutronix.de (mailing list archive) |
---|---|
State | Awaiting Upstream |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | can: m_can: fix struct net_device_ops::{open,stop} callbacks under high bus load | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Series ignored based on subject |
On 10.09.2024 19:15:28, Marc Kleine-Budde wrote: > From: Jake Hamby <Jake.Hamby@Teledyne.com> > > 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: e0d1f4816f2a ("can: m_can: add Bosch M_CAN controller support") > Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Tested successfully on a stm32mp1. Tested-by: Marc Kleine-Budde <mkl@pengutronix.de> regards, Mar c
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 012c3d22b01dd3d8558f2a40448770ca1da1aa1e..c1a07013433eb7b863eee072b959f46c1d5b008d 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1763,9 +1763,6 @@ static int m_can_close(struct net_device *dev) netif_stop_queue(dev); - if (!cdev->is_peripheral) - napi_disable(&cdev->napi); - m_can_stop(dev); m_can_clk_stop(cdev); free_irq(dev->irq, dev); @@ -1776,6 +1773,8 @@ static int m_can_close(struct net_device *dev) destroy_workqueue(cdev->tx_wq); cdev->tx_wq = NULL; can_rx_offload_disable(&cdev->offload); + } else { + napi_disable(&cdev->napi); } close_candev(dev); @@ -2030,6 +2029,8 @@ static int m_can_open(struct net_device *dev) if (cdev->is_peripheral) can_rx_offload_enable(&cdev->offload); + else + napi_enable(&cdev->napi); /* register interrupt handler */ if (cdev->is_peripheral) { @@ -2063,9 +2064,6 @@ static int m_can_open(struct net_device *dev) if (err) goto exit_start_fail; - if (!cdev->is_peripheral) - napi_enable(&cdev->napi); - netif_start_queue(dev); return 0; @@ -2079,6 +2077,8 @@ static int m_can_open(struct net_device *dev) out_wq_fail: if (cdev->is_peripheral) can_rx_offload_disable(&cdev->offload); + else + napi_disable(&cdev->napi); close_candev(dev); exit_disable_clks: m_can_clk_stop(cdev);