Skip to contentSkip to conversation

Add Loongson CAN-FD controller driver

PATCH Superseded Binbin Zhou 3 participants 6 messages Jul 21 – Jul 24

Subsystems (2)

v6 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v6 cover Add Loongson CAN-FD controller driver

Hi all:

This patchset adds support for the CAN-FD controller found on Loongson CPUs.

Patch 1 introduces the basic CAN-FD controller driver with support for classic CAN and CAN FD, including bit timing, error handling, NAPI-based RX, and multiple TX buffers.

Patch 2 adds optional DMA support for RX path using the Loongson APB CMC DMA engine, which significantly reduces CPU load under high receive throughput.

The driver has been tested on Loongson-2K3000 platforms with various CAN/CAN FD traffic patterns.

Finally, I'd like to thank Bingxiong, the original author of this driver, for his efforts in working on the patch.

Thanks.
Binbin

=========
V6:
- Rebase on linux-can/master;
Patch (1/2):
- Drop CAN_CTRLMODE_3_SAMPLES ctrlmode;
- Replace kfree_skb() with dev_kfree_skb_any();
- Drop REG_CMD_ERCRST operation;
- Rewrite loongson_canfd_tx_interrupt() to prevent duplicate handling of TX completion';
Patch (2/2):
- Added a fallback to true when dmaengine_tx_status() returns an error;
- Replaced all direct regmap_read() from LOONGSON_CANFD_RX_DATA with the priv->get_rx_data() callback;
- Release the DMA channel and clear priv->rx_ch on dma_alloc_coherent() failure;

Link to V5:
https://lore.kernel.org/all/[email protected]/

V5:
Patch (1/2):
- Fix tseg1_max const value;
- Empty FIFO when SKB allocate failed.
- Use REG_FRAME_META1_RWCNT as the playload read count value;
- Only clean processed interrupt flags in loongson_canfd_err_interrupt();
- Refact loongson_canfd_tx_interrupt();
- Add LOONGSON_CANFD_TRV_DLY into loongson_canfd_volatile_reg();
Patch (2/2):
- Fix dma_request_chan() error path;
- Fix build error;
- Fix loongson_canfd_rxdma_init() error path;

Link to V4:
https://lore.kernel.org/all/[email protected]/

V4:
- Fix some issues from sashiko.
Patch (1/2):
- Update commit message;
- Use common APIs to calculate DLC;
- Correct CAN_RTR_FLAG judgement;
- Add skb check for CAN_STATE_ERROR_ACTIVE case;
- Use regmap_write() rather than regmap_update_bits() to disable all interrupts;
- Add napi_disable() in error paths;
- Add clock-frequency return value check;
- More comments for macros.

Link to V3:
https://lore.kernel.org/all/[email protected]/

V3:
Patch (1/2):
- Replace the switch-case statement with a calculated mask in loongson_canfd_get_txbuf_sts();
- Change loongson_canfd_reset() return type to void;
- Drop old code in loongson_canfd_set_btr();
- Rename loongson_canfd_set_mode() to loongson_canfd_set_conf_mode();
- Drop cf->__res* usage;
- Drop unnecessary macro definitions;
- Add netif_napi_del() in probe error route path;
- Replace ternary operator with if-else;
- Drop stats->rx_packets and stats->rx_bytes count in CAN error frames;
- Add ethtool_ops;
- Add CAN_CTRLMODE_CC_LEN8_DLC;

Patch (2/2):
- Fix W=2 warning;
- Rename get_rx_frc() -> get_rxbuf_empty();
- Put loongson_canfd_rxdma_remove() before free_candev();
- Adjust the RXDMA probe process.

Link to V2:
https://lore.kernel.org/all/[email protected]/

V2:
Patch (1/2):
- Put all code into one file;
- Add COMPILE_TEST Kconfig option;
- Rewrite Kconfig description;
- Use regmap_test_bits() to simplify bit field checks;
- Drop odd FIELD_GET() usage;
- Don't use FIELD_GET() for a single bit;
- Use an if/else instead of the ternary operator;
- Use the CAN TDC framework to get the SSP value;
- Use guard(spinlock)/scoped_guard(spinlock);
- Use netdev_debug() to be less verboss;
- Check for memory allocation failure;
- Add CAN_ERR_CNT flag;
- Drop unused REG_DATA_xx_yy_W_DATA_yy definition;
- Add more function comment;

Link to V1:
https://lore.kernel.org/all/[email protected]/

Binbin Zhou (2):
can: Add Loongson CAN-FD controller driver
can: loongson_canfd: Add RXDMA support

 MAINTAINERS                      |    7 +
 drivers/net/can/Kconfig          |   11 +
 drivers/net/can/Makefile         |    1 +
 drivers/net/can/loongson_canfd.c | 1877 ++++++++++++++++++++++++++++++
 4 files changed, 1896 insertions(+)
 create mode 100644 drivers/net/can/loongson_canfd.c

base-commit: 1cb8553c02e93e5a150cebd42f9ee3db0ece4707

Signature · 1 line
2.52.0
#1 lore raw

PATCH v6 1/2 can: Add Loongson CAN-FD controller driver

Add a new driver for the Loongson CAN-FD controller, which is integrated into Loongson-2K series SoCs. The controller supports both CAN 2.0 and CAN-FD protocols, with up to 8 TX buffers and a flexible RX buffer.

The driver implements the core CAN device operations:
- NAPI-based receive path with interrupt masking to reduce overhead;
- TX echo support for accurate loopback and echo skb handling;
- Error reporting (warning, passive, bus-off) with detailed status;
- Support for common CAN controller modes: loopback, listen-only, one-shot, FD, and non-ISO FD;
- Auto TDC (Transmitter Delay Compensation) for FD data phase.

---
 MAINTAINERS                      |    7 +
 drivers/net/can/Kconfig          |   11 +
 drivers/net/can/Makefile         |    1 +
 drivers/net/can/loongson_canfd.c | 1687 ++++++++++++++++++++++++++++++
 4 files changed, 1706 insertions(+)
 create mode 100644 drivers/net/can/loongson_canfd.c
MAINTAINERS +7 -0
index f37a81950e25..6b39c880a05a 100644
@@ -15193,6 +15193,13 @@ F:	Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
 F:	sound/soc/loongson/loongson_*.c
 F:	sound/soc/loongson/loongson_*.h
 
+LOONGSON CAN FD DRIVER
+M:	Bingxiong Li <[email protected]>
+M:	Binbin Zhou <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/net/can/loongson_canfd/
+
 LOONGSON GPIO DRIVER
 M:	Yinbo Zhu <[email protected]>
 L:	[email protected]
drivers/net/can/Kconfig +11 -0
index a8fad6fe5302..95a0f898959c 100644
@@ -186,6 +186,17 @@ config CAN_KVASER_PCIEFD
 	    Kvaser M.2 PCIe 4xCAN
 	    Kvaser PCIe 8xCAN
 
+config CAN_LOONGSON_CANFD
+	tristate "Loongson CAN-FD controller"
+	depends on HAS_IOMEM
+	select REGMAP_MMIO
+	help
+	  This is a canfd driver switch for the Loongson platform,
+	  integrated with the Loongson-2K series SoCs.
+
+	  To compile as a module, choose M here: the module will be
+	  called loongson_canfd.
+
 config CAN_SLCAN
 	tristate "Serial / USB serial CAN Adaptors (slcan)"
 	depends on TTY
drivers/net/can/Makefile +1 -0
index 4010d17f8583..c4eae4595ce3 100644
@@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_GRCAN)		+= grcan.o
 obj-$(CONFIG_CAN_IFI_CANFD)	+= ifi_canfd/
 obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
 obj-$(CONFIG_CAN_KVASER_PCIEFD)	+= kvaser_pciefd/
+obj-$(CONFIG_CAN_LOONGSON_CANFD)	+= loongson_canfd.o
 obj-$(CONFIG_CAN_MSCAN)		+= mscan/
 obj-$(CONFIG_CAN_M_CAN)		+= m_can/
 obj-$(CONFIG_CAN_PEAK_PCIEFD)	+= peak_canfd/
drivers/net/can/loongson_canfd.c new file +1687 -0

1,687 lines not on this page · raw message

Signature · 1 line
2.52.0
#2 lore raw

Re: [PATCH v6 1/2] can: Add Loongson CAN-FD controller driver

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider: - [High] Integer underflow and missing bounds check in the RX path allows out-of-bounds heap writes.…

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Integer underflow and missing bounds check in the RX path allows out-of-bounds heap writes.
- [High] NAPI poll routine violates NAPI protocol on early exit, stranding the polling state machine.
- [High] Clearing the TX interrupt status after checking TX buffers causes a TOCTOU race condition that permanently loses completions.
- [High] Unhandled hardware interrupts and missing status clears trap the driver in an infinite ISR loop.
- [Medium] loongson_canfd_start_xmit silently drops packets instead of returning NETDEV_TX_BUSY when buffers are transiently unready.
- [Medium] Data race on ndev->stats.rx_errors due to concurrent modification from hardirq and softirq contexts.
- [Low] Useless processed_mask check in loongson_canfd_tx_interrupt.
--

--- Patch [1]: [PATCH v6 1/2] can: Add Loongson CAN-FD controller driver --- commit 5f440f327c688c271e3208983fc49fe2d7c3dd2d
Author: Binbin Zhou <[email protected]>

can: Add Loongson CAN-FD controller driver

Add a new driver for the Loongson CAN-FD controller, which is integrated into Loongson-2K series SoCs. The controller supports both CAN 2.0 and CAN-FD protocols, with up to 8 TX buffers and a flexible RX buffer.

Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +0 -0
new file mode 100644
index 0000000000000..211133258b083

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static netdev_tx_t loongson_canfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{

[ ... ]

Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5 -0
+	for_each_clear_bit(i, &tx_brp, LOONGSON_CANFD_TXBUF_NUM) {
+		u32 transmission_complete_mask = 0x3 << (i * 2);
+
+		if (!(tx_bs & transmission_complete_mask)) {
+			buf_id = i;

drivers/net/can/loongson_canfd.c line 925

Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10 -0
+			break;
+		}
+	}
+
+	if (!loongson_canfd_insert_frame(priv, cf, buf_id, can_is_canfd_skb(skb))) {
+		netdev_err(ndev, "TXNF set but cannot insert frame into TXTB! HW Bug?");
+		dev_kfree_skb_any(skb);
+		ndev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}

[Severity: Medium]
Is it correct to drop the packet and return NETDEV_TX_OK here?

If the loop falls through because all buffers have active tx_bs states, buf_id remains 0. Insertion will then fail. Should this instead stop the queue and return NETDEV_TX_BUSY to avoid dropping packets during transient buffer states?

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static int loongson_canfd_rx(struct net_device *ndev)
+{

[ ... ]

drivers/net/can/loongson_canfd.c line 965

Quoted 8 lines
drivers/net/can/loongson_canfd.c new file +8 -0
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta0);
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta1);
+
+	/* Number of characters received */
+	rwcnt = FIELD_GET(REG_FRAME_META1_RWCNT, meta1);
+	if (!rwcnt)
+		return -EAGAIN;
+	dbcnt = (rwcnt - 2) * LOONGSON_CANFD_DW_BYTE;

[Severity: High]
Can this result in an integer underflow if rwcnt is 1?

It appears dbcnt operates without a bounds check against the SKB allocation size. If the hardware provides rwcnt < 2, dbcnt could underflow to a huge 32-bit integer, leading to a buffer overflow when writing data to cfd->data.

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static void loongson_canfd_err_interrupt(struct net_device *ndev, u32 isr)
+{

[ ... ]

drivers/net/can/loongson_canfd.c line 1207

Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6 -0
+	/* Check for Bus Error interrupt */
+	if (isr & REG_INT_STAT_BEI) {
+		mask |= REG_INT_STAT_BEI;
+		netdev_err(ndev, "Bus Error interrupt\n");
+		priv->can.can_stats.bus_error++;
+		stats->rx_errors++;

[Severity: Medium]
Could this cause a data race on ndev->stats.rx_errors?

This is executed in hardirq context, while the same counter is also incremented in softirq context in loongson_canfd_rx_napi(). Non-atomic increments across these contexts might lead to torn updates or lost counts.

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
+{

[ ... ]

Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5 -0
+	while (!rxbuf_is_empty && work_done < quota && ret != -EAGAIN) {
+		ret = loongson_canfd_rx(ndev);
+		work_done++;
+		rxbuf_is_empty = loongson_canfd_rxbuf_empty(priv);
+	}

[ ... ]

drivers/net/can/loongson_canfd.c line 1261

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+	if (rxbuf_is_empty) {
+		if (napi_complete_done(napi, work_done)) {

[Severity: High]
What happens if the while loop exits early due to ret == -EAGAIN but rxbuf_is_empty is false?

This skips napi_complete_done() even though work_done < quota, which leaves the NAPI state stuck in NAPI_STATE_SCHED but off the poll list, potentially stalling the RX path permanently.

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static void loongson_canfd_tx_interrupt(struct net_device *ndev)
+{

[ ... ]

drivers/net/can/loongson_canfd.c line 1291

Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3 -0
+	for (buf_id = 0; buf_id < LOONGSON_CANFD_TXBUF_NUM; buf_id++) {
+		if (processed_mask & BIT(buf_id))
+			continue;

[Severity: Low]
Is this processed_mask check needed?

Since buf_id strictly increments from 0 to 7 in this loop, the bit for the current buf_id will always be clear when evaluated.

[ ... ]

drivers/net/can/loongson_canfd.c line 1343

Quoted 8 lines
drivers/net/can/loongson_canfd.c new file +8 -0
+	if (processed_mask) {
+		/*
+		 * Clear the interrupt again. We do not want to receive again interrupt
+		 * for the buffer already handled. If it is the last finished one then
+		 * it would cause log of spurious interrupt.
+		 */
+		regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, REG_INT_STAT_TXBHCI);
+	}

[Severity: High]
Could clearing the TX interrupt status at the end of the loop cause a race condition?

If a different TX buffer completes transmission after it was checked by the loop but before the REG_INT_STAT_TXBHCI bit is cleared, the software clear might wipe out the new hardware assertion, permanently losing the completion for that buffer.

[ ... ]

Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2 -0
+static irqreturn_t loongson_canfd_interrupt(int irq, void *dev_id)
+{

[ ... ]

drivers/net/can/loongson_canfd.c line 1369

Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3 -0
+	for (unsigned int irq_loops = 0; irq_loops < 10000; irq_loops++) {
+		/* Get the interrupt status */
+		regmap_read(priv->regmap, LOONGSON_CANFD_INT_STAT, &isr);

[Severity: High]
Is there a risk of an endless loop here?

If the hardware asserts an unhandled interrupt bit (like DOI or BSI), or if TXBHCI is set but skipped because processed_mask == 0 in the TX handler, the bit will remain set in INT_STAT. The loop will spin 10,000 times, and then loongson_canfd_disable_interrupts() will permanently kill the interface.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

PATCH v6 2/2 can: loongson_canfd: Add RXDMA support

In reply to Binbin Zhou

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.

The DMA mode is completely transparent to the under networking stack; the driver automatically selects the appropriate RX data reading method based on the availability of the DMA channel.

---
 drivers/net/can/Kconfig          |   2 +-
 drivers/net/can/loongson_canfd.c | 232 ++++++++++++++++++++++++++++---
 2 files changed, 212 insertions(+), 22 deletions(-)
drivers/net/can/Kconfig +1 -1
index 95a0f898959c..07a51aed54d0 100644
@@ -188,7 +188,7 @@ config CAN_KVASER_PCIEFD
 
 config CAN_LOONGSON_CANFD
 	tristate "Loongson CAN-FD controller"
-	depends on HAS_IOMEM
+	depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)
 	select REGMAP_MMIO
 	help
 	  This is a canfd driver switch for the Loongson platform,
drivers/net/can/loongson_canfd.c +211 -21

364 lines not on this page · raw message

Signature · 1 line
2.52.0
#4 lore raw

Re: [PATCH v6 2/2] can: loongson_canfd: Add RXDMA support

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

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 <[email protected]>

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.

Quoted 4 lines
drivers/net/can/loongson_canfd.c +0 -0
index 211133258b083..d32c834a11264 100644

[ ... ]

drivers/net/can/loongson_canfd.c static void loongson_canfd_set_txbuf_cmd(struct net_device *ndev, · line 550

Quoted 11 lines
drivers/net/can/loongson_canfd.c +10 -0
@@ -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.

Quoted 8 lines
drivers/net/can/loongson_canfd.c +8 -0
+}
+
+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);

drivers/net/can/loongson_canfd.c static void loongson_canfd_set_txbuf_cmd(struct net_device *ndev, · line 594

Quoted 10 lines
drivers/net/can/loongson_canfd.c +10 -0
+	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.

[ ... ]

Quoted 18 lines
drivers/net/can/loongson_canfd.c +3 -3
@@ -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);

drivers/net/can/loongson_canfd.c

Quoted 3 lines
drivers/net/can/loongson_canfd.c +0 -0
 	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.

[ ... ]

drivers/net/can/loongson_canfd.c static int loongson_canfd_rx(struct net_device *ndev) · line 1171

Quoted 6 lines
drivers/net/can/loongson_canfd.c +1 -1
@@ -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?

[ ... ]

Quoted 10 lines
drivers/net/can/loongson_canfd.c +2 -1
@@ -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.
 			 */

drivers/net/can/loongson_canfd.c static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota) · line 1433

Quoted 10 lines
drivers/net/can/loongson_canfd.c +7 -3
-			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.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
maintainer Reviewed-by on the v6 series
#5 lore raw
In reply to Binbin Zhou

For the whole series:

Quoted 135 lines · Binbin Zhou

Hi all:

This patchset adds support for the CAN-FD controller found on Loongson CPUs.

Patch 1 introduces the basic CAN-FD controller driver with support for classic CAN and CAN FD, including bit timing, error handling, NAPI-based RX, and multiple TX buffers.

Patch 2 adds optional DMA support for RX path using the Loongson APB CMC DMA engine, which significantly reduces CPU load under high receive throughput.

The driver has been tested on Loongson-2K3000 platforms with various CAN/CAN FD traffic patterns.

Finally, I'd like to thank Bingxiong, the original author of this driver, for his efforts in working on the patch.

Thanks.
Binbin

=========
V6:
- Rebase on linux-can/master;
Patch (1/2):
- Drop CAN_CTRLMODE_3_SAMPLES ctrlmode;
- Replace kfree_skb() with dev_kfree_skb_any();
- Drop REG_CMD_ERCRST operation;
- Rewrite loongson_canfd_tx_interrupt() to prevent duplicate handling of TX completion';
Patch (2/2):
- Added a fallback to true when dmaengine_tx_status() returns an error;
- Replaced all direct regmap_read() from LOONGSON_CANFD_RX_DATA with the priv->get_rx_data() callback;
- Release the DMA channel and clear priv->rx_ch on dma_alloc_coherent() failure;

Link to V5:
https://lore.kernel.org/all/[email protected]/

V5:
Patch (1/2):
- Fix tseg1_max const value;
- Empty FIFO when SKB allocate failed.
- Use REG_FRAME_META1_RWCNT as the playload read count value;
- Only clean processed interrupt flags in loongson_canfd_err_interrupt();
- Refact loongson_canfd_tx_interrupt();
- Add LOONGSON_CANFD_TRV_DLY into loongson_canfd_volatile_reg();
Patch (2/2):
- Fix dma_request_chan() error path;
- Fix build error;
- Fix loongson_canfd_rxdma_init() error path;

Link to V4:
https://lore.kernel.org/all/[email protected]/

V4:
- Fix some issues from sashiko.
Patch (1/2):
- Update commit message;
- Use common APIs to calculate DLC;
- Correct CAN_RTR_FLAG judgement;
- Add skb check for CAN_STATE_ERROR_ACTIVE case;
- Use regmap_write() rather than regmap_update_bits() to disable all interrupts;
- Add napi_disable() in error paths;
- Add clock-frequency return value check;
- More comments for macros.

Link to V3:
https://lore.kernel.org/all/[email protected]/

V3:
Patch (1/2):
- Replace the switch-case statement with a calculated mask in loongson_canfd_get_txbuf_sts();
- Change loongson_canfd_reset() return type to void;
- Drop old code in loongson_canfd_set_btr();
- Rename loongson_canfd_set_mode() to loongson_canfd_set_conf_mode();
- Drop cf->__res* usage;
- Drop unnecessary macro definitions;
- Add netif_napi_del() in probe error route path;
- Replace ternary operator with if-else;
- Drop stats->rx_packets and stats->rx_bytes count in CAN error frames;
- Add ethtool_ops;
- Add CAN_CTRLMODE_CC_LEN8_DLC;

Patch (2/2):
- Fix W=2 warning;
- Rename get_rx_frc() -> get_rxbuf_empty();
- Put loongson_canfd_rxdma_remove() before free_candev();
- Adjust the RXDMA probe process.

Link to V2:
https://lore.kernel.org/all/[email protected]/

V2:
Patch (1/2):
- Put all code into one file;
- Add COMPILE_TEST Kconfig option;
- Rewrite Kconfig description;
- Use regmap_test_bits() to simplify bit field checks;
- Drop odd FIELD_GET() usage;
- Don't use FIELD_GET() for a single bit;
- Use an if/else instead of the ternary operator;
- Use the CAN TDC framework to get the SSP value;
- Use guard(spinlock)/scoped_guard(spinlock);
- Use netdev_debug() to be less verboss;
- Check for memory allocation failure;
- Add CAN_ERR_CNT flag;
- Drop unused REG_DATA_xx_yy_W_DATA_yy definition;
- Add more function comment;

Link to V1:
https://lore.kernel.org/all/[email protected]/

Binbin Zhou (2):
can: Add Loongson CAN-FD controller driver
can: loongson_canfd: Add RXDMA support

 MAINTAINERS                      |    7 +
 drivers/net/can/Kconfig          |   11 +
 drivers/net/can/Makefile         |    1 +
 drivers/net/can/loongson_canfd.c | 1877 ++++++++++++++++++++++++++++++
 4 files changed, 1896 insertions(+)
 create mode 100644 drivers/net/can/loongson_canfd.c

base-commit: 1cb8553c02e93e5a150cebd42f9ee3db0ece4707 --
2.52.0