Linux CAN drivers development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Binbin Zhou" <zhoubinbin@loongson.cn>
Cc: "Oliver Hartkopp" <socketcan@hartkopp.net>,
	"Vincent Mailhol" <mailhol@kernel.org>,
	linux-can@vger.kernel.org,
	"Marc Kleine-Budde" <mkl@pengutronix.de>,
	"Oleksij Rempel" <o.rempel@pengutronix.de>
Subject: Re: [PATCH v6 2/2] can: loongson_canfd: Add RXDMA support
Date: Tue, 21 Jul 2026 11:56:39 +0000	[thread overview]
Message-ID: <20260721115640.710E51F000E9@smtp.kernel.org> (raw)
In-Reply-To: <0a0b43993195b2199df538d9386c4b0022cfbd99.1784597142.git.zhoubinbin@loongson.cn>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Critical] NAPI reads ahead of the DMA write pointer, leading to stale data reads and permanent ring buffer desynchronization.
- [High] The DMA receive buffer is freed before the DMA engine is terminated, causing hardware writes to freed memory.
- [High] Clearing the DMADI interrupt status at the end of NAPI causes lost wakeups for newly arrived frames.

Pre-existing issues:
- [Critical] Missing bounds check and integer underflow on `rwcnt` leads to a massive kernel heap buffer overflow.
--

--- Patch [2]: [PATCH v6 2/2] can: loongson_canfd: Add RXDMA support ---
commit e9fb5c097416d3376c7ac83b960fa3ca5f984b78
Author: Binbin Zhou <zhoubinbin@loongson.cn>

can: loongson_canfd: Add RXDMA support
    
Extend the driver with an optional DMA engine support for the receive
path. When a DMA channel named rx is available (e.g., from the
loongson2-apb-cmc-dma driver), the RX buffer is mapped to a cyclic DMA
transfer that continuously fills a pre-allocated ring buffer. The driver
then readds incoming CAN frames directly from the DMA buffer, reducing
the number of MMIO accesses and improving performance under high
traffic.

> diff --git a/drivers/net/can/loongson_canfd.c b/drivers/net/can/loongson_canfd.c
> index 211133258b083..d32c834a11264 100644
> --- a/drivers/net/can/loongson_canfd.c
> +++ b/drivers/net/can/loongson_canfd.c

[ ... ]

