The following happened on an i.MX25 using flexcan with many packets on the bus:
The rx-offload queue reached a length more than skb_queue_len_max. In can_rx_offload_offload_one() the drop variable was set to true which made the call to .mailbox_read() (here: flexcan_mailbox_read()) to _always_ return ERR_PTR(-ENOBUFS) and drop the rx'ed CAN frame. So can_rx_offload_offload_one() returned ERR_PTR(-ENOBUFS), too.
can_rx_offload_irq_offload_fifo() looks as follows:
| while (1) { | skb = can_rx_offload_offload_one(offload, 0); | if (IS_ERR(skb)) | continue; | if (!skb) | break; | ... | }
The flexcan driver wrongly always returns ERR_PTR(-ENOBUFS) if drop is requested, even if there is no CAN frame pending. As the i.MX25 is a single core CPU, while the rx-offload processing is active, there is no thread to process packets from the offload queue. So the queue doesn't get any shorter and this results is a tight loop.
Instead of always returning ERR_PTR(-ENOBUFS) if drop is requested, return NULL if no CAN frame is pending.
Changes since v1: https://lore.kernel.org/all/20220810144536.389237-1-u.kleine-koenig@pengutro... - don't break in can_rx_offload_irq_offload_fifo() in case of an error, return NULL in flexcan_mailbox_read() in case of no pending CAN frame instead
Fixes: 4e9c9484b085 ("can: rx-offload: Prepare for CAN FD support") Link: https://lore.kernel.org/all/20220811094254.1864367-1-mkl@pengutronix.de Cc: stable@vger.kernel.org # v5.5 Suggested-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Reviewed-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Tested-by: Thorsten Scherer t.scherer@eckelmann.de Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de --- drivers/net/can/flexcan/flexcan-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index f857968efed7..ccb438eca517 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -941,11 +941,6 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, u32 reg_ctrl, reg_id, reg_iflag1; int i;
- if (unlikely(drop)) { - skb = ERR_PTR(-ENOBUFS); - goto mark_as_read; - } - mb = flexcan_get_mb(priv, n);
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) { @@ -974,6 +969,11 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, reg_ctrl = priv->read(&mb->can_ctrl); }
+ if (unlikely(drop)) { + skb = ERR_PTR(-ENOBUFS); + goto mark_as_read; + } + if (reg_ctrl & FLEXCAN_MB_CNT_EDL) skb = alloc_canfd_skb(offload->dev, &cfd); else
base-commit: 6a1dbfefdae4f7809b3e277cc76785dac0ac1cd0
Hello:
This series was applied to netdev/net.git (master) by Marc Kleine-Budde mkl@pengutronix.de:
On Wed, 21 Sep 2022 10:36:07 +0200 you wrote:
The following happened on an i.MX25 using flexcan with many packets on the bus:
The rx-offload queue reached a length more than skb_queue_len_max. In can_rx_offload_offload_one() the drop variable was set to true which made the call to .mailbox_read() (here: flexcan_mailbox_read()) to _always_ return ERR_PTR(-ENOBUFS) and drop the rx'ed CAN frame. So can_rx_offload_offload_one() returned ERR_PTR(-ENOBUFS), too.
[...]
Here is the summary with links: - [net,1/3] can: flexcan: flexcan_mailbox_read() fix return value for drop = true https://git.kernel.org/netdev/net/c/a09721dd47c8 - [net,2/3] can: gs_usb: gs_can_open(): fix race dev->can.state condition https://git.kernel.org/netdev/net/c/5440428b3da6 - [net,3/3] can: gs_usb: gs_usb_set_phys_id(): return with error if identify is not supported https://git.kernel.org/netdev/net/c/0f2211f1cf58
You are awesome, thank you!
linux-stable-mirror@lists.linaro.org