[PATCH net v8 01/10] can: rockchip_canfd: prevent TX stall on echo skb failure
Cunhao Lu via B4 Relay
devnull+1579567540.qq.com at kernel.org
Sun Nov 8 03:33:28 PST 2026
From: Cunhao Lu <1579567540 at qq.com>
rkcanfd_start_xmit() advances tx_head and requests transmission even when
can_put_echo_skb() fails. Completion matches self-received frames against
the echo ring, so an entry without an echo skb cannot be completed and
can leave the TX queue stopped.
Install the echo skb before writing the hardware TX buffer. If echo
preparation fails or returns success without installing an echo skb,
drop the frame without writing TX data or commands, advancing tx_head
or adding BQL bytes.
Pass an extra reference to can_put_echo_skb() and retain the original skb
as the frame-data source until submission finishes. This keeps the data
alive even if echo cleanup removes the installed clone. Release the
retained reference on both success and failure.
Backports require can_put_echo_skb() to consume the passed reference on
every return path, including -EINVAL, or equivalent ownership handling.
Fixes: b6661d73290c ("can: rockchip_canfd: add TX PATH")
Cc: stable at vger.kernel.org
Signed-off-by: Cunhao Lu <1579567540 at qq.com>
---
Changes in v8:
- Retain the original skb as the frame-data source and release it after
submission or failure.
- Reject successful echo preparation if no echo skb was installed.
---
drivers/net/can/rockchip/rockchip_canfd-tx.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/net/can/rockchip/rockchip_canfd-tx.c b/drivers/net/can/rockchip/rockchip_canfd-tx.c
index 12200dcfd3389..420e59b41059c 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-tx.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-tx.c
@@ -117,16 +117,21 @@ netdev_tx_t rkcanfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tx_head = rkcanfd_get_tx_head(priv);
reg_cmd = RKCANFD_REG_CMD_TX_REQ(tx_head);
+ /* Retain the original skb as the frame-data source even if the
+ * echo skb is removed before submission finishes.
+ */
+ frame_len = can_skb_get_frame_len(skb);
+ err = can_put_echo_skb(skb_get(skb), ndev, tx_head, frame_len);
+ if (unlikely(err || !priv->can.echo_skb[tx_head]))
+ goto out_drop;
+
rkcanfd_write(priv, RKCANFD_REG_FD_TXFRAMEINFO, reg_frameinfo);
rkcanfd_write(priv, RKCANFD_REG_FD_TXID, reg_id);
for (i = 0; i < cfd->len; i += 4)
rkcanfd_write(priv, RKCANFD_REG_FD_TXDATA0 + i,
*(u32 *)(cfd->data + i));
- frame_len = can_skb_get_frame_len(skb);
- err = can_put_echo_skb(skb, ndev, tx_head, frame_len);
- if (!err)
- netdev_sent_queue(priv->ndev, frame_len);
+ netdev_sent_queue(priv->ndev, frame_len);
WRITE_ONCE(priv->tx_head, priv->tx_head + 1);
@@ -137,6 +142,14 @@ netdev_tx_t rkcanfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
RKCANFD_TX_STOP_THRESHOLD,
RKCANFD_TX_START_THRESHOLD);
+ dev_consume_skb_any(skb);
+
+ return NETDEV_TX_OK;
+
+out_drop:
+ ndev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+
return NETDEV_TX_OK;
}
--
2.34.1
More information about the Linux-rockchip
mailing list