> @@ -521,13 +541,150 @@ static void loongson_canfd_set_txbuf_cmd(struct net_device *ndev,
> +static bool loongson_canfd_get_rxbuf_empty_in_dma(struct loongson_canfd_priv *priv)
> +{
> +	struct dma_tx_state state;
> +	enum dma_status status;
> +
> +	status = dmaengine_tx_status(priv->rx_ch, priv->rx_cookie, &state);
> +	if (status != DMA_IN_PROGRESS)
> +		return true;
> +
> +	return priv->last_res == (state.residue / DMA_SLAVE_BUSWIDTH_4_BYTES);

[Severity: Critical]
Will this residue check allow NAPI to read ahead of the DMA write pointer?

Since the residue changes as soon as a single word is written, the CPU will
detect data is ready before a complete frame has been transferred. When
loongson_canfd_rx() is called, it will decrement priv->last_res to
unconditionally read multiple words (meta0, meta1, and payload), which might
result in fetching unwritten or stale memory for length fields and payload.

> +}
> +
> +static void loongson_canfd_rxdma_free(struct loongson_canfd_priv *priv, struct device *dev)
> +{
> +	if (!priv->rx_buf)
> +		return;
> +
> +	dma_free_coherent(dev, LOONGSON_CANFD_RXBUF_SZ, priv->rx_buf, priv->rx_dma_buf);
> +	priv->rx_buf = NULL;
> +}
> +
> +static void loongson_canfd_rxdma_remove(struct loongson_canfd_priv *priv, struct device *dev)
> +{
> +	if (!priv->rx_ch)
> +		return;
> +
> +	loongson_canfd_rxdma_free(priv, dev);
> +	dmaengine_terminate_sync(priv->rx_ch);

[Severity: High]
Does this free the DMA buffer while the cyclic DMA channel is still active?

Calling loongson_canfd_rxdma_free() before dmaengine_terminate_sync() could
allow the DMA controller to continue writing to pages that have been freed
and potentially reallocated to other kernel structures, which might cause
memory corruption during module unload or if probe fails.

[ ... ]

> @@ -949,14 +1109,14 @@ static int loongson_canfd_rx(struct net_device *ndev)
>  {
>  	struct loongson_canfd_priv *priv = netdev_priv(ndev);
>  	struct net_device_stats *stats = &ndev->stats;
> -	u32 meta0, meta1, dlc, rwcnt, dbcnt, i, data;
> +	u32 meta0, meta1, dlc, rwcnt, dbcnt, i;
>  	struct canfd_frame *cfd;
>  	struct can_frame *ccf;
>  	struct sk_buff *skb;
>  	bool is_can_fd;
>  
> -	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta0);
> -	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta1);
> +	meta0 = priv->get_rx_data(priv);
> +	meta1 = priv->get_rx_data(priv);
>  
>  	/* Number of characters received */
>  	rwcnt = FIELD_GET(REG_FRAME_META1_RWCNT, meta1);
>  	if (!rwcnt)
>  		return -EAGAIN;
>  	dbcnt = (rwcnt - 2) * LOONGSON_CANFD_DW_BYTE;

[Severity: Critical]
This is a pre-existing issue, but does this calculation need bounds checking
or underflow protection?

If rwcnt is parsed from stale memory as 1 (which might happen due to the DMA
read-ahead behavior mentioned above), rwcnt - 2 will underflow, resulting in
a very large dbcnt.

[ ... ]

> @@ -1008,11 +1168,11 @@ static int loongson_canfd_rx(struct net_device *ndev)
>  
>  	/* Copy payload */
>  	for (i = 0; i < dbcnt; i += LOONGSON_CANFD_DW_BYTE)
> -		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, (u32 *)(cfd->data + i));
> +		*(u32 *)(cfd->data + i) = priv->get_rx_data(priv);

[Severity: Critical]
This is also a pre-existing issue, but if dbcnt is huge due to the integer
underflow mentioned above, will this loop cause a heap buffer overflow by
copying gigabytes of data into cfd->data?

[ ... ]

> @@ -1259,13 +1419,18 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
>  
>  	if (rxbuf_is_empty) {
>  		if (napi_complete_done(napi, work_done)) {
> +			int int_ena;
>  			/*
> -			 * Clear and enable RBNEI. It is level-triggered,
> +			 * Clear and enable RBNEI/DMADI. It is level-triggered, so
>  			 * so there is no race condition.
>  			 */
> -			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, REG_INT_STAT_RBNEI);
> -			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK,
> -				     (REG_INT_STAT_RBNEI << 16));
> +			if (priv->rx_ch)
> +				int_ena = REG_INT_STAT_DMADI;
> +			else
> +				int_ena = REG_INT_STAT_RBNEI;
> +
> +			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, int_ena);
> +			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, (int_ena << 16));

[Severity: High]
Does unconditionally clearing the DMADI interrupt flag here cause a lost
wakeup?

If a frame finishes its DMA transfer after the rxbuf_is_empty check but
before this write to LOONGSON_CANFD_INT_STAT, the hardware sets the DMADI
flag, which will then be cleared immediately. Because it is cleared before
unmasking, the interrupt for the new frame could be lost, potentially
stalling incoming CAN frames.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1784597141.git.zhoubinbin@loongson.cn?part=2

      reply	other threads:[~2026-07-21 11:56 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-21 11:44 [PATCH v6 0/2] Add Loongson CAN-FD controller driver Binbin Zhou
2026-07-21 11:44 ` [PATCH v6 1/2] can: " Binbin Zhou
2026-07-21 11:56   ` sashiko-bot
2026-07-21 11:44 ` [PATCH v6 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
2026-07-21 11:56   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260721115640.710E51F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-can@vger.kernel.org \
    --cc=mailhol@kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=o.rempel@pengutronix.de \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=socketcan@hartkopp.net \
    --cc=zhoubinbin@loongson.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox