Re: [PATCH v3 2/3] can: rockchip_canfd: retry the outstanding TX buffer

[email protected] Thu, 30 Jul 2026 14:05:14 +0000
Newsgroups org.kernel.vger.linux-can
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(=
s) to consider:

Pre-existing issues:
- [High] Concurrent MMIO accesses to RKCANFD_REG_MODE from softirq and hard=
irq contexts without locking defeat the Erratum 12 workaround.
- [High] Lockless update of `tx_head` lacks memory barriers, risking a NULL=
 pointer dereference when the RX IRQ handler reads `echo_skb`.
--

--- Patch [2]: [PATCH v3 2/3] can: rockchip_canfd: retry the outstanding TX=
 buffer ---
commit c91fe3adb2c3d0a63ee8904bebefd12fa1335d29
Author: Cunhao Lu <[email protected]>

can: rockchip_canfd: retry the outstanding TX buffer

This patch modifies rkcanfd_xmit_retry to use tx_tail instead of tx_head
to select the outstanding buffer for retransmission. This corrects an issue
introduced when the TX FIFO depth was increased to two.

> diff --git a/drivers/net/can/rockchip/rockchip_canfd-tx.c b/drivers/net/c=
an/rockchip/rockchip_canfd-tx.c
> index b1954b72560cf..2b5cd6aab31b6 100644
> --- a/drivers/net/can/rockchip/rockchip_canfd-tx.c
> +++ b/drivers/net/can/rockchip/rockchip_canfd-tx.c
> @@ -57,8 +57,8 @@ static void rkcanfd_start_xmit_write_cmd(const struct r=
kcanfd_priv *priv,
> =20
>  void rkcanfd_xmit_retry(struct rkcanfd_priv *priv)
>  {
> -	const unsigned int tx_head =3D rkcanfd_get_tx_head(priv);
> -	const u32 reg_cmd =3D RKCANFD_REG_CMD_TX_REQ(tx_head);
> +	const unsigned int tx_tail =3D rkcanfd_get_tx_tail(priv);

[Severity: High]
This is a pre-existing issue, but does the lockless update of tx_head lack
memory barriers, risking a NULL pointer dereference when the RX IRQ handler
reads echo_skb?

In rkcanfd_start_xmit(), the CPU populates priv->can.echo_skb[tx_head]
locklessly via can_put_echo_skb() and then increments tx_head:

	err =3D can_put_echo_skb(skb, ndev, tx_head, frame_len);
	if (err) {
		ndev->stats.tx_dropped++;
		return NETDEV_TX_OK;
	}
	netdev_sent_queue(priv->ndev, frame_len);

	WRITE_ONCE(priv->tx_head, priv->tx_head + 1);

Because there is no memory barrier separating these operations,
weakly-ordered architectures can reorder the store to tx_head to become
visible before the store to echo_skb.

A concurrent hardware interrupt on another CPU executing
rkcanfd_handle_rx_int_one() could read the updated tx_head and attempt to
read echo_skb[tx_tail] in rkcanfd_rxstx_filter():

	tx_tail =3D rkcanfd_get_tx_tail(priv);
	skb =3D priv->can.echo_skb[tx_tail];
	if (!skb) {
		netdev_err(priv->ndev,
			   "%s: echo_skb[%u]=3DNULL tx_head=3D0x%08x tx_tail=3D0x%08x\n",
			   __func__, tx_tail,
			   priv->tx_head, priv->tx_tail);
		return -ENOMSG;

Lacking a paired acquire barrier, it may read a NULL pointer.
This would terminate the RX FIFO processing loop prematurely,
leaving frames in the hardware FIFO. Should there be memory barriers ensuri=
ng
the echo_skb store completes before tx_head is incremented?

> +	const u32 reg_cmd =3D RKCANFD_REG_CMD_TX_REQ(tx_tail);
> =20
>  	rkcanfd_start_xmit_write_cmd(priv, reg_cmd);

[Severity: High]
This isn't a bug introduced by this patch, but does calling
rkcanfd_start_xmit_write_cmd() from both softirq and hardirq contexts
without locking defeat the Erratum 12 workaround?

The rkcanfd_start_xmit() function running in NET_TX_SOFTIRQ context calls
rkcanfd_start_xmit_write_cmd() to execute a non-atomic read-modify-write
sequence on RKCANFD_REG_MODE:

static void rkcanfd_start_xmit_write_cmd(...)
{
	if (priv->devtype_data.quirks & RKCANFD_QUIRK_RK3568_ERRATUM_12)
		rkcanfd_write(priv, RKCANFD_REG_MODE, priv->reg_mode_default |
			      RKCANFD_REG_MODE_SPACE_RX_MODE);

If a hardware interrupt occurs immediately after the softirq sets
RKCANFD_REG_MODE_SPACE_RX_MODE, the hardirq handler rkcanfd_irq() can run.
It can call rkcanfd_xmit_retry(), which also executes
rkcanfd_start_xmit_write_cmd(), restoring RKCANFD_REG_MODE to
priv->reg_mode_default on exit.

When the softirq resumes, it proceeds to write to RKCANFD_REG_CMD but
RKCANFD_REG_MODE is now back in its default state, meaning the required
Erratum 12 workaround is missing. Could this silent bypass cause incorrect
CAN bus behavior or TX stalls?

>  }

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260730-master-v3-=
[email protected]?part=3D2