All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Add Loongson CAN-FD controller driver
@ 2026-06-08  8:49 Binbin Zhou
  2026-06-08  8:49 ` [PATCH v2 1/2] can: " Binbin Zhou
  2026-06-08  8:49 ` [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
  0 siblings, 2 replies; 4+ messages in thread
From: Binbin Zhou @ 2026-06-08  8:49 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Marc Kleine-Budde, Vincent Mailhol,
	Bingxiong Li
  Cc: Huacai Chen, Xuerui Wang, loongarch, linux-can, jeffbai,
	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 Binxiong, the original author of this driver,
for his efforts in working on the patch.

Thanks.
Binbin

-------
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/cover.1777273055.git.zhoubinbin@loongson.cn/

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

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


base-commit: f1359c240191e686614847905fc861cbda480b47
-- 
2.52.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] can: Add Loongson CAN-FD controller driver
  2026-06-08  8:49 [PATCH v2 0/2] Add Loongson CAN-FD controller driver Binbin Zhou
@ 2026-06-08  8:49 ` Binbin Zhou
  2026-06-08  8:49 ` [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
  1 sibling, 0 replies; 4+ messages in thread
From: Binbin Zhou @ 2026-06-08  8:49 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Marc Kleine-Budde, Vincent Mailhol,
	Bingxiong Li
  Cc: Huacai Chen, Xuerui Wang, loongarch, linux-can, jeffbai,
	Binbin Zhou

Add support for the CAN-FD controller integrated into Loongson-2K series
SoCs. The controller supports both Classic CAN and CAN FD, with up to 8
transmit buffers, hardware timestamping, error counters, and various
control modes (loopback, listen-only, one-shot, non-ISO FD, etc.).

The driver implements:
- NAPI for RX path
- TX buffer management with echo skb support
- Bus error reporting and fault confinement state handling
- Bit timing configuration for nominal and data phase
- Secondary Sample Point (SSP) configuration for high bitrates

Co-developed-by: Bingxiong Li <libingxiong@loongson.cn>
Signed-off-by: Bingxiong Li <libingxiong@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 MAINTAINERS                      |    7 +
 drivers/net/can/Kconfig          |   15 +
 drivers/net/can/Makefile         |    1 +
 drivers/net/can/loongson_canfd.c | 1766 ++++++++++++++++++++++++++++++
 4 files changed, 1789 insertions(+)
 create mode 100644 drivers/net/can/loongson_canfd.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7a2ffd9d37d5..1ee16edae734 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14935,6 +14935,13 @@ F:	arch/loongarch/
 F:	drivers/*/*loongarch*
 F:	drivers/cpufreq/loongson3_cpufreq.c
 
+LOONGSON CAN FD DRIVER
+M:	Bingxiong Li <libingxiong@loongson.cn>
+M:	Binbin Zhou <zhoubinbin@loongson.cn>
+L:	linux-can@vger.kernel.org
+S:	Maintained
+F:	drivers/net/can/loongson_canfd.c
+
 LOONGSON GPIO DRIVER
 M:	Yinbo Zhu <zhuyinbo@loongson.cn>
 L:	linux-gpio@vger.kernel.org
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index e15e320db476..28014e264f30 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -189,6 +189,21 @@ 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 || COMPILE_TEST
+	select REGMAP_MMIO
+	help
+	  This is a canfd driver switch for the Loongson platform,
+	  integrated with the Loongson-2K series SoCs.
+
+	  It supports both Classic CAN and CAN FD, with up to 8 transmit
+	  buffers, hardware timestamping, error counters, and various
+	  control modes.
+
+	  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
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index d7bc10a6b8ea..1ce78443d710 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -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/
diff --git a/drivers/net/can/loongson_canfd.c b/drivers/net/can/loongson_canfd.c
new file mode 100644
index 000000000000..3794700e04c8
--- /dev/null
+++ b/drivers/net/can/loongson_canfd.c
@@ -0,0 +1,1766 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LOONGSON CANFD controller
+ *
+ * Copyright (C) 2024-2026 Loongson Technology Corporation Limited
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define LOONGSON_CANFD_DEVICE_ID	0x0	/* CANFD controller ID Register */
+#define LOONGSON_CANFD_MODE		0x4	/* Mode Configuration Register */
+#define LOONGSON_CANFD_CONF		0x8	/* Configure Register */
+#define LOONGSON_CANFD_STAT		0xc	/* Status Register */
+#define LOONGSON_CANFD_CMD		0x10	/* Command Register */
+#define LOONGSON_CANFD_INT_STAT		0x14	/* Interrupt Status Register */
+#define LOONGSON_CANFD_INT_ENA		0x18	/* Interrupt Enable Register */
+#define LOONGSON_CANFD_INT_MASK		0x1c	/* Interrupt Mask Register */
+#define LOONGSON_CANFD_BTR_NORM		0x20	/* Normal Rate Configuration Register */
+#define LOONGSON_CANFD_BTR_FD		0x24	/* FD Data Rate Configuration Register */
+#define LOONGSON_CANFD_ERL		0x28	/* Error Threshold Configuration Register */
+#define LOONGSON_CANFD_FSTAT		0x2c	/* Error Status Register */
+#define LOONGSON_CANFD_ERC		0x30	/* Error Count Register */
+#define LOONGSON_CANFD_BRE		0x34	/* Rate Error Count Register */
+#define LOONGSON_CANFD_CTR_PRES		0x38	/* Error Count Debug Register */
+#define LOONGSON_CANFD_ERR_CAPT		0x3c	/* Error Capture Status Register */
+#define LOONGSON_CANFD_RETX_CNT		0x40	/* Retransmission Count Register */
+#define LOONGSON_CANFD_ALC		0x44	/* Lost Arbitration Capture Register */
+#define LOONGSON_CANFD_TRV_DLY		0x48	/* Transmission Delay Measurement Register */
+#define LOONGSON_CANFD_SSP_CFG		0x4c	/* Second Sampling Point Configuration Register */
+#define LOONGSON_CANFD_RX_FR_CNT	0x50	/* Receive Message Count Register */
+#define LOONGSON_CANFD_TX_FR_CNT	0x54	/* Transmit Message Count Register */
+#define LOONGSON_CANFD_DEBUG		0x58	/* Debug Register */
+#define LOONGSON_CANFD_TS		0x5c	/* Timestamp Register */
+#define LOONGSON_CANFD_TX_FRM_TST	0x60	/* Transmit Message Debug Register */
+#define LOONGSON_CANFD_FRC_DIV		0x64	/* Fractional Divider Ratio Register */
+#define LOONGSON_CANFD_FLT_A_MASK	0x68	/* Filter A Mask Register */
+#define LOONGSON_CANFD_FLT_A_VAL	0x6c	/* Filter A value Register */
+#define LOONGSON_CANFD_FLT_B_MASK	0x70	/* Filter B Mask Register */
+#define LOONGSON_CANFD_FLT_B_VAL	0x74	/* Filter B value Register */
+#define LOONGSON_CANFD_FLT_C_MASK	0x78	/* Filter C Mask Register */
+#define LOONGSON_CANFD_FLT_C_VAL	0x7c	/* Filter C value Register */
+#define LOONGSON_CANFD_FLT_R_LOW	0x80	/* Range Filter Low Threshold Register */
+#define LOONGSON_CANFD_FLT_R_HI		0x84	/* Range Filter High Threshold Register */
+#define LOONGSON_CANFD_FLT_CTRL		0x88	/* Filter Control Register */
+#define LOONGSON_CANFD_RX_MEM_INFO	0x8c	/* Receive Buffer Information Register */
+#define LOONGSON_CANFD_RX_PRT		0x90	/* Receive Buffer Pointer Register */
+#define LOONGSON_CANFD_RX_STAT		0x94	/* Receive Buffer Status Register */
+#define LOONGSON_CANFD_RX_DATA		0x98	/* Receive Data Register */
+#define LOONGSON_CANFD_TX_STAT		0x9c	/* Transmit Buffer Status Register */
+#define LOONGSON_CANFD_TX_CMD		0xa0	/* Transmit Command Register */
+#define LOONGSON_CANFD_TX_SEL		0xa4	/* Transmit Buffer Selection Register */
+#define LOONGSON_CANFD_TX_DATA_1	0xb0
+#define LOONGSON_CANFD_TX_DATA_2	0xb4
+#define LOONGSON_CANFD_TX_DATA_3	0xb8
+#define LOONGSON_CANFD_TX_DATA_4	0xbc
+#define LOONGSON_CANFD_TX_DATA_5	0xc0
+#define LOONGSON_CANFD_TX_DATA_6	0xc4
+#define LOONGSON_CANFD_TX_DATA_7	0xc8
+#define LOONGSON_CANFD_TX_DATA_8	0xcc
+#define LOONGSON_CANFD_TX_DATA_9	0xd0
+#define LOONGSON_CANFD_TX_DATA_10	0xd4
+#define LOONGSON_CANFD_TX_DATA_11	0xd8
+#define LOONGSON_CANFD_TX_DATA_12	0xdc
+#define LOONGSON_CANFD_TX_DATA_13	0xe0
+#define LOONGSON_CANFD_TX_DATA_14	0xe4
+#define LOONGSON_CANFD_TX_DATA_15	0xe8
+#define LOONGSON_CANFD_TX_DATA_16	0xec
+#define LOONGSON_CANFD_TX_DATA_17	0xf0
+#define LOONGSON_CANFD_TX_DATA_18	0xf4
+
+/* Bitfields of CANFD controller ID register */
+#define REG_ID_MASK			GENMASK(15, 0)
+#define REG_ID_VER_MIN			GENMASK(23, 16)
+#define REG_ID_VER_MAJ			GENMASK(31, 24)
+
+/* Bitfields of Mode Configuration register */
+#define REG_MODE_RST			BIT(0)
+#define REG_MODE_BMM			BIT(1)
+#define REG_MODE_STM			BIT(2)
+#define REG_MODE_AFM			BIT(3)
+#define REG_MODE_FDE			BIT(4)
+#define REG_MODE_TTTM			BIT(5)
+#define REG_MODE_ROM			BIT(6)
+#define REG_MODE_ACF			BIT(7)
+#define REG_MODE_TSTM			BIT(8)
+#define REG_MODE_RXBAM			BIT(9)
+#define REG_MODE_ITSM			BIT(10)
+#define REG_MODE_RTSOP			BIT(12)
+#define REG_MODE_BUFM			BIT(13)
+
+/* Bitfields of Configure register */
+#define REG_CONF_RTRLE			BIT(0)
+#define REG_CONF_RTRTH			GENMASK(4, 1)
+#define REG_CONF_ILBP			BIT(5)
+#define REG_CONF_ENA			BIT(6)
+#define REG_CONF_NISOFD			BIT(7)
+#define REG_CONF_PEX			BIT(8)
+#define REG_CONF_FDRF			BIT(10)
+
+/* Bitfields of Status register */
+#define REG_STAT_RXNE			BIT(0)
+#define REG_STAT_DOR			BIT(1)
+#define REG_STAT_TXNF			BIT(2)
+#define REG_STAT_EFT			BIT(3)
+#define REG_STAT_RXS			BIT(4)
+#define REG_STAT_TXS			BIT(5)
+#define REG_STAT_EWL			BIT(6)
+#define REG_STAT_IDLE			BIT(7)
+#define REG_STAT_PEXS			BIT(8)
+#define REG_STAT_STCNT			BIT(16)
+
+/* Bitfields of Command register */
+#define REG_CMD_RXRPMV			BIT(1)
+#define REG_CMD_RRB			BIT(2)
+#define REG_CMD_CDO			BIT(3)
+#define REG_CMD_ERCRST			BIT(4)
+#define REG_CMD_RXFCRST			BIT(5)
+#define REG_CMD_TXFCRST			BIT(6)
+#define REG_CMD_CPEXS			BIT(7)
+
+/* Bitfields of Interrupt Status register */
+#define REG_INT_STAT_RXI		BIT(0)
+#define REG_INT_STAT_TXI		BIT(1)
+#define REG_INT_STAT_EWLI		BIT(2)
+#define REG_INT_STAT_DOI		BIT(3)
+#define REG_INT_STAT_FCSI		BIT(4)
+#define REG_INT_STAT_ALI		BIT(5)
+#define REG_INT_STAT_BEI		BIT(6)
+#define REG_INT_STAT_RXFI		BIT(7)
+#define REG_INT_STAT_BSI		BIT(8)
+#define REG_INT_STAT_RBNEI		BIT(9)
+#define REG_INT_STAT_TXBHCI		BIT(10)
+#define REG_INT_STAT_OFI		BIT(11)
+#define REG_INT_STAT_DMADI		BIT(12)
+
+#define REG_INT_STAT_ERRORI	(REG_INT_STAT_EWLI | REG_INT_STAT_FCSI | REG_INT_STAT_ALI)
+
+/* Bitfields of Interrupt Enable register */
+#define REG_INT_ENA_CLR			GENMASK(28, 16)
+#define REG_INT_ENA_SET			GENMASK(12, 0)
+
+/* Bitfields of Interrupt Mask register */
+#define REG_INT_MASK_SET		GENMASK(12, 0)
+#define REG_INT_MASK_CLR		GENMASK(28, 16)
+
+/* Bitfields of Normal Rate Configuration register */
+#define REG_BTR_PROP			GENMASK(6, 0)
+#define REG_BTR_PH1			GENMASK(12, 7)
+#define REG_BTR_PH2			GENMASK(18, 13)
+#define REG_BTR_BRP			GENMASK(22, 19)
+#define REG_BTR_SJW			GENMASK(31, 27)
+
+/* Bitfields of FD Data Rate Configuration register */
+#define REG_BTR_FD_PROP			GENMASK(6, 0)
+#define REG_BTR_FD_PH1			GENMASK(11, 7)
+#define REG_BTR_FD_PH2			GENMASK(17, 13)
+#define REG_BTR_FD_BRP			GENMASK(26, 19)
+#define REG_BTR_FD_SJW			GENMASK(31, 27)
+
+/* Bitfields of Error Threshold Configuration register */
+#define REG_ERL_ERP			GENMASK(7, 0)
+#define REG_ERL_EW			GENMASK(23, 16)
+
+/* Bitfields of Error Status register */
+#define REG_FSTAT_ERA			BIT(0)
+#define REG_FSTAT_ERP			BIT(1)
+#define REG_FSTAT_BOF			BIT(2)
+
+#define REG_FSTAT_MASK			GENMASK(2, 0)
+
+/* Bitfields of Error Count register */
+#define REG_ERC_TEC			GENMASK(8, 0)
+#define REG_ERC_REC			GENMASK(24, 16)
+
+/* Bitfields of Rate Error Count register */
+#define REG_BRE_NORM			GENMASK(15, 0)
+#define REG_BRE_FD_DATA			GENMASK(31, 16)
+
+/* Bitfields of Error Count Debug register */
+#define REG_CTR_PRES_CTPV		GENMASK(8, 0)
+#define REG_CTR_PRES_PTX		BIT(9)
+#define REG_CTR_PRES_PRX		BIT(10)
+
+/* Bitfields of Error Capture Status register */
+#define REG_ERR_CAPT_POS		GENMASK(4, 0)
+#define REG_ERR_CAPT_TYPE		GENMASK(7, 5)
+
+/* Bitfields of Retransmission Count register */
+#define REG_RETX_CNT_VAL		GENMASK(3, 0)
+
+/* Bitfields of Lost Arbitration Capture register */
+#define REG_ALC_BIT_POS			GENMASK(4, 0)
+#define REG_ALC_ID_FIELD		GENMASK(7, 5)
+
+/* Bitfields of Transmission Delay Measurement register */
+#define REG_TRV_DLY_VAL			GENMASK(6, 0)
+
+/* Bitfields of Second Sampling Point Configuration register */
+#define REG_SSP_CFG_OFF			GENMASK(7, 0)
+#define REG_SSP_CFG_SRC			GENMASK(9, 8)
+#define REG_SSP_CFG_SAT			BIT(10)
+
+/* Bitfields of Receive Message Count register */
+#define REG_RX_FR_CNT_VAL		GENMASK(31, 0)
+
+/* Bitfields of Transmit Message Count register */
+#define REG_TX_FR_CNT_VAL		GENMASK(31, 0)
+
+/* Bitfields of Debug register */
+#define REG_DEBUG_STF_CNT		GENMASK(2, 0)
+#define REG_DEBUG_DSTF_CNT		GENMASK(5, 3)
+#define REG_DEBUG_PC_ARB		BIT(6)
+#define REG_DEBUG_PC_CON		BIT(7)
+#define REG_DEBUG_PC_DAT		BIT(8)
+#define REG_DEBUG_PC_STC		BIT(9)
+#define REG_DEBUG_PC_CRC		BIT(10)
+#define REG_DEBUG_PC_CRCD		BIT(11)
+#define REG_DEBUG_PC_ACK		BIT(12)
+#define REG_DEBUG_PC_ACKD		BIT(13)
+#define REG_DEBUG_PC_EOF		BIT(14)
+#define REG_DEBUG_PC_INT		BIT(15)
+#define REG_DEBUG_PC_SUSP		BIT(16)
+#define REG_DEBUG_PC_OVR		BIT(17)
+#define REG_DEBUG_PC_SOF		BIT(18)
+
+/* Bitfields of Timestamp register */
+#define REG_TS_TIMESTAMP		GENMASK(15, 0)
+#define REG_TS_PSC			GENMASK(24, 16)
+
+/* Bitfields of Fractional Divider Ratio register */
+#define REG_FRC_FRC_DBT			GENMASK(15, 8)
+#define REG_FRC_FRC_NBT			GENMASK(7, 0)
+
+/* Bitfields of Filter A Mask register */
+#define REG_FIL_A_MASK			GENMASK(28, 0)
+
+/* Bitfields of Filter A value register */
+#define REG_FIL_A_VAL			GENMASK(28, 0)
+
+/* Bitfields of Filter B Mask register */
+#define REG_FIL_B_MASK			GENMASK(28, 0)
+
+/* Bitfields of Filter B value register */
+#define REG_FIL_B_VAL			GENMASK(28, 0)
+
+/* Bitfields of Filter C Mask register */
+#define REG_FIL_C_MASK			GENMASK(28, 0)
+
+/* Bitfields of Filter C value register */
+#define REG_FIL_C_VAL			GENMASK(28, 0)
+
+/* Bitfields of Range Filter Low Threshold register */
+#define REG_FIL_R_LOW_VAL		GENMASK(28, 0)
+
+/* Bitfields of Range Filter High Threshold register */
+#define REG_FIL_R_HI_VAL		GENMASK(28, 0)
+
+/* Bitfields of Filter Control register */
+#define REG_FIL_CTRL_FANB		BIT(0)
+#define REG_FIL_CTRL_FANE		BIT(1)
+#define REG_FIL_CTRL_FAFB		BIT(2)
+#define REG_FIL_CTRL_FAFE		BIT(3)
+#define REG_FIL_CTRL_FBNB		BIT(4)
+#define REG_FIL_CTRL_FBNE		BIT(5)
+#define REG_FIL_CTRL_FBFB		BIT(6)
+#define REG_FIL_CTRL_FBFE		BIT(7)
+#define REG_FIL_CTRL_FCNB		BIT(8)
+#define REG_FIL_CTRL_FCNE		BIT(9)
+#define REG_FIL_CTRL_FCFB		BIT(10)
+#define REG_FIL_CTRL_FCFE		BIT(11)
+#define REG_FIL_CTRL_FRNB		BIT(12)
+#define REG_FIL_CTRL_FRNE		BIT(13)
+#define REG_FIL_CTRL_FRFB		BIT(14)
+#define REG_FIL_CTRL_FRFE		BIT(15)
+#define REG_FIL_CTRL_SFA		BIT(16)
+#define REG_FIL_CTRL_SFB		BIT(17)
+#define REG_FIL_CTRL_SFC		BIT(18)
+#define REG_FIL_CTRL_SFR		BIT(19)
+
+/* Bitfields of Receive Buffer Information register */
+#define REG_RX_MEM_INFO_BUFF_SIZE	GENMASK(12, 0)
+#define REG_RX_MEM_INFO_MEM_FREE	GENMASK(28, 16)
+
+/* Bitfields of Receive Buffer Pointer register */
+#define REG_RX_PTR_WPP			GENMASK(11, 0)
+#define REG_RX_PTR_RPP			GENMASK(27, 16)
+
+/* Bitfields of Receive Buffer Status register */
+#define REG_RX_STAT_RXE			BIT(0)
+#define REG_RX_STAT_RXF			BIT(1)
+#define REG_RX_STAT_RXMOF		BIT(2)
+#define REG_RX_STAT_RXFRC		GENMASK(14, 4)
+#define REG_RX_STAT_RTSOP		BIT(16)
+
+/* Bitfields of Receive Data register */
+#define REG_RX_DATA_VAL			GENMASK(31, 0)
+
+/* Bitfields of Transmit Buffer Status register */
+#define REG_TX_STAT_BRP			GENMASK(7, 0)
+#define REG_TX_STAT_TXS			GENMASK(10, 8)
+#define REG_TX_STAT_BS			GENMASK(31, 16)
+
+#define REG_TX_STAT_BS_TX0		GENMASK(17, 16)
+#define REG_TX_STAT_BS_TX1		GENMASK(19, 18)
+#define REG_TX_STAT_BS_TX2		GENMASK(21, 20)
+#define REG_TX_STAT_BS_TX3		GENMASK(23, 22)
+#define REG_TX_STAT_BS_TX4		GENMASK(25, 24)
+#define REG_TX_STAT_BS_TX5		GENMASK(27, 26)
+#define REG_TX_STAT_BS_TX6		GENMASK(29, 28)
+#define REG_TX_STAT_BS_TX7		GENMASK(31, 30)
+
+/* Bitfields of Transmit Command register */
+#define REG_TX_CMD_BAR			GENMASK(7, 0)
+#define REG_TX_CMD_BCR			GENMASK(15, 8)
+#define REG_TX_CMD_BSC			GENMASK(23, 16)
+
+/* Bitfields of Transmit Buffer Selection register */
+#define REG_TX_SEL_BUF_SEL		GENMASK(3, 0)
+#define REG_TX_SEL_BUF_CNT		GENMASK(7, 4)
+
+/* Loongson CANFD Frame format */
+#define LOONGSON_CANFD_FRAME_META0	0x0
+#define LOONGSON_CANFD_FRAME_META1	0x4
+#define LOONGSON_CANFD_FRAME_DB_1	0x8
+#define LOONGSON_CANFD_FRAME_DB_2	0xc
+#define LOONGSON_CANFD_FRAME_DB_3	0x10
+#define LOONGSON_CANFD_FRAME_DB_4	0x14
+#define LOONGSON_CANFD_FRAME_DB_5	0x18
+#define LOONGSON_CANFD_FRAME_DB_6	0x1c
+#define LOONGSON_CANFD_FRAME_DB_7	0x20
+#define LOONGSON_CANFD_FRAME_DB_8	0x24
+#define LOONGSON_CANFD_FRAME_DB_9	0x28
+#define LOONGSON_CANFD_FRAME_DB_10	0x2c
+#define LOONGSON_CANFD_FRAME_DB_11	0x30
+#define LOONGSON_CANFD_FRAME_DB_12	0x34
+#define LOONGSON_CANFD_FRAME_DB_13	0x38
+#define LOONGSON_CANFD_FRAME_DB_14	0x3c
+#define LOONGSON_CANFD_FRAME_DB_16	0x40
+#define LOONGSON_CANFD_FRAME_DB_17	0x44
+
+/* Bitfields of FRAME META0 */
+#define REG_FRAME_META0_ID_EXT		GENMASK(17, 0)
+#define REG_FRAME_META0_ID_BASE		GENMASK(28, 18)
+#define REG_FRAME_META0_RTR		BIT(29)	/* Remote Transmission Request, only in CAN2.0 */
+/* Extended Identifier Type. 1: 29 bits ID, 0: 11 bits ID. */
+#define REG_FRAME_META0_XDT		BIT(30)
+#define REG_FRAME_META0_ESI		BIT(31)	/* Error State Indicator, only in CAN-FD */
+
+/* Bitfields of FRAME META1 */
+#define REG_FRAME_META1_TIMESTAMP	GENMASK(15, 0)
+#define REG_FRAME_META1_DLC		GENMASK(19, 16)	/* Data Length Code */
+#define REG_FRAME_META1_BRS		BIT(20)	/* Bit Rate Shift, Only in CANFD */
+/* Flexible Data-rate Format. 1: CANFD, 0: CAN2.0 */
+#define REG_FRAME_META1_FDF		BIT(21)
+#define REG_FRAME_META1_RWCNT		GENMASK(28, 24)	/* Read Word Counter */
+
+/* Bitfields of FRAME TEST */
+#define REG_FRAME_TEST_FSTC		BIT(0)
+#define REG_FRAME_TEST_FCRC		BIT(1)
+#define REG_FRAME_TEST_SDLC		BIT(2)
+#define REG_FRAME_TEST_TPRM		GENMASK(12, 8)
+
+#define DEV_NAME			"loongson_canfd"
+#define LOONGSON_CANFD_ID		0xBABE
+#define LOONGSON_CANFD_DW_BYTE		4
+#define LOONGSON_CANFD_TXBUF_NUM	8
+#define LOONGSON_CANFD_MAX_RTXTH	0xf
+
+/**
+ * struct loongson_canfd_priv - This definition define CAN driver instance
+ * @can: CAN private data structure.
+ * @napi: NAPI structure
+ * @regmap: regmap of the CAN device
+ * @res: Pointer to the CAN device respurce
+ * @tx_lock: Lock for synchronizing TX interrupt handling
+ */
+struct loongson_canfd_priv {
+	struct can_priv		can;		/* must be first member! */
+	struct napi_struct	napi;
+	struct regmap		*regmap;
+	struct resource		*res;
+	spinlock_t		tx_lock;	/* protect the sending queue */
+};
+
+/**
+ * enum loongson_canfd_txbuf_sts - status of TX buffer
+ * @TX_BS_IDLE: Status processed or not sent.
+ * @TX_BS_VALID: Sending successful.
+ * @TX_BS_FAIL: Sending failed.
+ * @TX_BS_CANCEL: Sending cancelled.
+ */
+enum loongson_canfd_txbuf_sts {
+	TX_BS_IDLE	= 0x0,
+	TX_BS_VALID	= 0x1,
+	TX_BS_FAIL	= 0x2,
+	TX_BS_CANCEL	= 0x3
+};
+
+/**
+ * enum loongson_canfd_txbuf_cmd - command of TX buffer
+ * @TXT_CMD_ADD: Buffer add request.
+ * @TXT_CMD_CANCEL: Buffer cancel request.
+ * @TXT_CMD_SR_CLEAN: Buffer send record clear.
+ *     1: to clear the send completion record (LOONGSON_CANFD_TX_STAT[BS]).
+ */
+enum loongson_canfd_txbuf_cmd {
+	TXT_CMD_ADD		= 0x01,
+	TXT_CMD_CANCEL		= 0x02,
+	TXT_CMD_SR_CLEAN	= 0x03
+};
+
+static const struct can_bittiming_const loongson_canfd_bit_timing = {
+	.name		= DEV_NAME,
+	.tseg1_min	= 2,
+	.tseg1_max	= 190,
+	.tseg2_min	= 2,
+	.tseg2_max	= 63,
+	.sjw_max	= 31,
+	.brp_min	= 1,
+	.brp_max	= 15,
+	.brp_inc	= 1,
+};
+
+static const struct can_bittiming_const loongson_canfd_bit_timing_data = {
+	.name		= DEV_NAME,
+	.tseg1_min	= 2,
+	.tseg1_max	= 190,
+	.tseg2_min	= 2,
+	.tseg2_max	= 63,
+	.sjw_max	= 31,
+	.brp_min	= 1,
+	.brp_max	= 255,
+	.brp_inc	= 1,
+};
+
+/* CAN FD Transmission Delay Compensation constants */
+static const struct can_tdc_const loongson_canfd_tdc_data = {
+	.tdcv_min	= 0,
+	.tdcv_max	= 0,
+	.tdco_min	= 1,
+	.tdco_max	= 127,
+	.tdcf_min	= 0,	/* Filter window not supported */
+	.tdcf_max	= 0,
+};
+
+/**
+ * loongson_canfd_enabled() - Gets the controller is enabled
+ * @priv: Pointer to private data
+ *
+ * Return: True - the controller is enabled.
+ *	   False - the controller is disabled.
+ */
+static bool loongson_canfd_enabled(struct loongson_canfd_priv *priv)
+{
+	return !!regmap_test_bits(priv->regmap, LOONGSON_CANFD_CONF, REG_CONF_ENA);
+}
+
+/**
+ * loongson_canfd_txbuf_freed() - Gets the flag for TX buffer to be sent
+ * @priv: Pointer to private data
+ *
+ * Return: True - TX buffer is empty.
+ *	   False - TX buffer is processing
+ */
+static bool loongson_canfd_txbuf_freed(struct loongson_canfd_priv *priv)
+{
+	return !regmap_test_bits(priv->regmap, LOONGSON_CANFD_TX_STAT, REG_TX_STAT_BRP);
+}
+
+/**
+ * loongson_canfd_get_txbuf_sts() - Gets status of TX buffer
+ * @priv: Pointer to private data
+ * @buf_id: Buffer index (0-based)
+ *
+ * Return: Status of TX buffer
+ */
+static enum loongson_canfd_txbuf_sts
+loongson_canfd_get_txbuf_sts(struct loongson_canfd_priv *priv, u8 buf_id)
+{
+	u32 sts, mask;
+
+	switch (buf_id) {
+	case 0:
+		mask = REG_TX_STAT_BS_TX0;
+		break;
+	case 1:
+		mask = REG_TX_STAT_BS_TX1;
+		break;
+	case 2:
+		mask = REG_TX_STAT_BS_TX2;
+		break;
+	case 3:
+		mask = REG_TX_STAT_BS_TX3;
+		break;
+	case 4:
+		mask = REG_TX_STAT_BS_TX4;
+		break;
+	case 5:
+		mask = REG_TX_STAT_BS_TX5;
+		break;
+	case 6:
+		mask = REG_TX_STAT_BS_TX6;
+		break;
+	case 7:
+		mask = REG_TX_STAT_BS_TX7;
+		break;
+	}
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &sts);
+
+	return field_get(mask, sts);
+}
+
+/**
+ * loongson_canfd_get_txbuf_id() - Gets the index of a non-idle TX buffer
+ * @priv: Pointer to private data
+ * @sts: Status of TXT buffer to outside
+ *
+ * Return: Buffer index (0-based)
+ */
+static unsigned int loongson_canfd_get_txbuf_id(struct loongson_canfd_priv *priv,
+						enum loongson_canfd_txbuf_sts *sts)
+{
+	unsigned int i;
+
+	for (i = 0; i < LOONGSON_CANFD_TXBUF_NUM; i++) {
+		if (loongson_canfd_get_txbuf_sts(priv, i)) {
+			*sts = loongson_canfd_get_txbuf_sts(priv, i);
+			break;
+		}
+	}
+
+	if (i == LOONGSON_CANFD_TXBUF_NUM)
+		*sts = TX_BS_IDLE;
+
+	return i;
+}
+
+/**
+ * loongson_canfd_txbuf_is_writable() - Checks if frame can be inserted to TX Buffer
+ * @priv: Pointer to private data
+ * @buf_id: Buffer index (0-based)
+ *
+ * Return: True - Frame can be inserted to TXT Buffer,
+ *	   False - If attempted, frame will not be inserted to TX Buffer
+ */
+static bool loongson_canfd_txbuf_is_writable(struct loongson_canfd_priv *priv, u8 buf_id)
+{
+	enum loongson_canfd_txbuf_sts bs;
+
+	bs = loongson_canfd_get_txbuf_sts(priv, buf_id);
+	if (bs)
+		return false;
+
+	return !regmap_test_bits(priv->regmap, LOONGSON_CANFD_TX_STAT, BIT(buf_id));
+}
+
+/**
+ * loongson_canfd_set_txbuf_cmd() - Applies command on TX buffer
+ * @ndev: Pointer to net_device structure
+ * @cmd: Command to set
+ * @buf_id: Buffer index (0-based)
+ */
+static void loongson_canfd_set_txbuf_cmd(struct net_device *ndev,
+					 enum loongson_canfd_txbuf_cmd cmd, u8 buf_id)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 mask;
+
+	switch (cmd) {
+	case TXT_CMD_ADD:
+		mask = REG_TX_CMD_BAR;
+		break;
+	case TXT_CMD_CANCEL:
+		mask = REG_TX_CMD_BCR;
+		break;
+	case TXT_CMD_SR_CLEAN:
+		mask = REG_TX_CMD_BSC;
+		break;
+	default:
+		netdev_err(ndev, "Unknown command id: %x\n", cmd);
+		return;
+	}
+
+	regmap_write(priv->regmap, LOONGSON_CANFD_TX_CMD, field_prep(mask, 0x1 << buf_id));
+}
+
+/**
+ * loongson_canfd_reset() - Issues software reset request to Loongson CANFD
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 for success, -%ETIMEDOUT if CAN controller does not leave reset
+ */
+static int loongson_canfd_reset(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+
+	regmap_write(priv->regmap, LOONGSON_CANFD_MODE, REG_MODE_RST);
+	regmap_write(priv->regmap, LOONGSON_CANFD_MODE, REG_MODE_RXBAM | REG_MODE_BUFM);
+
+	return 0;
+}
+
+/**
+ * loongson_canfd_set_btr() - Sets CAN bus bit timing in Loongson CANFD
+ * @ndev: Pointer to net_device structure
+ * @bt: Pointer to Bit timing structure
+ * @nominal: True - Nominal bit timing, False - Data bit timing
+ *
+ * Return: 0 - OK, -%EPERM if controller is enabled
+ */
+static int loongson_canfd_set_btr(struct net_device *ndev, struct can_bittiming *bt, bool nominal)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 phase_seg1 = bt->phase_seg1;
+	u32 prop_seg = bt->prop_seg;
+	int max_ph1_len = 31;
+	u32 btr = 0;
+
+	if (loongson_canfd_enabled(priv)) {
+		netdev_err(ndev, "BUG! Cannot set bittiming - CAN is enabled\n");
+		return -EPERM;
+	}
+
+	if (nominal)
+		max_ph1_len = 63;
+
+	/*
+	 * The timing calculation functions have only constraints on tseg1,
+	 * which is prop_seg + phase1_seg combined.
+	 * tseg1 is then split in half and stored into prog_seg and phase_seg1.
+	 * In Loongson CAN-FD, PROP is 6/7 bits wide but PH1 only 6/5, so we must
+	 * re-distribute the values here.
+	 */
+	if (phase_seg1 > max_ph1_len) {
+		prop_seg += phase_seg1 - max_ph1_len;
+		phase_seg1 = max_ph1_len;
+		bt->prop_seg = prop_seg;
+		bt->phase_seg1 = phase_seg1;
+	}
+
+	if (nominal) {
+		btr = FIELD_PREP(REG_BTR_PROP, prop_seg) |
+		      FIELD_PREP(REG_BTR_PH1, phase_seg1) |
+		      FIELD_PREP(REG_BTR_PH2, bt->phase_seg2) |
+		      FIELD_PREP(REG_BTR_BRP, bt->brp) |
+		      FIELD_PREP(REG_BTR_SJW, bt->sjw);
+
+		regmap_write(priv->regmap, LOONGSON_CANFD_BTR_NORM, btr);
+	} else {
+		btr = FIELD_PREP(REG_BTR_FD_PROP, prop_seg) |
+		      FIELD_PREP(REG_BTR_FD_PH1, phase_seg1) |
+		      FIELD_PREP(REG_BTR_FD_PH2, bt->phase_seg2) |
+		      FIELD_PREP(REG_BTR_FD_BRP, bt->brp) |
+		      FIELD_PREP(REG_BTR_FD_SJW, bt->sjw);
+
+		regmap_write(priv->regmap, LOONGSON_CANFD_BTR_FD, btr);
+	}
+
+	return 0;
+}
+
+/**
+ * loongson_canfd_set_bittiming() - CAN set nominal bit timing routine
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 on success, -%EPERM on error
+ */
+static int loongson_canfd_set_bittiming(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct can_bittiming *bt = &priv->can.bittiming;
+
+	/* Note that bt may be modified here */
+	return loongson_canfd_set_btr(ndev, bt, true);
+}
+
+/**
+ * loongson_canfd_set_data_bittiming() - CAN set data bit timing routine
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 on success, -%EPERM on error
+ */
+static int loongson_canfd_set_data_bittiming(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct can_bittiming *dbt = &priv->can.fd.data_bittiming;
+
+	/* Note that dbt may be modified here */
+	return loongson_canfd_set_btr(ndev, dbt, false);
+}
+
+/**
+ * loongson_canfd_get_auto_tdcv - Get Transmitter Delay Compensation Value
+ * @ndev: Pointer to net_device structure
+ * @tdcv: Pointer to TDCV value
+ *
+ * Return: 0 on success
+ */
+static int loongson_canfd_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 val;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_TRV_DLY, &val);
+	*tdcv = FIELD_GET(REG_TRV_DLY_VAL, val);
+
+	return 0;
+}
+
+/**
+ * loongson_canfd_set_secondary_sample_point() - Set secondary sample point in Loongson CANFD
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 on success, -%EPERM if controller is enabled
+ */
+static int loongson_canfd_set_secondary_sample_point(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 ssp_cfg;
+
+	if (loongson_canfd_enabled(priv)) {
+		netdev_err(ndev, "BUG! Cannot set SSP - CAN is enabled\n");
+		return -EPERM;
+	}
+
+	if (can_fd_tdc_is_enabled(&priv->can))
+		ssp_cfg = FIELD_PREP(REG_SSP_CFG_OFF, priv->can.fd.tdc.tdco) |
+			  FIELD_PREP(REG_SSP_CFG_SRC, 0x0);
+	else
+		ssp_cfg = FIELD_PREP(REG_SSP_CFG_SRC, 0x1);
+
+	regmap_write(priv->regmap, LOONGSON_CANFD_SSP_CFG, ssp_cfg);
+
+	return 0;
+}
+
+/**
+ * loongson_canfd_set_mode() - Sets Loongson CANFD mode
+ * @priv: Pointer to private data
+ * @ctrlmode: Pointer to controller modes to be set
+ */
+static void loongson_canfd_set_mode(struct loongson_canfd_priv *priv,
+				    const struct can_ctrlmode *ctrlmode)
+{
+	u32 mode, conf;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_MODE, &mode);
+
+	if (ctrlmode->flags & CAN_CTRLMODE_LISTENONLY)
+		mode |= REG_MODE_BMM;
+	else
+		mode &= ~REG_MODE_BMM;
+
+	if (ctrlmode->flags & CAN_CTRLMODE_FD)
+		mode |= REG_MODE_FDE;
+	else
+		mode &= ~REG_MODE_FDE;
+
+	if (ctrlmode->flags & CAN_CTRLMODE_PRESUME_ACK)
+		mode |= REG_MODE_ACF;
+	else
+		mode &= ~REG_MODE_ACF;
+
+	/*
+	 * Some bits fixed:
+	 * TSTM - Off, User shall not be able to change REC/TEC by hand
+	 * during operation
+	 */
+	mode &= ~REG_MODE_TSTM;
+	regmap_write(priv->regmap, LOONGSON_CANFD_MODE, mode);
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_CONF, &conf);
+
+	if (ctrlmode->flags & CAN_CTRLMODE_LOOPBACK)
+		conf |= REG_CONF_ILBP;
+	else
+		conf &= ~REG_CONF_ILBP;
+
+	if (ctrlmode->flags & CAN_CTRLMODE_FD_NON_ISO)
+		conf |= REG_CONF_NISOFD;
+	else
+		conf &= ~REG_CONF_NISOFD;
+
+	/* One shot mode supported indirectly via Retransmit limit */
+	conf &= ~FIELD_PREP(REG_CONF_RTRTH, LOONGSON_CANFD_MAX_RTXTH);
+
+	if (ctrlmode->flags & CAN_CTRLMODE_ONE_SHOT)
+		conf |= REG_CONF_RTRLE;
+	else
+		conf |= REG_CONF_RTRLE | FIELD_PREP(REG_CONF_RTRTH, LOONGSON_CANFD_MAX_RTXTH);
+
+	regmap_write(priv->regmap, LOONGSON_CANFD_CONF, conf);
+}
+
+/**
+ * loongson_canfd_chip_start() - This routine starts the driver
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int loongson_canfd_chip_start(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct can_ctrlmode mode;
+	u16 int_ena, int_msk;
+	int ret;
+
+	/* Configure bit-rates and ssp */
+	ret = loongson_canfd_set_bittiming(ndev);
+	if (ret < 0)
+		return ret;
+
+	ret = loongson_canfd_set_data_bittiming(ndev);
+	if (ret < 0)
+		return ret;
+
+	ret = loongson_canfd_set_secondary_sample_point(ndev);
+	if (ret < 0)
+		return ret;
+
+	/* Configure modes */
+	mode.flags = priv->can.ctrlmode;
+	mode.mask = 0xFFFFFFFF;
+	loongson_canfd_set_mode(priv, &mode);
+
+	/* Configure interrupts */
+	int_ena = REG_INT_STAT_RBNEI | REG_INT_STAT_TXBHCI |
+		  REG_INT_STAT_EWLI | REG_INT_STAT_FCSI;
+
+	/* Bus error reporting */
+	if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+		int_ena |= REG_INT_STAT_ALI | REG_INT_STAT_BEI;
+
+	int_msk = ~int_ena; /* Mask all disabled interrupts */
+
+	/* It's after reset, so there is no need to clear anything */
+	regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, int_msk);
+	regmap_write(priv->regmap, LOONGSON_CANFD_INT_ENA, int_ena);
+
+	/* Controller enters ERROR_ACTIVE on initial FCSI */
+	priv->can.state = CAN_STATE_STOPPED;
+
+	/* Enable the controller */
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_CONF, REG_CONF_ENA, REG_CONF_ENA);
+
+	return 0;
+}
+
+/**
+ * loongson_canfd_do_set_mode() - Sets mode of the driver
+ * @ndev: Pointer to net_device structure
+ * @mode: Tells the mode of the driver
+ *
+ * This check the drivers state and calls the corresponding modes to set.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int loongson_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+	int ret;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		ret = loongson_canfd_reset(ndev);
+		if (ret < 0)
+			return ret;
+
+		ret = loongson_canfd_chip_start(ndev);
+		if (ret < 0) {
+			netdev_err(ndev, "loongson_canfd_chip_start failed!\n");
+			return ret;
+		}
+
+		netif_wake_queue(ndev);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * loongson_canfd_insert_frame() - Inserts frame to TXT buffer
+ * @priv: Pointer to private data
+ * @cf:	 Pointer to CAN frame to be inserted
+ * @buf: TXT Buffer index to which frame is inserted (0-based)
+ * @isfdf: True - CAN FD Frame, False - CAN 2.0 Frame
+ *
+ * Return:
+ * * True - Frame inserted successfully
+ * * False - Frame was not inserted due to one of:
+ *	1. TXT Buffer is not writable (it is in wrong state)
+ *	2. Invalid TXT buffer index
+ *	3. Invalid frame length
+ */
+static bool loongson_canfd_insert_frame(struct loongson_canfd_priv *priv,
+					const struct canfd_frame *cf, u8 buf, bool isfdf)
+{
+	u32 meta0, meta1;
+
+	if (buf >= LOONGSON_CANFD_TXBUF_NUM)
+		return false;
+
+	if (!loongson_canfd_txbuf_is_writable(priv, buf))
+		return false;
+
+	/* Prepare identifier */
+	if (cf->can_id & CAN_EFF_FLAG) {
+		meta0 = cf->can_id & CAN_EFF_MASK;
+		meta0 |= REG_FRAME_META0_XDT;
+	} else {
+		meta0 = FIELD_PREP(REG_FRAME_META0_ID_BASE, cf->can_id & CAN_SFF_MASK);
+	}
+
+	/* Prepare Frame format */
+	if (cf->can_id & CAN_RTR_FLAG)
+		meta0 |= REG_FRAME_META0_RTR;
+
+	if (isfdf) {
+		meta1 = REG_FRAME_META1_FDF;
+
+		if (cf->flags & CANFD_BRS)
+			meta1 |= REG_FRAME_META1_BRS;
+	}
+
+	meta1 |= FIELD_PREP(REG_FRAME_META1_DLC, can_fd_len2dlc(cf->len));
+
+	/* TXT buffer select */
+	regmap_write(priv->regmap, LOONGSON_CANFD_TX_SEL, buf);
+
+	/* Write ID, Frame format */
+	regmap_write(priv->regmap, LOONGSON_CANFD_TX_DATA_1 + LOONGSON_CANFD_FRAME_META0, meta0);
+	regmap_write(priv->regmap, LOONGSON_CANFD_TX_DATA_1 + LOONGSON_CANFD_FRAME_META1, meta1);
+
+	/* Write Data payload */
+	if (!(cf->can_id & CAN_RTR_FLAG)) {
+		for (unsigned int i = 0; i < cf->len; i += LOONGSON_CANFD_DW_BYTE) {
+			regmap_write(priv->regmap,
+				     LOONGSON_CANFD_TX_DATA_1 + LOONGSON_CANFD_FRAME_DB_1 + i,
+				     le32_to_cpu(*(__le32 *)(cf->data + i)));
+		}
+	}
+
+	return true;
+}
+
+/**
+ * loongson_canfd_start_xmit() - Starts the transmission
+ * @skb: sk_buff pointer that contains data to be Txed
+ * @ndev: Pointer to net_device structure
+ *
+ * Invoked from upper layers to initiate transmission. Uses the next available free TX Buffer and
+ * populates its fields to start the transmission.
+ *
+ * Return: %NETDEV_TX_OK on success,
+ *         %NETDEV_TX_BUSY when no free TX buffer is available, negative return values reserved
+ *         for error cases.
+ */
+static netdev_tx_t loongson_canfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 buf_id, tx_stat, i = 0;
+	unsigned long tx_brp;
+	u16 tx_bs;
+
+	if (can_dropped_invalid_skb(ndev, skb))
+		return NETDEV_TX_OK;
+
+	if (unlikely(!loongson_canfd_txbuf_freed(priv))) {
+		netif_stop_queue(ndev);
+		netdev_err(ndev, "BUG!, no TXB free when queue awake!\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	guard(spinlock_irqsave)(&priv->tx_lock);
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &tx_stat);
+	tx_brp = FIELD_GET(REG_TX_STAT_BRP, tx_stat);
+	tx_bs = FIELD_GET(REG_TX_STAT_BS, tx_stat);
+
+	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;
+			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?");
+		kfree_skb(skb);
+		ndev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+
+	can_put_echo_skb(skb, ndev, buf_id, 0);
+
+	loongson_canfd_set_txbuf_cmd(ndev, TXT_CMD_ADD, buf_id);
+
+	/* Check if all TX buffers are full */
+	if (!loongson_canfd_txbuf_freed(priv))
+		netif_stop_queue(ndev);
+
+	return NETDEV_TX_OK;
+}
+
+/**
+ * loongson_canfd_read_rx_frame() - Reads frame from RX FIFO
+ * @priv: Pointer to  private data
+ * @cf:	 Pointer to CAN frame struct
+ * @meta0: The first `frame format` read previously
+ * @meta1: The second `frame format` read previously
+ */
+static void loongson_canfd_read_rx_frame(struct loongson_canfd_priv *priv, struct canfd_frame *cf,
+					 u32 meta0, u32 meta1)
+{
+	u32 data, i, wc, len;
+
+	/* Extended Identifier Type */
+	if (meta0 & REG_FRAME_META0_XDT)
+		cf->can_id = (meta0 & CAN_EFF_MASK) | CAN_EFF_FLAG;
+	else
+		cf->can_id = FIELD_GET(REG_FRAME_META0_ID_BASE, meta0) & CAN_SFF_MASK;
+
+	/* BRS, ESI, RTR Flags */
+	cf->flags = 0;
+
+	if (meta1 & REG_FRAME_META1_FDF) {
+		if (meta1 & REG_FRAME_META1_BRS)
+			cf->flags |= CANFD_BRS;
+
+		if (meta0 & REG_FRAME_META0_ESI)
+			cf->flags |= CANFD_ESI;
+	} else if (meta0 & REG_FRAME_META0_RTR) {
+		cf->can_id |= CAN_RTR_FLAG;
+	}
+
+	/* Timesamp */
+	cf->__res0 = meta1;
+	cf->__res1 = meta1 >> 8;
+
+	wc = FIELD_GET(REG_FRAME_META1_RWCNT, meta1) - 2;
+
+	/* Data Length Code */
+	len = FIELD_GET(REG_FRAME_META1_DLC, meta1);
+	if (len > 8) {
+		if (meta1 & REG_FRAME_META1_FDF)
+			len = wc << 2;
+		else
+			len = 8;
+	}
+
+	cf->len = len;
+	if (unlikely(len > wc * LOONGSON_CANFD_DW_BYTE))
+		len = wc * LOONGSON_CANFD_DW_BYTE;
+
+	/* Data */
+	for (i = 0; i < len; i += LOONGSON_CANFD_DW_BYTE) {
+		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
+		*(__le32 *)(cf->data + i) = cpu_to_le32(data);
+	}
+
+	while (unlikely(i < wc * LOONGSON_CANFD_DW_BYTE)) {
+		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
+		i += LOONGSON_CANFD_DW_BYTE;
+	}
+}
+
+/**
+ * loongson_canfd_rx() -  Called from CAN ISR to complete the received frame processing
+ * @ndev: Pointer to net_device structure
+ *
+ * This function is invoked from the CAN isr to process the Rx frames. It does minimal
+ * processing and invokes "netif_receive_skb" to complete further processing.
+ * Return: 1 when frame is passed to the network layer, 0 when the first frame word is read but
+ *	   system is out of free SKBs temporally and left code to resolve SKB allocation later,
+ *         -%EAGAIN in a case of empty Rx FIFO.
+ */
+static int loongson_canfd_rx(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct canfd_frame *cf;
+	struct sk_buff *skb;
+	u32 meta0, meta1;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta0);
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &meta1);
+
+	/* Number of characters received */
+	if (!FIELD_GET(REG_FRAME_META1_RWCNT, meta1))
+		return -EAGAIN;
+
+	/* Flexible Data-rate Format */
+	if (meta1 & REG_FRAME_META1_FDF)
+		skb = alloc_canfd_skb(ndev, &cf);
+	else
+		skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
+	if (unlikely(!skb))
+		return -ENOMEM;
+
+	loongson_canfd_read_rx_frame(priv, cf, meta0, meta1);
+
+	netif_receive_skb(skb);
+
+	return 1;
+}
+
+/**
+ * loongson_canfd_read_fault_state() - Reads Loongson CANFD fault state.
+ * @ndev: Pointer to net_device structure
+ *
+ * Returns: Fault confinement state of controller
+ */
+static enum can_state loongson_canfd_read_fault_state(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	enum can_state sts = CAN_STATE_ERROR_PASSIVE;
+	u32 fstat;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_FSTAT, &fstat);
+
+	switch (FIELD_GET(REG_FSTAT_MASK, fstat)) {
+	case REG_FSTAT_ERA:
+		u32 ewl, erl, rec_tec, max_tec;
+
+		regmap_read(priv->regmap, LOONGSON_CANFD_ERL, &erl);
+		regmap_read(priv->regmap, LOONGSON_CANFD_ERC, &rec_tec);
+
+		ewl = FIELD_GET(REG_ERL_EW, erl);
+		max_tec = max(FIELD_GET(REG_ERC_REC, rec_tec), FIELD_GET(REG_ERC_TEC, rec_tec));
+
+		if (ewl > max_tec)
+			sts = CAN_STATE_ERROR_ACTIVE;
+		else
+			sts = CAN_STATE_ERROR_WARNING;
+		break;
+	case REG_FSTAT_ERP:
+		sts = CAN_STATE_ERROR_PASSIVE;
+		break;
+	case REG_FSTAT_BOF:
+		sts = CAN_STATE_BUS_OFF;
+		break;
+	default:
+		netdev_err(ndev, "Invalid error state.\n");
+		break;
+	}
+
+	return sts;
+}
+
+/**
+ * loongson_canfd_get_bec() - Reads REC/TEC counter values from controller
+ * @priv: Pointer to private data
+ * @bec: Pointer to Error counter structure
+ */
+static void loongson_canfd_get_bec(struct loongson_canfd_priv *priv, struct can_berr_counter *bec)
+{
+	u32 erc;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_ERC, &erc);
+	bec->rxerr = FIELD_GET(REG_ERC_REC, erc);
+	bec->txerr = FIELD_GET(REG_ERC_TEC, erc);
+}
+
+/**
+ * loongson_canfd_get_berr_counter() - error counter routine
+ * @ndev: Pointer to net_device structure
+ * @bec: Pointer to can_berr_counter structure
+ *
+ * Return: 0 always
+ */
+static int loongson_canfd_get_berr_counter(const struct net_device *ndev,
+					   struct can_berr_counter *bec)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+
+	loongson_canfd_get_bec(priv, bec);
+	return 0;
+}
+
+/**
+ * loongson_canfd_err_interrupt() - Error frame ISR
+ * @ndev: net_device pointer
+ * @isr: interrupt status register value
+ *
+ * This is the CAN error interrupt and it will check the type of error and forward the error
+ * frame to upper layers.
+ */
+static void loongson_canfd_err_interrupt(struct net_device *ndev, u32 isr)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	struct can_berr_counter bec;
+	enum can_state state;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	u32 err_capt, alc;
+
+	loongson_canfd_get_bec(priv, &bec);
+
+	state = loongson_canfd_read_fault_state(ndev);
+	regmap_read(priv->regmap, LOONGSON_CANFD_ERR_CAPT, &err_capt);
+	regmap_read(priv->regmap, LOONGSON_CANFD_ALC, &alc);
+
+	netdev_dbg(ndev, "%s: ISR 0x%08x, rxerr %d, txerr %d, error type %lu, pos %lu, ALC id_field %lu, bit %lu\n",
+		   __func__, isr, bec.rxerr, bec.txerr,
+		   FIELD_GET(REG_ERR_CAPT_TYPE, err_capt),
+		   FIELD_GET(REG_ERR_CAPT_POS, err_capt),
+		   FIELD_GET(REG_ALC_ID_FIELD, alc),
+		   FIELD_GET(REG_ALC_BIT_POS, alc));
+
+	skb = alloc_can_err_skb(ndev, &cf);
+
+	/*
+	 * EWLI: error warning limit condition met
+	 * FCSI: fault confinement state changed
+	 * ALI:  arbitration lost (just informative)
+	 * BEI:  bus error interrupt
+	 */
+	if ((isr & REG_INT_STAT_FCSI) || (isr & REG_INT_STAT_EWLI)) {
+		netdev_info(ndev, "state changes from %s to %s\n",
+			    can_get_state_str(priv->can.state), can_get_state_str(state));
+
+		if (priv->can.state == state)
+			netdev_warn(ndev, "cur and pre state is the same!(miss intr?)\n");
+
+		isr = REG_INT_STAT_FCSI | REG_INT_STAT_EWLI;
+		priv->can.state = state;
+		switch (state) {
+		case CAN_STATE_BUS_OFF:
+			priv->can.can_stats.bus_off++;
+			if (priv->can.restart_ms)
+				regmap_write(priv->regmap, LOONGSON_CANFD_CMD,
+					     REG_CMD_ERCRST);
+
+			can_bus_off(ndev);
+			if (skb)
+				cf->can_id |= CAN_ERR_BUSOFF;
+			break;
+		case CAN_STATE_ERROR_PASSIVE:
+			priv->can.can_stats.error_passive++;
+			if (skb) {
+				cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
+				if (bec.rxerr >= CAN_ERROR_PASSIVE_THRESHOLD)
+					cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE;
+				else
+					cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE;
+				cf->data[6] = bec.txerr;
+				cf->data[7] = bec.rxerr;
+			}
+			break;
+		case CAN_STATE_ERROR_WARNING:
+			priv->can.can_stats.error_warning++;
+			if (skb) {
+				cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
+				if (bec.txerr > bec.rxerr)
+					cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+				else
+					cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+				cf->data[6] = bec.txerr;
+				cf->data[7] = bec.rxerr;
+			}
+			break;
+		case CAN_STATE_ERROR_ACTIVE:
+			cf->can_id |= CAN_ERR_CNT;
+			cf->data[1] = CAN_ERR_CRTL_ACTIVE;
+			cf->data[6] = bec.txerr;
+			cf->data[7] = bec.rxerr;
+			break;
+		default:
+			netdev_err(ndev, "Unexpected state: %d, %s!\n", state,
+				   can_get_state_str(state));
+			break;
+		}
+	}
+
+	/* Check for Arbitration Lost interrupt */
+	if (isr & REG_INT_STAT_ALI) {
+		isr = REG_INT_STAT_ALI;
+		netdev_err(ndev, "Arbitration Lost interrupt\n");
+		priv->can.can_stats.arbitration_lost++;
+		if (skb) {
+			cf->can_id |= CAN_ERR_LOSTARB;
+			cf->data[0] = CAN_ERR_LOSTARB_UNSPEC;
+		}
+	}
+
+	/* Check for Bus Error interrupt */
+	if (isr & REG_INT_STAT_BEI) {
+		isr = REG_INT_STAT_BEI;
+		netdev_err(ndev, "Bus Error interrupt\n");
+		priv->can.can_stats.bus_error++;
+		stats->rx_errors++;
+		if (skb) {
+			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+			cf->data[2] = CAN_ERR_PROT_UNSPEC;
+			cf->data[3] = CAN_ERR_PROT_LOC_UNSPEC;
+		}
+	}
+
+	if (skb)
+		netif_rx(skb);
+
+	regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, isr);
+	regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, isr << 16);
+}
+
+static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
+{
+	struct net_device *ndev = napi->dev;
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	int work_done = 0, ret = 1;
+	u32 sts, rx_frc, rx_sts;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_STAT, &rx_sts);
+	rx_frc = FIELD_GET(REG_RX_STAT_RXFRC, rx_sts);
+
+	while (rx_frc && work_done < quota && ret > 0) {
+		ret = loongson_canfd_rx(ndev);
+		work_done++;
+		regmap_read(priv->regmap, LOONGSON_CANFD_RX_STAT, &rx_sts);
+		rx_frc = FIELD_GET(REG_RX_STAT_RXFRC, rx_sts);
+	}
+
+	/* Check for RX FIFO Overflow */
+	regmap_read(priv->regmap, LOONGSON_CANFD_STAT, &sts);
+	if (sts & REG_STAT_DOR) {
+		struct net_device_stats *stats = &ndev->stats;
+		struct can_frame *cf;
+		struct sk_buff *skb;
+
+		netdev_info(ndev, "Loongson canfd RX overflow\n");
+		stats->rx_over_errors++;
+		stats->rx_errors++;
+
+		skb = alloc_can_err_skb(ndev, &cf);
+		if (skb) {
+			cf->can_id |= CAN_ERR_CRTL;
+			cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+			stats->rx_packets++;
+			stats->rx_bytes += cf->can_dlc;
+			netif_rx(skb);
+		}
+
+		/* Clear Data Overrun */
+		regmap_write(priv->regmap, LOONGSON_CANFD_CMD, REG_CMD_CDO);
+	}
+
+	if (!rx_frc && ret != 0) {
+		if (napi_complete_done(napi, work_done)) {
+			/*
+			 * Clear and enable RBNEI. It is level-triggered, 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));
+		}
+	}
+
+	return work_done;
+}
+
+static void loongson_canfd_tx_interrupt(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	enum loongson_canfd_txbuf_sts sts;
+	u32 buf_id;
+
+	guard(spinlock_irqsave)(&priv->tx_lock);
+
+	while ((buf_id = loongson_canfd_get_txbuf_id(priv, &sts)) < LOONGSON_CANFD_TXBUF_NUM) {
+		switch (sts) {
+		case TX_BS_VALID:
+			stats->tx_bytes += can_get_echo_skb(ndev, buf_id, NULL);
+			stats->tx_packets++;
+			break;
+		case TX_BS_FAIL:
+			u32 cnt;
+			/*
+			 * This indicated that retransmit limit has been reached.
+			 * Obviously we should not echo the frame, but also not indicate any
+			 * kind of error. If desired, it was already reported (possible
+			 * multiple times) on each arbitration lost.
+			 */
+			regmap_read(priv->regmap, LOONGSON_CANFD_TX_FR_CNT, &cnt);
+			netdev_warn(ndev, "TXB in FAIL state, TX frame count: %d\n", cnt);
+			can_free_echo_skb(ndev, buf_id, NULL);
+			stats->tx_dropped++;
+			break;
+		case TX_BS_CANCEL:
+			/*
+			 * We *could* re-queue the frame, but multiqueue/abort is
+			 * not supported yet anyway.
+			 */
+			netdev_warn(ndev, "TXB in CANCEL state\n");
+			can_free_echo_skb(ndev, buf_id, NULL);
+			stats->tx_dropped++;
+			break;
+		default:
+			break;
+		}
+
+		loongson_canfd_set_txbuf_cmd(ndev, TXT_CMD_SR_CLEAN, buf_id);
+	}
+
+	/*
+	 * 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);
+
+	/* Check if at least one TX buffer is free */
+	if (loongson_canfd_txbuf_freed(priv))
+		netif_wake_queue(ndev);
+}
+
+/**
+ * loongson_canfd_interrupt() - CAN Isr
+ * @irq: irq number
+ * @dev_id: device id pointer
+ *
+ * This is the Loongson CANFD ISR. It checks for the type of interrupt
+ * and invokes the corresponding ISR.
+ *
+ * Return:
+ * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
+ */
+static irqreturn_t loongson_canfd_interrupt(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	u32 isr, imask;
+
+	for (unsigned int irq_loops = 0; irq_loops < 10000; irq_loops++) {
+		/* Get the interrupt status */
+		regmap_read(priv->regmap, LOONGSON_CANFD_INT_STAT, &isr);
+		if (!isr)
+			return irq_loops ? IRQ_HANDLED : IRQ_NONE;
+
+		/* Receive Buffer Not Empty Interrupt */
+		if (isr & REG_INT_STAT_RBNEI) {
+			/*
+			 * Mask RXBNEI the first, then clear interrupt and schedule NAPI.
+			 * Even if another IRQ fires, RBNEI will always be 0 (masked).
+			 */
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, REG_INT_STAT_RBNEI);
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, REG_INT_STAT_RBNEI);
+			napi_schedule(&priv->napi);
+		}
+
+		/* TX Buffer HW Command Interrupt */
+		if (isr & REG_INT_STAT_TXBHCI)
+			loongson_canfd_tx_interrupt(ndev);
+
+		/* Error interrupts */
+		imask = isr & REG_INT_STAT_ERRORI;
+		if (imask) {
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, imask);
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, imask);
+			loongson_canfd_err_interrupt(ndev, isr);
+		}
+
+		/* Ignore RI, TI, LFI, RFI, BSI */
+	}
+
+	netdev_err(ndev, "Intterupt state: 0x%x.\n", isr);
+
+	if (isr & REG_INT_STAT_TXBHCI) {
+		for (unsigned int i = 0; i < LOONGSON_CANFD_TXBUF_NUM; i++) {
+			u32 sts = loongson_canfd_get_txbuf_sts(priv, i);
+
+			netdev_err(ndev, "TX buf %d status: 0x%x.\n", i, sts);
+		}
+	}
+
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_INT_ENA, REG_INT_ENA_CLR, REG_INT_ENA_CLR);
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_INT_MASK,
+			   REG_INT_MASK_SET, REG_INT_MASK_SET);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * loongson_canfd_chip_stop() - Driver stop routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the drivers stop routine. It will disable the interrupts and
+ * disable the controller.
+ */
+static void loongson_canfd_chip_stop(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+
+	/* Disable interrupts and disable CAN */
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_INT_ENA, REG_INT_ENA_CLR, REG_INT_ENA_CLR);
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_INT_MASK,
+			   REG_INT_MASK_SET, REG_INT_MASK_SET);
+	regmap_update_bits(priv->regmap, LOONGSON_CANFD_CONF, REG_CONF_ENA, 0);
+
+	priv->can.state = CAN_STATE_STOPPED;
+}
+
+/**
+ * loongson_canfd_open() - Driver open routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver open routine.
+ * Return: 0 on success and failure value on error
+ */
+static int loongson_canfd_open(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	int ret;
+
+	ret = loongson_canfd_reset(ndev);
+	if (ret < 0)
+		return ret;
+
+	/* Common open */
+	ret = open_candev(ndev);
+	if (ret) {
+		netdev_warn(ndev, "open_candev failed!\n");
+		return ret;
+	}
+
+	ret = request_irq(ndev->irq, loongson_canfd_interrupt, IRQF_SHARED, ndev->name, ndev);
+	if (ret < 0) {
+		netdev_err(ndev, "irq allocation for CAN failed\n");
+		goto err_irq;
+	}
+
+	ret = loongson_canfd_chip_start(ndev);
+	if (ret < 0) {
+		netdev_err(ndev, "loongson_canfd_chip_start failed!\n");
+		goto err_chip_start;
+	}
+
+	netdev_info(ndev, "loongson_canfd_device registered\n");
+	napi_enable(&priv->napi);
+	netif_start_queue(ndev);
+
+	return 0;
+
+err_chip_start:
+	free_irq(ndev->irq, ndev);
+err_irq:
+	close_candev(ndev);
+	return ret;
+}
+
+/**
+ * loongson_canfd_close() - Driver close routine
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 always
+ */
+static int loongson_canfd_close(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+
+	netif_stop_queue(ndev);
+	napi_disable(&priv->napi);
+	loongson_canfd_chip_stop(ndev);
+	free_irq(ndev->irq, ndev);
+	close_candev(ndev);
+
+	return 0;
+}
+
+static const struct net_device_ops loongson_canfd_netdev_ops = {
+	.ndo_open       = loongson_canfd_open,
+	.ndo_stop       = loongson_canfd_close,
+	.ndo_start_xmit = loongson_canfd_start_xmit,
+};
+
+static const struct regmap_range loongson_canfd_reg_table_wr_range[] = {
+	regmap_reg_range(LOONGSON_CANFD_DEVICE_ID, LOONGSON_CANFD_CONF),
+	regmap_reg_range(LOONGSON_CANFD_CMD, LOONGSON_CANFD_CMD),
+	regmap_reg_range(LOONGSON_CANFD_INT_STAT, LOONGSON_CANFD_ERL),
+	regmap_reg_range(LOONGSON_CANFD_CTR_PRES, LOONGSON_CANFD_CTR_PRES),
+	regmap_reg_range(LOONGSON_CANFD_SSP_CFG, LOONGSON_CANFD_SSP_CFG),
+	regmap_reg_range(LOONGSON_CANFD_TS, LOONGSON_CANFD_FLT_CTRL),
+	regmap_reg_range(LOONGSON_CANFD_TX_CMD, LOONGSON_CANFD_TX_DATA_18),
+};
+
+static const struct regmap_range loongson_canfd_reg_table_rd_range[] = {
+	regmap_reg_range(LOONGSON_CANFD_DEVICE_ID, LOONGSON_CANFD_STAT),
+	regmap_reg_range(LOONGSON_CANFD_INT_STAT, LOONGSON_CANFD_BRE),
+	regmap_reg_range(LOONGSON_CANFD_ERR_CAPT, LOONGSON_CANFD_TX_STAT),
+	regmap_reg_range(LOONGSON_CANFD_TX_SEL, LOONGSON_CANFD_TX_DATA_18),
+};
+
+static const struct regmap_access_table loongson_canfd_reg_table_wr = {
+	.yes_ranges = loongson_canfd_reg_table_wr_range,
+	.n_yes_ranges = ARRAY_SIZE(loongson_canfd_reg_table_wr_range),
+};
+
+static const struct regmap_access_table loongson_canfd_reg_table_rd = {
+	.yes_ranges = loongson_canfd_reg_table_rd_range,
+	.n_yes_ranges = ARRAY_SIZE(loongson_canfd_reg_table_rd_range),
+};
+
+static bool loongson_canfd_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LOONGSON_CANFD_MODE:
+	case LOONGSON_CANFD_CONF:
+	case LOONGSON_CANFD_STAT:
+	case LOONGSON_CANFD_INT_STAT:
+	case LOONGSON_CANFD_INT_ENA:
+	case LOONGSON_CANFD_INT_MASK:
+	case LOONGSON_CANFD_ERL:
+	case LOONGSON_CANFD_FSTAT:
+	case LOONGSON_CANFD_ERC:
+	case LOONGSON_CANFD_ERR_CAPT:
+	case LOONGSON_CANFD_ALC:
+	case LOONGSON_CANFD_TX_FR_CNT:
+	case LOONGSON_CANFD_RX_STAT:
+	case LOONGSON_CANFD_RX_DATA:
+	case LOONGSON_CANFD_TX_STAT:
+	case LOONGSON_CANFD_TX_SEL:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config loongson_cangfd_regmap = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.wr_table	= &loongson_canfd_reg_table_wr,
+	.rd_table	= &loongson_canfd_reg_table_rd,
+	.volatile_reg	= loongson_canfd_volatile_reg,
+	.max_register	= LOONGSON_CANFD_TX_DATA_18,
+	.cache_type	= REGCACHE_MAPLE,
+};
+
+static int loongson_canfd_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct loongson_canfd_priv *priv;
+	struct net_device *ndev;
+	struct regmap *regmap;
+	struct resource *res;
+	void __iomem *base;
+	u32 clk_rate;
+	int ret, irq;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	regmap = devm_regmap_init_mmio(dev, base, &loongson_cangfd_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	device_property_read_u32(dev, "clock-frequency", &clk_rate);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	/* Create a CAN device instance */
+	ndev = alloc_candev(sizeof(*priv), LOONGSON_CANFD_TXBUF_NUM);
+	if (!ndev)
+		return -ENOMEM;
+
+	priv = netdev_priv(ndev);
+	spin_lock_init(&priv->tx_lock);
+	priv->regmap = regmap;
+	priv->res = res;
+
+	priv->can.clock.freq = clk_rate;
+	priv->can.bittiming_const = &loongson_canfd_bit_timing;
+	priv->can.fd.data_bittiming_const = &loongson_canfd_bit_timing_data;
+	priv->can.fd.tdc_const = &loongson_canfd_tdc_data;
+
+	priv->can.fd.do_set_data_bittiming = loongson_canfd_set_data_bittiming;
+	priv->can.fd.do_get_auto_tdcv = loongson_canfd_get_auto_tdcv;
+	priv->can.do_set_mode = loongson_canfd_do_set_mode;
+	priv->can.do_set_bittiming = loongson_canfd_set_bittiming;
+	priv->can.do_get_berr_counter = loongson_canfd_get_berr_counter;
+
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY |
+				       CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_ONE_SHOT |
+				       CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_FD |
+				       CAN_CTRLMODE_PRESUME_ACK | CAN_CTRLMODE_FD_NON_ISO |
+				       CAN_CTRLMODE_TDC_AUTO;
+
+	ndev->irq = irq;
+	ndev->flags |= IFF_ECHO;	/* We support local echo */
+	platform_set_drvdata(pdev, ndev);
+	ndev->netdev_ops = &loongson_canfd_netdev_ops;
+	SET_NETDEV_DEV(ndev, dev);
+
+	ret = loongson_canfd_reset(ndev);
+	if (ret < 0)
+		goto err_candev_free;
+
+	netif_napi_add(ndev, &priv->napi, loongson_canfd_rx_napi);
+
+	ret = register_candev(ndev);
+	if (ret) {
+		dev_err(dev, "register_candev failed with %d\n", ret);
+		goto err_candev_free;
+	}
+
+	return 0;
+
+err_candev_free:
+	free_candev(ndev);
+	return ret;
+}
+
+static void loongson_canfd_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+
+	unregister_candev(ndev);
+	netif_napi_del(&priv->napi);
+	free_candev(ndev);
+}
+
+static const struct acpi_device_id loongson_canfd_acpi_match[] = {
+	{ "LOON0015" },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, loongson_canfd_acpi_match);
+
+static struct platform_driver loongson_canfd_driver = {
+	.probe  = loongson_canfd_probe,
+	.remove = loongson_canfd_remove,
+	.driver = {
+		.name = DEV_NAME,
+		.acpi_match_table = loongson_canfd_acpi_match,
+	},
+};
+module_platform_driver(loongson_canfd_driver);
+
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_DESCRIPTION("Loongson CAN-FD Controller driver");
+MODULE_LICENSE("GPL");
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
  2026-06-08  8:49 [PATCH v2 0/2] Add Loongson CAN-FD controller driver Binbin Zhou
  2026-06-08  8:49 ` [PATCH v2 1/2] can: " Binbin Zhou
@ 2026-06-08  8:49 ` Binbin Zhou
  2026-06-08 12:13   ` Vincent Mailhol
  1 sibling, 1 reply; 4+ messages in thread
From: Binbin Zhou @ 2026-06-08  8:49 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Marc Kleine-Budde, Vincent Mailhol,
	Bingxiong Li
  Cc: Huacai Chen, Xuerui Wang, loongarch, linux-can, jeffbai,
	Binbin Zhou

Add optional DMA support for RX path using the Loongson APB CMC DMA
engine. When a DMA channel is successfully requested, the driver:

- Uses DMA cyclic transfers to write incoming CAN frames directly to
  a coherent DMA buffer
- Replaces RXBNEI (RX buffer not empty interrupt) with DMADI (DMA
  done interrupt)
- Dynamically switches between DMA and PIO modes based on channel
  availability

This significantly reduces CPU intervention under high RX load,
especially beneficial for CAN FD at higher data rates.

Co-developed-by: Bingxiong Li <libingxiong@loongson.cn>
Signed-off-by: Bingxiong Li <libingxiong@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/net/can/Kconfig          |   2 +-
 drivers/net/can/loongson_canfd.c | 209 ++++++++++++++++++++++++++++---
 2 files changed, 190 insertions(+), 21 deletions(-)

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 28014e264f30..16e07be6438c 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -191,7 +191,7 @@ config CAN_KVASER_PCIEFD
 
 config CAN_LOONGSON_CANFD
 	tristate "Loongson CAN-FD controller"
-	depends on HAS_IOMEM || COMPILE_TEST
+	depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)
 	select REGMAP_MMIO
 	help
 	  This is a canfd driver switch for the Loongson platform,
diff --git a/drivers/net/can/loongson_canfd.c b/drivers/net/can/loongson_canfd.c
index 3794700e04c8..131d6d008a5d 100644
--- a/drivers/net/can/loongson_canfd.c
+++ b/drivers/net/can/loongson_canfd.c
@@ -6,10 +6,14 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/acpi_dma.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -376,8 +380,10 @@
 #define DEV_NAME			"loongson_canfd"
 #define LOONGSON_CANFD_ID		0xBABE
 #define LOONGSON_CANFD_DW_BYTE		4
+#define LOONGSON_CANFD_RXBUF_SZ		SZ_1K
 #define LOONGSON_CANFD_TXBUF_NUM	8
 #define LOONGSON_CANFD_MAX_RTXTH	0xf
+#define LOONGSON_CANFD_RXDMA_NUM	(LOONGSON_CANFD_RXBUF_SZ / DMA_SLAVE_BUSWIDTH_4_BYTES)
 
 /**
  * struct loongson_canfd_priv - This definition define CAN driver instance
@@ -385,14 +391,26 @@
  * @napi: NAPI structure
  * @regmap: regmap of the CAN device
  * @res: Pointer to the CAN device respurce
+ * @rx_ch: CAN DMA rx channel
+ * @rx_dma_buf: CAN DMA rx buffer bus address
+ * @rx_buf: CAN DMA rx buffer cpu address
+ * @rx_frc: Last rx data in DMA route
  * @tx_lock: Lock for synchronizing TX interrupt handling
+ * @get_rx_data:  Callback of reading CAN rx data
+ * @get_rx_frc: Callback of the number of messages in the receive buffer
  */
 struct loongson_canfd_priv {
 	struct can_priv		can;		/* must be first member! */
 	struct napi_struct	napi;
 	struct regmap		*regmap;
 	struct resource		*res;
+	struct dma_chan		*rx_ch;
+	dma_addr_t		rx_dma_buf;	/* dma rx buffer bus address */
+	unsigned int		*rx_buf;	/* dma rx buffer cpu address */
+	u16			rx_frc;
 	spinlock_t		tx_lock;	/* protect the sending queue */
+	u32 (*get_rx_data)(struct loongson_canfd_priv *priv);
+	bool (*get_rx_frc)(struct loongson_canfd_priv *priv);
 };
 
 /**
@@ -614,6 +632,125 @@ static int loongson_canfd_reset(struct net_device *ndev)
 	return 0;
 }
 
+/**
+ * loongson_canfd_get_rxdata_in_dma() - Reading RX data in DMA mode
+ * @priv: Pointer to private data
+ *
+ * Return: The CANFD RX data.
+ */
+static u32 loongson_canfd_get_rxdata_in_dma(struct loongson_canfd_priv *priv)
+{
+	u32 c = 0;
+
+	c = priv->rx_buf[LOONGSON_CANFD_RXDMA_NUM - priv->rx_frc--];
+	if (priv->rx_frc == 0)
+		priv->rx_frc = LOONGSON_CANFD_RXDMA_NUM;
+
+	return c;
+}
+
+/**
+ * loongson_canfd_rxfrc_in_dma() - Gets he number of messages in the receive buffer in DMA mode
+ * @priv: Pointer to private data
+ *
+ * Return: The number of messages in the receive buffer
+ */
+static bool loongson_canfd_rxfrc_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_ch->cookie, &state);
+
+	return priv->rx_frc != (state.residue / DMA_SLAVE_BUSWIDTH_4_BYTES) &&
+	       (status == DMA_IN_PROGRESS);
+}
+
+static void loongson_canfd_rxdma_remove(struct loongson_canfd_priv *priv, struct device *dev)
+{
+	dma_free_coherent(dev, LOONGSON_CANFD_RXBUF_SZ, priv->rx_buf, priv->rx_dma_buf);
+}
+
+/**
+ * loongson_canfd_rxdma_init() - Loongson canfd RXDMA initialization
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: The number of messages in the receive buffer
+ */
+static int loongson_canfd_rxdma_init(struct net_device *ndev)
+{
+	struct loongson_canfd_priv *priv = netdev_priv(ndev);
+	struct dma_async_tx_descriptor *desc = NULL;
+	struct device *dev = ndev->dev.parent;
+	struct dma_slave_config config;
+	int ret;
+
+	priv->rx_buf = dma_alloc_coherent(dev, LOONGSON_CANFD_RXBUF_SZ,
+					  &priv->rx_dma_buf, GFP_KERNEL);
+	if (!priv->rx_buf)
+		return -ENOMEM;
+
+	/* Configure DMA channel */
+	memset(&config, 0, sizeof(config));
+	config.src_addr = priv->res->start + LOONGSON_CANFD_RX_DATA;
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	ret = dmaengine_slave_config(priv->rx_ch, &config);
+	if (ret < 0) {
+		netdev_err(ndev, "Loongson canfd rxdma channel config failed\n");
+		goto err_config;
+	}
+
+	/* Prepare a DMA cyclic transaction */
+	desc = dmaengine_prep_dma_cyclic(priv->rx_ch, priv->rx_dma_buf,
+					 LOONGSON_CANFD_RXBUF_SZ, LOONGSON_CANFD_RXBUF_SZ,
+					 DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+	if (!desc) {
+		netdev_err(ndev, "Loongson canfd rxdma cyclic transaction failed\n");
+		ret = -EBUSY;
+		goto err_config;
+	}
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(priv->rx_ch);
+
+	return 0;
+
+err_config:
+	loongson_canfd_rxdma_remove(priv, dev);
+	return ret;
+}
+
+/**
+ * loongson_canfd_get_rxdata_in_poll() - Reading RX data in poll mode
+ * @priv: Pointer to private data
+ *
+ * Return: The CANFD RX data.
+ */
+static u32 loongson_canfd_get_rxdata_in_poll(struct loongson_canfd_priv *priv)
+{
+	u32 data;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
+
+	return data;
+}
+
+/**
+ * loongson_canfd_rxfrc_in_poll() - Gets he number of messages in the receive buffer in poll mode
+ * @priv: Pointer to private data
+ *
+ * Return: The number of messages in the receive buffer
+ */
+static bool loongson_canfd_rxfrc_in_poll(struct loongson_canfd_priv *priv)
+{
+	u32 rx_sts;
+
+	regmap_read(priv->regmap, LOONGSON_CANFD_RX_STAT, &rx_sts);
+
+	return FIELD_GET(REG_RX_STAT_RXFRC, rx_sts) ? true : false;
+}
+
 /**
  * loongson_canfd_set_btr() - Sets CAN bus bit timing in Loongson CANFD
  * @ndev: Pointer to net_device structure
@@ -838,8 +975,8 @@ static int loongson_canfd_chip_start(struct net_device *ndev)
 	loongson_canfd_set_mode(priv, &mode);
 
 	/* Configure interrupts */
-	int_ena = REG_INT_STAT_RBNEI | REG_INT_STAT_TXBHCI |
-		  REG_INT_STAT_EWLI | REG_INT_STAT_FCSI;
+	int_ena = REG_INT_STAT_TXBHCI | REG_INT_STAT_EWLI | REG_INT_STAT_FCSI;
+	int_ena |= priv->rx_ch ? REG_INT_STAT_DMADI : REG_INT_STAT_RBNEI;
 
 	/* Bus error reporting */
 	if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
@@ -1074,12 +1211,12 @@ static void loongson_canfd_read_rx_frame(struct loongson_canfd_priv *priv, struc
 
 	/* Data */
 	for (i = 0; i < len; i += LOONGSON_CANFD_DW_BYTE) {
-		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
+		data = priv->get_rx_data(priv);
 		*(__le32 *)(cf->data + i) = cpu_to_le32(data);
 	}
 
 	while (unlikely(i < wc * LOONGSON_CANFD_DW_BYTE)) {
-		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
+		data = priv->get_rx_data(priv);
 		i += LOONGSON_CANFD_DW_BYTE;
 	}
 }
@@ -1101,8 +1238,8 @@ static int loongson_canfd_rx(struct net_device *ndev)
 	struct sk_buff *skb;
 	u32 meta0, meta1;
 
-	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 */
 	if (!FIELD_GET(REG_FRAME_META1_RWCNT, meta1))
@@ -1328,16 +1465,16 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
 	struct net_device *ndev = napi->dev;
 	struct loongson_canfd_priv *priv = netdev_priv(ndev);
 	int work_done = 0, ret = 1;
-	u32 sts, rx_frc, rx_sts;
+	int int_ena = priv->rx_ch ? REG_INT_STAT_DMADI : REG_INT_STAT_RBNEI;
+	bool rx_frc;
+	u32 sts;
 
-	regmap_read(priv->regmap, LOONGSON_CANFD_RX_STAT, &rx_sts);
-	rx_frc = FIELD_GET(REG_RX_STAT_RXFRC, rx_sts);
+	rx_frc = priv->get_rx_frc(priv);
 
 	while (rx_frc && work_done < quota && ret > 0) {
 		ret = loongson_canfd_rx(ndev);
 		work_done++;
-		regmap_read(priv->regmap, LOONGSON_CANFD_RX_STAT, &rx_sts);
-		rx_frc = FIELD_GET(REG_RX_STAT_RXFRC, rx_sts);
+		rx_frc = priv->get_rx_frc(priv);
 	}
 
 	/* Check for RX FIFO Overflow */
@@ -1367,13 +1504,11 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
 	if (!rx_frc && ret != 0) {
 		if (napi_complete_done(napi, work_done)) {
 			/*
-			 * Clear and enable RBNEI. It is level-triggered, so
+			 * Clear and enable RBNEI/DMADI. It is level-triggered, 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));
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, int_ena);
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, (int_ena << 16));
 		}
 	}
 
@@ -1460,13 +1595,14 @@ static irqreturn_t loongson_canfd_interrupt(int irq, void *dev_id)
 			return irq_loops ? IRQ_HANDLED : IRQ_NONE;
 
 		/* Receive Buffer Not Empty Interrupt */
-		if (isr & REG_INT_STAT_RBNEI) {
+		imask = priv->rx_ch ? REG_INT_STAT_DMADI : REG_INT_STAT_RBNEI;
+		if (isr & imask) {
 			/*
 			 * Mask RXBNEI the first, then clear interrupt and schedule NAPI.
 			 * Even if another IRQ fires, RBNEI will always be 0 (masked).
 			 */
-			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, REG_INT_STAT_RBNEI);
-			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, REG_INT_STAT_RBNEI);
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, imask);
+			regmap_write(priv->regmap, LOONGSON_CANFD_INT_STAT, imask);
 			napi_schedule(&priv->napi);
 		}
 
@@ -1663,6 +1799,7 @@ static int loongson_canfd_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct loongson_canfd_priv *priv;
 	struct net_device *ndev;
+	struct dma_chan *rx_ch;
 	struct regmap *regmap;
 	struct resource *res;
 	void __iomem *base;
@@ -1683,14 +1820,24 @@ static int loongson_canfd_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
+	rx_ch = dma_request_chan(dev, "rx");
+	if (PTR_ERR(rx_ch) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	if (IS_ERR(rx_ch)) {
+		dev_warn(dev, "Fall back in poll mode for any non-deferral error.\n");
+		rx_ch = NULL;
+	}
+
 	/* Create a CAN device instance */
 	ndev = alloc_candev(sizeof(*priv), LOONGSON_CANFD_TXBUF_NUM);
 	if (!ndev)
-		return -ENOMEM;
+		goto err_dma_rx;
 
 	priv = netdev_priv(ndev);
 	spin_lock_init(&priv->tx_lock);
 	priv->regmap = regmap;
+	priv->rx_ch = rx_ch;
 	priv->res = res;
 
 	priv->can.clock.freq = clk_rate;
@@ -1720,6 +1867,19 @@ static int loongson_canfd_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_candev_free;
 
+	if (priv->rx_ch) {
+		priv->get_rx_data = loongson_canfd_get_rxdata_in_dma;
+		priv->get_rx_frc = loongson_canfd_rxfrc_in_dma;
+		priv->rx_frc = LOONGSON_CANFD_RXDMA_NUM;
+		ret = loongson_canfd_rxdma_init(ndev);
+		if (ret) {
+			dev_err(dev, "interrupt mode used for rx (no dma)\n");
+			goto err_candev_free;
+		}
+	} else {
+		priv->get_rx_data = loongson_canfd_get_rxdata_in_poll;
+		priv->get_rx_frc = loongson_canfd_rxfrc_in_poll;
+	}
 	netif_napi_add(ndev, &priv->napi, loongson_canfd_rx_napi);
 
 	ret = register_candev(ndev);
@@ -1732,6 +1892,9 @@ static int loongson_canfd_probe(struct platform_device *pdev)
 
 err_candev_free:
 	free_candev(ndev);
+err_dma_rx:
+	if (rx_ch)
+		dma_release_channel(rx_ch);
 	return ret;
 }
 
@@ -1740,6 +1903,11 @@ static void loongson_canfd_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct loongson_canfd_priv *priv = netdev_priv(ndev);
 
+	if (priv->rx_ch) {
+		loongson_canfd_rxdma_remove(priv, &pdev->dev);
+		dma_release_channel(priv->rx_ch);
+	}
+
 	unregister_candev(ndev);
 	netif_napi_del(&priv->napi);
 	free_candev(ndev);
@@ -1761,6 +1929,7 @@ static struct platform_driver loongson_canfd_driver = {
 };
 module_platform_driver(loongson_canfd_driver);
 
+MODULE_SOFTDEP("pre: loongson2-apb-cmc-dma");
 MODULE_AUTHOR("Loongson Technology Corporation Limited");
 MODULE_DESCRIPTION("Loongson CAN-FD Controller driver");
 MODULE_LICENSE("GPL");
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
  2026-06-08  8:49 ` [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
@ 2026-06-08 12:13   ` Vincent Mailhol
  0 siblings, 0 replies; 4+ messages in thread
From: Vincent Mailhol @ 2026-06-08 12:13 UTC (permalink / raw)
  To: Binbin Zhou, Binbin Zhou, Huacai Chen, Marc Kleine-Budde,
	Bingxiong Li
  Cc: Huacai Chen, Xuerui Wang, loongarch, linux-can, jeffbai

On 08/06/2026 at 10:49, Binbin Zhou wrote:
> Add optional DMA support for RX path using the Loongson APB CMC DMA
> engine. When a DMA channel is successfully requested, the driver:
> 
> - Uses DMA cyclic transfers to write incoming CAN frames directly to
>   a coherent DMA buffer
> - Replaces RXBNEI (RX buffer not empty interrupt) with DMADI (DMA
>   done interrupt)
> - Dynamically switches between DMA and PIO modes based on channel
>   availability
> 
> This significantly reduces CPU intervention under high RX load,
> especially beneficial for CAN FD at higher data rates.
> 
> Co-developed-by: Bingxiong Li <libingxiong@loongson.cn>
> Signed-off-by: Bingxiong Li <libingxiong@loongson.cn>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---

Please check the W=2 warnings:

  $ make W=12 drivers/net/can/loongson_canfd.o
    DESCEND objtool
    INSTALL libsubcmd_headers
    CC      drivers/net/can/loongson_canfd.o
  drivers/net/can/loongson_canfd.c:1917:9: warning: missing initializer for field 'driver_data' of 'const struct acpi_device_id' [-Wmissing-field-initializers]
   1917 |         { "LOON0015" },
        |         ^
  In file included from ./include/linux/acpi.h:16,
                   from drivers/net/can/loongson_canfd.c:8:
  ./include/linux/mod_devicetable.h:219:24: note: 'driver_data' declared here
    219 |         kernel_ulong_t driver_data;
        |                        ^~~~~~~~~~~
  drivers/net/can/loongson_canfd.c: In function 'loongson_canfd_start_xmit':
  drivers/net/can/loongson_canfd.c:1116:13: warning: 'buf_id' may be used uninitialized [-Wmaybe-uninitialized]
   1116 |         u32 buf_id, tx_stat, i = 0;
        |             ^~~~~~
  drivers/net/can/loongson_canfd.c:1116:13: note: 'buf_id' was declared here
   1116 |         u32 buf_id, tx_stat, i = 0;
        |             ^~~~~~
  In function 'loongson_canfd_insert_frame',
      inlined from 'loongson_canfd_start_xmit' at drivers/net/can/loongson_canfd.c:1144:7:
  drivers/net/can/loongson_canfd.c:1079:15: warning: 'meta1' may be used uninitialized [-Wmaybe-uninitialized]
   1079 |         meta1 |= FIELD_PREP(REG_FRAME_META1_DLC, can_fd_len2dlc(cf->len));
        |               ^~
  drivers/net/can/loongson_canfd.c: In function 'loongson_canfd_start_xmit':
  drivers/net/can/loongson_canfd.c:1052:20: note: 'meta1' was declared here
   1052 |         u32 meta0, meta1;
        |                    ^~~~~
  drivers/net/can/loongson_canfd.c: In function 'loongson_canfd_probe':
  drivers/net/can/loongson_canfd.c:1807:13: warning: 'ret' may be used uninitialized [-Wmaybe-uninitialized]
   1807 |         int ret, irq;
        |             ^~~
  drivers/net/can/loongson_canfd.c:1807:13: note: 'ret' was declared here
   1807 |         int ret, irq;
        |             ^~~
  drivers/net/can/loongson_canfd.c: At top level:
  drivers/net/can/loongson_canfd.c:47:9: warning: macro 'LOONGSON_CANFD_RX_FR_CNT' is not used [-Wunused-macros]
     47 | #define LOONGSON_CANFD_RX_FR_CNT        0x50    /* Receive Message Count Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:354:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_14' is not used [-Wunused-macros]
    354 | #define LOONGSON_CANFD_FRAME_DB_14      0x3c
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:307:9: warning: macro 'REG_RX_STAT_RXF' is not used [-Wunused-macros]
    307 | #define REG_RX_STAT_RXF                 BIT(1)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:255:9: warning: macro 'REG_FIL_A_VAL' is not used [-Wunused-macros]
    255 | #define REG_FIL_A_VAL                   GENMASK(28, 0)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:105:9: warning: macro 'REG_MODE_RTSOP' is not used [-Wunused-macros]
    105 | #define REG_MODE_RTSOP                  BIT(12)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:221:9: warning: macro 'REG_RX_FR_CNT_VAL' is not used [-Wunused-macros]
    221 | #define REG_RX_FR_CNT_VAL               GENMASK(31, 0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:273:9: warning: macro 'REG_FIL_R_HI_VAL' is not used [-Wunused-macros]
    273 | #define REG_FIL_R_HI_VAL                GENMASK(28, 0)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:234:9: warning: macro 'REG_DEBUG_PC_CRCD' is not used [-Wunused-macros]
    234 | #define REG_DEBUG_PC_CRCD               BIT(11)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:249:9: warning: macro 'REG_FRC_FRC_NBT' is not used [-Wunused-macros]
    249 | #define REG_FRC_FRC_NBT                 GENMASK(7, 0)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:336:9: warning: macro 'REG_TX_SEL_BUF_CNT' is not used [-Wunused-macros]
    336 | #define REG_TX_SEL_BUF_CNT              GENMASK(7, 4)
        |         ^~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:218:9: warning: macro 'REG_SSP_CFG_SAT' is not used [-Wunused-macros]
    218 | #define REG_SSP_CFG_SAT                 BIT(10)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:91:9: warning: macro 'REG_ID_VER_MAJ' is not used [-Wunused-macros]
     91 | #define REG_ID_VER_MAJ                  GENMASK(31, 24)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:359:9: warning: macro 'REG_FRAME_META0_ID_EXT' is not used [-Wunused-macros]
    359 | #define REG_FRAME_META0_ID_EXT          GENMASK(17, 0)
        |         ^~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:245:9: warning: macro 'REG_TS_PSC' is not used [-Wunused-macros]
    245 | #define REG_TS_PSC                      GENMASK(24, 16)
        |         ^~~~~~~~~~
  drivers/net/can/loongson_canfd.c:231:9: warning: macro 'REG_DEBUG_PC_DAT' is not used [-Wunused-macros]
    231 | #define REG_DEBUG_PC_DAT                BIT(8)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:227:9: warning: macro 'REG_DEBUG_STF_CNT' is not used [-Wunused-macros]
    227 | #define REG_DEBUG_STF_CNT               GENMASK(2, 0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:193:9: warning: macro 'REG_BRE_NORM' is not used [-Wunused-macros]
    193 | #define REG_BRE_NORM                    GENMASK(15, 0)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:238:9: warning: macro 'REG_DEBUG_PC_INT' is not used [-Wunused-macros]
    238 | #define REG_DEBUG_PC_INT                BIT(15)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:56:9: warning: macro 'LOONGSON_CANFD_FLT_B_VAL' is not used [-Wunused-macros]
     56 | #define LOONGSON_CANFD_FLT_B_VAL        0x74    /* Filter B value Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:136:9: warning: macro 'REG_CMD_CPEXS' is not used [-Wunused-macros]
    136 | #define REG_CMD_CPEXS                   BIT(7)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:126:9: warning: macro 'REG_STAT_PEXS' is not used [-Wunused-macros]
    126 | #define REG_STAT_PEXS                   BIT(8)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:78:9: warning: macro 'LOONGSON_CANFD_TX_DATA_10' is not used [-Wunused-macros]
     78 | #define LOONGSON_CANFD_TX_DATA_10       0xd4
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:79:9: warning: macro 'LOONGSON_CANFD_TX_DATA_11' is not used [-Wunused-macros]
     79 | #define LOONGSON_CANFD_TX_DATA_11       0xd8
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:81:9: warning: macro 'LOONGSON_CANFD_TX_DATA_13' is not used [-Wunused-macros]
     81 | #define LOONGSON_CANFD_TX_DATA_13       0xe0
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:83:9: warning: macro 'LOONGSON_CANFD_TX_DATA_15' is not used [-Wunused-macros]
     83 | #define LOONGSON_CANFD_TX_DATA_15       0xe8
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:84:9: warning: macro 'LOONGSON_CANFD_TX_DATA_16' is not used [-Wunused-macros]
     84 | #define LOONGSON_CANFD_TX_DATA_16       0xec
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:85:9: warning: macro 'LOONGSON_CANFD_TX_DATA_17' is not used [-Wunused-macros]
     85 | #define LOONGSON_CANFD_TX_DATA_17       0xf0
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:352:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_12' is not used [-Wunused-macros]
    352 | #define LOONGSON_CANFD_FRAME_DB_12      0x34
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:353:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_13' is not used [-Wunused-macros]
    353 | #define LOONGSON_CANFD_FRAME_DB_13      0x38
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:356:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_17' is not used [-Wunused-macros]
    356 | #define LOONGSON_CANFD_FRAME_DB_17      0x44
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:139:9: warning: macro 'REG_INT_STAT_RXI' is not used [-Wunused-macros]
    139 | #define REG_INT_STAT_RXI                BIT(0)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:267:9: warning: macro 'REG_FIL_C_VAL' is not used [-Wunused-macros]
    267 | #define REG_FIL_C_VAL                   GENMASK(28, 0)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:252:9: warning: macro 'REG_FIL_A_MASK' is not used [-Wunused-macros]
    252 | #define REG_FIL_A_MASK                  GENMASK(28, 0)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:292:9: warning: macro 'REG_FIL_CTRL_SFA' is not used [-Wunused-macros]
    292 | #define REG_FIL_CTRL_SFA                BIT(16)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:232:9: warning: macro 'REG_DEBUG_PC_STC' is not used [-Wunused-macros]
    232 | #define REG_DEBUG_PC_STC                BIT(9)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:59:9: warning: macro 'LOONGSON_CANFD_FLT_R_LOW' is not used [-Wunused-macros]
     59 | #define LOONGSON_CANFD_FLT_R_LOW        0x80    /* Range Filter Low Threshold Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:58:9: warning: macro 'LOONGSON_CANFD_FLT_C_VAL' is not used [-Wunused-macros]
     58 | #define LOONGSON_CANFD_FLT_C_VAL        0x7c    /* Filter C value Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:235:9: warning: macro 'REG_DEBUG_PC_ACK' is not used [-Wunused-macros]
    235 | #define REG_DEBUG_PC_ACK                BIT(12)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:140:9: warning: macro 'REG_INT_STAT_TXI' is not used [-Wunused-macros]
    140 | #define REG_INT_STAT_TXI                BIT(1)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:57:9: warning: macro 'LOONGSON_CANFD_FLT_C_MASK' is not used [-Wunused-macros]
     57 | #define LOONGSON_CANFD_FLT_C_MASK       0x78    /* Filter C Mask Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:317:9: warning: macro 'REG_TX_STAT_TXS' is not used [-Wunused-macros]
    317 | #define REG_TX_STAT_TXS                 GENMASK(10, 8)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:306:9: warning: macro 'REG_RX_STAT_RXE' is not used [-Wunused-macros]
    306 | #define REG_RX_STAT_RXE                 BIT(0)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:104:9: warning: macro 'REG_MODE_ITSM' is not used [-Wunused-macros]
    104 | #define REG_MODE_ITSM                   BIT(10)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:100:9: warning: macro 'REG_MODE_ROM' is not used [-Wunused-macros]
    100 | #define REG_MODE_ROM                    BIT(6)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:298:9: warning: macro 'REG_RX_MEM_INFO_BUFF_SIZE' is not used [-Wunused-macros]
    298 | #define REG_RX_MEM_INFO_BUFF_SIZE       GENMASK(12, 0)
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:248:9: warning: macro 'REG_FRC_FRC_DBT' is not used [-Wunused-macros]
    248 | #define REG_FRC_FRC_DBT                 GENMASK(15, 8)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:230:9: warning: macro 'REG_DEBUG_PC_CON' is not used [-Wunused-macros]
    230 | #define REG_DEBUG_PC_CON                BIT(7)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:233:9: warning: macro 'REG_DEBUG_PC_CRC' is not used [-Wunused-macros]
    233 | #define REG_DEBUG_PC_CRC                BIT(10)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:198:9: warning: macro 'REG_CTR_PRES_PTX' is not used [-Wunused-macros]
    198 | #define REG_CTR_PRES_PTX                BIT(9)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:124:9: warning: macro 'REG_STAT_EWL' is not used [-Wunused-macros]
    124 | #define REG_STAT_EWL                    BIT(6)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:114:9: warning: macro 'REG_CONF_PEX' is not used [-Wunused-macros]
    114 | #define REG_CONF_PEX                    BIT(8)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:96:9: warning: macro 'REG_MODE_STM' is not used [-Wunused-macros]
     96 | #define REG_MODE_STM                    BIT(2)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:150:9: warning: macro 'REG_INT_STAT_OFI' is not used [-Wunused-macros]
    150 | #define REG_INT_STAT_OFI                BIT(11)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:89:9: warning: macro 'REG_ID_MASK' is not used [-Wunused-macros]
     89 | #define REG_ID_MASK                     GENMASK(15, 0)
        |         ^~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:194:9: warning: macro 'REG_BRE_FD_DATA' is not used [-Wunused-macros]
    194 | #define REG_BRE_FD_DATA                 GENMASK(31, 16)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:270:9: warning: macro 'REG_FIL_R_LOW_VAL' is not used [-Wunused-macros]
    270 | #define REG_FIL_R_LOW_VAL               GENMASK(28, 0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:261:9: warning: macro 'REG_FIL_B_VAL' is not used [-Wunused-macros]
    261 | #define REG_FIL_B_VAL                   GENMASK(28, 0)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:55:9: warning: macro 'LOONGSON_CANFD_FLT_B_MASK' is not used [-Wunused-macros]
     55 | #define LOONGSON_CANFD_FLT_B_MASK       0x70    /* Filter B Mask Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:43:9: warning: macro 'LOONGSON_CANFD_RETX_CNT' is not used [-Wunused-macros]
     43 | #define LOONGSON_CANFD_RETX_CNT         0x40    /* Retransmission Count Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:367:9: warning: macro 'REG_FRAME_META1_TIMESTAMP' is not used [-Wunused-macros]
    367 | #define REG_FRAME_META1_TIMESTAMP       GENMASK(15, 0)
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:229:9: warning: macro 'REG_DEBUG_PC_ARB' is not used [-Wunused-macros]
    229 | #define REG_DEBUG_PC_ARB                BIT(6)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:375:9: warning: macro 'REG_FRAME_TEST_FSTC' is not used [-Wunused-macros]
    375 | #define REG_FRAME_TEST_FSTC             BIT(0)
        |         ^~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:178:9: warning: macro 'REG_ERL_ERP' is not used [-Wunused-macros]
    178 | #define REG_ERL_ERP                     GENMASK(7, 0)
        |         ^~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:378:9: warning: macro 'REG_FRAME_TEST_TPRM' is not used [-Wunused-macros]
    378 | #define REG_FRAME_TEST_TPRM             GENMASK(12, 8)
        |         ^~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:264:9: warning: macro 'REG_FIL_C_MASK' is not used [-Wunused-macros]
    264 | #define REG_FIL_C_MASK                  GENMASK(28, 0)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:241:9: warning: macro 'REG_DEBUG_PC_SOF' is not used [-Wunused-macros]
    241 | #define REG_DEBUG_PC_SOF                BIT(18)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:290:9: warning: macro 'REG_FIL_CTRL_FRFB' is not used [-Wunused-macros]
    290 | #define REG_FIL_CTRL_FRFB               BIT(14)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:288:9: warning: macro 'REG_FIL_CTRL_FRNB' is not used [-Wunused-macros]
    288 | #define REG_FIL_CTRL_FRNB               BIT(12)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:244:9: warning: macro 'REG_TS_TIMESTAMP' is not used [-Wunused-macros]
    244 | #define REG_TS_TIMESTAMP                GENMASK(15, 0)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:118:9: warning: macro 'REG_STAT_RXNE' is not used [-Wunused-macros]
    118 | #define REG_STAT_RXNE                   BIT(0)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:157:9: warning: macro 'REG_INT_ENA_SET' is not used [-Wunused-macros]
    157 | #define REG_INT_ENA_SET                 GENMASK(12, 0)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:299:9: warning: macro 'REG_RX_MEM_INFO_MEM_FREE' is not used [-Wunused-macros]
    299 | #define REG_RX_MEM_INFO_MEM_FREE        GENMASK(28, 16)
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:161:9: warning: macro 'REG_INT_MASK_CLR' is not used [-Wunused-macros]
    161 | #define REG_INT_MASK_CLR                GENMASK(28, 16)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:281:9: warning: macro 'REG_FIL_CTRL_FBNE' is not used [-Wunused-macros]
    281 | #define REG_FIL_CTRL_FBNE               BIT(5)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:279:9: warning: macro 'REG_FIL_CTRL_FAFE' is not used [-Wunused-macros]
    279 | #define REG_FIL_CTRL_FAFE               BIT(3)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:123:9: warning: macro 'REG_STAT_TXS' is not used [-Wunused-macros]
    123 | #define REG_STAT_TXS                    BIT(5)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:80:9: warning: macro 'LOONGSON_CANFD_TX_DATA_12' is not used [-Wunused-macros]
     80 | #define LOONGSON_CANFD_TX_DATA_12       0xdc
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:82:9: warning: macro 'LOONGSON_CANFD_TX_DATA_14' is not used [-Wunused-macros]
     82 | #define LOONGSON_CANFD_TX_DATA_14       0xe4
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:70:9: warning: macro 'LOONGSON_CANFD_TX_DATA_2' is not used [-Wunused-macros]
     70 | #define LOONGSON_CANFD_TX_DATA_2        0xb4
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:74:9: warning: macro 'LOONGSON_CANFD_TX_DATA_6' is not used [-Wunused-macros]
     74 | #define LOONGSON_CANFD_TX_DATA_6        0xc4
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:75:9: warning: macro 'LOONGSON_CANFD_TX_DATA_7' is not used [-Wunused-macros]
     75 | #define LOONGSON_CANFD_TX_DATA_7        0xc8
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:77:9: warning: macro 'LOONGSON_CANFD_TX_DATA_9' is not used [-Wunused-macros]
     77 | #define LOONGSON_CANFD_TX_DATA_9        0xd0
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:291:9: warning: macro 'REG_FIL_CTRL_FRFE' is not used [-Wunused-macros]
    291 | #define REG_FIL_CTRL_FRFE               BIT(15)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:335:9: warning: macro 'REG_TX_SEL_BUF_SEL' is not used [-Wunused-macros]
    335 | #define REG_TX_SEL_BUF_SEL              GENMASK(3, 0)
        |         ^~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:134:9: warning: macro 'REG_CMD_RXFCRST' is not used [-Wunused-macros]
    134 | #define REG_CMD_RXFCRST                 BIT(5)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:147:9: warning: macro 'REG_INT_STAT_BSI' is not used [-Wunused-macros]
    147 | #define REG_INT_STAT_BSI                BIT(8)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:99:9: warning: macro 'REG_MODE_TTTM' is not used [-Wunused-macros]
     99 | #define REG_MODE_TTTM                   BIT(5)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:51:9: warning: macro 'LOONGSON_CANFD_TX_FRM_TST' is not used [-Wunused-macros]
     51 | #define LOONGSON_CANFD_TX_FRM_TST       0x60    /* Transmit Message Debug Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:206:9: warning: macro 'REG_RETX_CNT_VAL' is not used [-Wunused-macros]
    206 | #define REG_RETX_CNT_VAL                GENMASK(3, 0)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:228:9: warning: macro 'REG_DEBUG_DSTF_CNT' is not used [-Wunused-macros]
    228 | #define REG_DEBUG_DSTF_CNT              GENMASK(5, 3)
        |         ^~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:199:9: warning: macro 'REG_CTR_PRES_PRX' is not used [-Wunused-macros]
    199 | #define REG_CTR_PRES_PRX                BIT(10)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:142:9: warning: macro 'REG_INT_STAT_DOI' is not used [-Wunused-macros]
    142 | #define REG_INT_STAT_DOI                BIT(3)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:125:9: warning: macro 'REG_STAT_IDLE' is not used [-Wunused-macros]
    125 | #define REG_STAT_IDLE                   BIT(7)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:197:9: warning: macro 'REG_CTR_PRES_CTPV' is not used [-Wunused-macros]
    197 | #define REG_CTR_PRES_CTPV               GENMASK(8, 0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:97:9: warning: macro 'REG_MODE_AFM' is not used [-Wunused-macros]
     97 | #define REG_MODE_AFM                    BIT(3)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:240:9: warning: macro 'REG_DEBUG_PC_OVR' is not used [-Wunused-macros]
    240 | #define REG_DEBUG_PC_OVR                BIT(17)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:310:9: warning: macro 'REG_RX_STAT_RTSOP' is not used [-Wunused-macros]
    310 | #define REG_RX_STAT_RTSOP               BIT(16)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:313:9: warning: macro 'REG_RX_DATA_VAL' is not used [-Wunused-macros]
    313 | #define REG_RX_DATA_VAL                 GENMASK(31, 0)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:63:9: warning: macro 'LOONGSON_CANFD_RX_PRT' is not used [-Wunused-macros]
     63 | #define LOONGSON_CANFD_RX_PRT           0x90    /* Receive Buffer Pointer Register */
        |         ^~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:258:9: warning: macro 'REG_FIL_B_MASK' is not used [-Wunused-macros]
    258 | #define REG_FIL_B_MASK                  GENMASK(28, 0)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:289:9: warning: macro 'REG_FIL_CTRL_FRNE' is not used [-Wunused-macros]
    289 | #define REG_FIL_CTRL_FRNE               BIT(13)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:377:9: warning: macro 'REG_FRAME_TEST_SDLC' is not used [-Wunused-macros]
    377 | #define REG_FRAME_TEST_SDLC             BIT(2)
        |         ^~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:293:9: warning: macro 'REG_FIL_CTRL_SFB' is not used [-Wunused-macros]
    293 | #define REG_FIL_CTRL_SFB                BIT(17)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:294:9: warning: macro 'REG_FIL_CTRL_SFC' is not used [-Wunused-macros]
    294 | #define REG_FIL_CTRL_SFC                BIT(18)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:295:9: warning: macro 'REG_FIL_CTRL_SFR' is not used [-Wunused-macros]
    295 | #define REG_FIL_CTRL_SFR                BIT(19)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:224:9: warning: macro 'REG_TX_FR_CNT_VAL' is not used [-Wunused-macros]
    224 | #define REG_TX_FR_CNT_VAL               GENMASK(31, 0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:60:9: warning: macro 'LOONGSON_CANFD_FLT_R_HI' is not used [-Wunused-macros]
     60 | #define LOONGSON_CANFD_FLT_R_HI         0x84    /* Range Filter High Threshold Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:71:9: warning: macro 'LOONGSON_CANFD_TX_DATA_3' is not used [-Wunused-macros]
     71 | #define LOONGSON_CANFD_TX_DATA_3        0xb8
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:73:9: warning: macro 'LOONGSON_CANFD_TX_DATA_5' is not used [-Wunused-macros]
     73 | #define LOONGSON_CANFD_TX_DATA_5        0xc0
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:76:9: warning: macro 'LOONGSON_CANFD_TX_DATA_8' is not used [-Wunused-macros]
     76 | #define LOONGSON_CANFD_TX_DATA_8        0xcc
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:115:9: warning: macro 'REG_CONF_FDRF' is not used [-Wunused-macros]
    115 | #define REG_CONF_FDRF                   BIT(10)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:122:9: warning: macro 'REG_STAT_RXS' is not used [-Wunused-macros]
    122 | #define REG_STAT_RXS                    BIT(4)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:303:9: warning: macro 'REG_RX_PTR_RPP' is not used [-Wunused-macros]
    303 | #define REG_RX_PTR_RPP                  GENMASK(27, 16)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:286:9: warning: macro 'REG_FIL_CTRL_FCFB' is not used [-Wunused-macros]
    286 | #define REG_FIL_CTRL_FCFB               BIT(10)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:287:9: warning: macro 'REG_FIL_CTRL_FCFE' is not used [-Wunused-macros]
    287 | #define REG_FIL_CTRL_FCFE               BIT(11)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:121:9: warning: macro 'REG_STAT_EFT' is not used [-Wunused-macros]
    121 | #define REG_STAT_EFT                    BIT(3)
        |         ^~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:130:9: warning: macro 'REG_CMD_RXRPMV' is not used [-Wunused-macros]
    130 | #define REG_CMD_RXRPMV                  BIT(1)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:342:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_2' is not used [-Wunused-macros]
    342 | #define LOONGSON_CANFD_FRAME_DB_2       0xc
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:344:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_4' is not used [-Wunused-macros]
    344 | #define LOONGSON_CANFD_FRAME_DB_4       0x14
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:347:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_7' is not used [-Wunused-macros]
    347 | #define LOONGSON_CANFD_FRAME_DB_7       0x20
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:348:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_8' is not used [-Wunused-macros]
    348 | #define LOONGSON_CANFD_FRAME_DB_8       0x24
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:343:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_3' is not used [-Wunused-macros]
    343 | #define LOONGSON_CANFD_FRAME_DB_3       0x10
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:349:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_9' is not used [-Wunused-macros]
    349 | #define LOONGSON_CANFD_FRAME_DB_9       0x28
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:345:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_5' is not used [-Wunused-macros]
    345 | #define LOONGSON_CANFD_FRAME_DB_5       0x18
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:346:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_6' is not used [-Wunused-macros]
    346 | #define LOONGSON_CANFD_FRAME_DB_6       0x1c
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:52:9: warning: macro 'LOONGSON_CANFD_FRC_DIV' is not used [-Wunused-macros]
     52 | #define LOONGSON_CANFD_FRC_DIV          0x64    /* Fractional Divider Ratio Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:350:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_10' is not used [-Wunused-macros]
    350 | #define LOONGSON_CANFD_FRAME_DB_10      0x2c
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:351:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_11' is not used [-Wunused-macros]
    351 | #define LOONGSON_CANFD_FRAME_DB_11      0x30
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:355:9: warning: macro 'LOONGSON_CANFD_FRAME_DB_16' is not used [-Wunused-macros]
    355 | #define LOONGSON_CANFD_FRAME_DB_16      0x40
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:54:9: warning: macro 'LOONGSON_CANFD_FLT_A_VAL' is not used [-Wunused-macros]
     54 | #define LOONGSON_CANFD_FLT_A_VAL        0x6c    /* Filter A value Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:237:9: warning: macro 'REG_DEBUG_PC_EOF' is not used [-Wunused-macros]
    237 | #define REG_DEBUG_PC_EOF                BIT(14)
        |         ^~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:49:9: warning: macro 'LOONGSON_CANFD_DEBUG' is not used [-Wunused-macros]
     49 | #define LOONGSON_CANFD_DEBUG            0x58    /* Debug Register */
        |         ^~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:131:9: warning: macro 'REG_CMD_RRB' is not used [-Wunused-macros]
    131 | #define REG_CMD_RRB                     BIT(2)
        |         ^~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:302:9: warning: macro 'REG_RX_PTR_WPP' is not used [-Wunused-macros]
    302 | #define REG_RX_PTR_WPP                  GENMASK(11, 0)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:239:9: warning: macro 'REG_DEBUG_PC_SUSP' is not used [-Wunused-macros]
    239 | #define REG_DEBUG_PC_SUSP               BIT(16)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:376:9: warning: macro 'REG_FRAME_TEST_FCRC' is not used [-Wunused-macros]
    376 | #define REG_FRAME_TEST_FCRC             BIT(1)
        |         ^~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:278:9: warning: macro 'REG_FIL_CTRL_FAFB' is not used [-Wunused-macros]
    278 | #define REG_FIL_CTRL_FAFB               BIT(2)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:276:9: warning: macro 'REG_FIL_CTRL_FANB' is not used [-Wunused-macros]
    276 | #define REG_FIL_CTRL_FANB               BIT(0)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:277:9: warning: macro 'REG_FIL_CTRL_FANE' is not used [-Wunused-macros]
    277 | #define REG_FIL_CTRL_FANE               BIT(1)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:282:9: warning: macro 'REG_FIL_CTRL_FBFB' is not used [-Wunused-macros]
    282 | #define REG_FIL_CTRL_FBFB               BIT(6)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:283:9: warning: macro 'REG_FIL_CTRL_FBFE' is not used [-Wunused-macros]
    283 | #define REG_FIL_CTRL_FBFE               BIT(7)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:308:9: warning: macro 'REG_RX_STAT_RXMOF' is not used [-Wunused-macros]
    308 | #define REG_RX_STAT_RXMOF               BIT(2)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:280:9: warning: macro 'REG_FIL_CTRL_FBNB' is not used [-Wunused-macros]
    280 | #define REG_FIL_CTRL_FBNB               BIT(4)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:90:9: warning: macro 'REG_ID_VER_MIN' is not used [-Wunused-macros]
     90 | #define REG_ID_VER_MIN                  GENMASK(23, 16)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:62:9: warning: macro 'LOONGSON_CANFD_RX_MEM_INFO' is not used [-Wunused-macros]
     62 | #define LOONGSON_CANFD_RX_MEM_INFO      0x8c    /* Receive Buffer Information Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:127:9: warning: macro 'REG_STAT_STCNT' is not used [-Wunused-macros]
    127 | #define REG_STAT_STCNT                  BIT(16)
        |         ^~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:236:9: warning: macro 'REG_DEBUG_PC_ACKD' is not used [-Wunused-macros]
    236 | #define REG_DEBUG_PC_ACKD               BIT(13)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:146:9: warning: macro 'REG_INT_STAT_RXFI' is not used [-Wunused-macros]
    146 | #define REG_INT_STAT_RXFI               BIT(7)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:120:9: warning: macro 'REG_STAT_TXNF' is not used [-Wunused-macros]
    120 | #define REG_STAT_TXNF                   BIT(2)
        |         ^~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:135:9: warning: macro 'REG_CMD_TXFCRST' is not used [-Wunused-macros]
    135 | #define REG_CMD_TXFCRST                 BIT(6)
        |         ^~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:381:9: warning: macro 'LOONGSON_CANFD_ID' is not used [-Wunused-macros]
    381 | #define LOONGSON_CANFD_ID               0xBABE
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:72:9: warning: macro 'LOONGSON_CANFD_TX_DATA_4' is not used [-Wunused-macros]
     72 | #define LOONGSON_CANFD_TX_DATA_4        0xbc
        |         ^~~~~~~~~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:284:9: warning: macro 'REG_FIL_CTRL_FCNB' is not used [-Wunused-macros]
    284 | #define REG_FIL_CTRL_FCNB               BIT(8)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:285:9: warning: macro 'REG_FIL_CTRL_FCNE' is not used [-Wunused-macros]
    285 | #define REG_FIL_CTRL_FCNE               BIT(9)
        |         ^~~~~~~~~~~~~~~~~
  drivers/net/can/loongson_canfd.c:53:9: warning: macro 'LOONGSON_CANFD_FLT_A_MASK' is not used [-Wunused-macros]
     53 | #define LOONGSON_CANFD_FLT_A_MASK       0x68    /* Filter A Mask Register */
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~

>  drivers/net/can/Kconfig          |   2 +-
>  drivers/net/can/loongson_canfd.c | 209 ++++++++++++++++++++++++++++---
>  2 files changed, 190 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 28014e264f30..16e07be6438c 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -191,7 +191,7 @@ config CAN_KVASER_PCIEFD
>  
>  config CAN_LOONGSON_CANFD
>  	tristate "Loongson CAN-FD controller"
> -	depends on HAS_IOMEM || COMPILE_TEST
> +	depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)

The logic is odd here. If your driver can be COMPILE_TESTed without
HAS_IOMEM, then patch 1 should be:

	depends on HAS_IOMEM || COMPILE_TEST

and patch 2 should be:

	depends on (HAS_IOMEM && LOONGSON2_APB_CMC_DMA) || COMPILE_TEST

If your driver need HAS_IOMEM even for a compile test, then patch 1
should be:

	depends on HAS_IOMEM

and patch 2 should be:

	depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)

Here, you are doing a weird mix.

>  	select REGMAP_MMIO
>  	help
>  	  This is a canfd driver switch for the Loongson platform,


Yours sincerely,
Vincent Mailhol

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-08 12:13 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-08  8:49 [PATCH v2 0/2] Add Loongson CAN-FD controller driver Binbin Zhou
2026-06-08  8:49 ` [PATCH v2 1/2] can: " Binbin Zhou
2026-06-08  8:49 ` [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
2026-06-08 12:13   ` Vincent Mailhol

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.