Add Loongson CAN-FD controller driver
Subsystems (2)
v2 cover Add Loongson CAN-FD controller driver
Hi all:
This patchset adds support for the CAN-FD controller found on Loongson CPUs.
Patch 1 introduces the basic CAN-FD controller driver with support for classic CAN and CAN FD, including bit timing, error handling, NAPI-based RX, and multiple TX buffers.
Patch 2 adds optional DMA support for RX path using the Loongson APB CMC DMA engine, which significantly reduces CPU load under high receive throughput.
The driver has been tested on Loongson-2K3000 platforms with various CAN/CAN FD traffic patterns.
Finally, I'd like to thank 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/[email protected]/
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
Signature · 1 line
2.52.0
PATCH v2 1/2 can: Add Loongson CAN-FD controller driver
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
--- 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
MAINTAINERS +7 -0
@@ -14935,6 +14935,13 @@ F: arch/loongarch/ F: drivers/*/*loongarch* F: drivers/cpufreq/loongson3_cpufreq.c +LOONGSON CAN FD DRIVER +M: Bingxiong Li <[email protected]> +M: Binbin Zhou <[email protected]> +L: [email protected] +S: Maintained +F: drivers/net/can/loongson_canfd.c + LOONGSON GPIO DRIVER M: Yinbo Zhu <[email protected]> L: [email protected]
drivers/net/can/Kconfig +15 -0
@@ -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
drivers/net/can/Makefile +1 -0
@@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd/ +obj-$(CONFIG_CAN_LOONGSON_CANFD) += loongson_canfd.o obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_M_CAN) += m_can/ obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/
drivers/net/can/loongson_canfd.c new file +1766 -0
1,766 lines not on this page · raw message
Signature · 1 line
2.52.0
Vincent Mailhol
maintainerRe: [PATCH v2 1/2] can: Add Loongson CAN-FD controller driver
Quoted 600 lines · 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 bitratesCo-developed-by Bingxiong Li <[email protected]>Signed-off-by Bingxiong Li <[email protected]>Signed-off-by Binbin Zhou <[email protected]>--- 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.cMAINTAINERS +7
-0@@ -14935,6 +14935,13 @@ F: arch/loongarch/ F: drivers/*/*loongarch* F: drivers/cpufreq/loongson3_cpufreq.c +LOONGSON CAN FD DRIVER +M: Bingxiong Li <[email protected]> +M: Binbin Zhou <[email protected]> +L: [email protected] +S: Maintained +F: drivers/net/can/loongson_canfd.c + LOONGSON GPIO DRIVER M: Yinbo Zhu <[email protected]> L: [email protected]drivers/net/can/Kconfig +15
-0@@ -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 TTYdrivers/net/can/Makefile +1
-0@@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd/ +obj-$(CONFIG_CAN_LOONGSON_CANFD) += loongson_canfd.o obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_M_CAN) += m_can/ obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/drivers/net/can/loongson_canfd.c new file +515
-0@@ -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 ;
drivers/net/can/loongson_canfd.c line 525
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+break ; +case 7 : + mask =REG_TX_STAT_BS_TX7 ; +break ; + } + +regmap_read (priv->regmap,LOONGSON_CANFD_TX_STAT , &sts); + +return field_get (mask, sts); +}
I think it is easier to compute the mask than doing this switch case. Maybe something like this:
#define REG_TX_STAT_BS_TX_BASE 16
/* ... */
static enum loongson_canfd_txbuf_sts
loongson_canfd_get_txbuf_sts(struct loongson_canfd_priv *priv, u8 buf_id)
{
u32 mask, sts;
mask = GENMASK(REG_TX_STAT_BS_TX_BASE + 2 * buf_id + 1,
REG_TX_STAT_BS_TX_BASE + 2 * buf_id);
regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &sts);
return field_get(mask, sts);
}Or equivalent:
#define REG_TX_STAT_BS_TX_MASK_BASE GENMASK(17, 16)
/* ... */
static enum loongson_canfd_txbuf_sts
loongson_canfd_get_txbuf_sts(struct loongson_canfd_priv *priv, u8 buf_id)
{
u32 mask, sts;
mask = REG_TX_STAT_BS_TX_MASK_BASE << 2 * buf_id;
regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &sts);
return field_get(mask, sts);
}Quoted 62 lines
drivers/net/can/loongson_canfd.c new file +62
-0+/** +* 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 ;
drivers/net/can/loongson_canfd.c line 598
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+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));
^^^^^^^^^^^^^ Nitpick: regmap_write(priv->regmap, LOONGSON_CANFD_TX_CMD, field_prep(mask, BIT(buf_id)));
drivers/net/can/loongson_canfd.c line 605
Quoted 7 lines
drivers/net/can/loongson_canfd.c new file +7
-0+} + +/** +* 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
^^^^^^^^^^^
This part of the documentation does not match the code.
Quoted 14 lines
drivers/net/can/loongson_canfd.c new file +14
-0+*/ +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
drivers/net/can/loongson_canfd.c line 629
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+* @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;
No need for those phase_seg1 and prop_seg variables. Directly do the math on bt->phase_seg1 and bt->prop_seg.
drivers/net/can/loongson_canfd.c line 630
Quoted 1 line
drivers/net/can/loongson_canfd.c new file +1
-0+int max_ph1_len =31 ;
Replace this magic value by a macro. If I understand correctly your intent, this 31 value correspond to the maximum value which can be taken by your phase 1 register. So the correct code is:
int max_ph1_len = FIELD_MAX(REG_BTR_FD_PH1);
drivers/net/can/loongson_canfd.c line 636
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+u32 btr =0 ; + +if (loongson_canfd_enabled (priv)) { +netdev_err (ndev,"BUG! Cannot set bittiming - CAN is enabled\n" ); +return -EPERM ; + }
The framework should already prevent this from occuring. You can drop this check (and other similar checks) and change the return type to such functions to void.
If you were somehow able to reach trigger this function while the CAN device is enabled, let us know!
drivers/net/can/loongson_canfd.c line 639
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+if (nominal) + max_ph1_len =63 ;
It is disturbing to have the data bittiming value and the nominal bittiming value separated. Group them together. With the magic number replaced by the adequate macros, this gives you something like:
int ph1_max; /* ... */ if (nominal) ph1_max = FIELD_MAX(REG_BTR_PH1); else ph1_max = FIELD_MAX(REG_BTR_FD_PH1);
(while at it, I renamed to ph1_max because the this is not a length, so I am not sure why you put a _len suffix).
Quoted 107 lines
drivers/net/can/loongson_canfd.c new file +107
-0+/* +* 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); +
drivers/net/can/loongson_canfd.c line 757
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+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)
Rename this to loongson_canfd_set_ctrlmode(). Otherwhise there is a risk of confusion with loongson_canfd_do_set_mode()
Quoted 71 lines
drivers/net/can/loongson_canfd.c new file +71
-0+{ +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 )
drivers/net/can/loongson_canfd.c line 838
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-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);
Why do you need to set the mask to 0xFFFFFFFF? It seems that you are not even using it in loongson_canfd_set_mode(). Isn't it possible to directly pass priv->can.ctrlmode?
drivers/net/can/loongson_canfd.c line 851
Quoted 12 lines
drivers/net/can/loongson_canfd.c new file +12
-0+/* 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);
Nitpick: you can directly do:
regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, ~int_ena);
and remove your int_msk variable.
Quoted 95 lines
drivers/net/can/loongson_canfd.c new file +95
-0+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); +
drivers/net/can/loongson_canfd.c line 956
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+/* 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)));
^^^^^^^^^^
This cast is just wrong. What if the code is run on a big endian machine?
To begin with, here, you are writing to your registers. So it should be the other way around: cpu_to_le32(). And to add to it, if you need endian conversion, populate regmap_config.val_format_endian.
Also, why do you need some endian conversion only here and not on the other registers?
Quoted 90 lines
drivers/net/can/loongson_canfd.c new file +90
-0+ } + } + +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 ®_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 ®_FRAME_META1_FDF ) {
drivers/net/can/loongson_canfd.c line 1056
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+if (meta1 ®_FRAME_META1_BRS ) + cf->flags |=CANFD_BRS ; + +if (meta0 ®_FRAME_META0_ESI ) + cf->flags |=CANFD_ESI ; + }else if (meta0 ®_FRAME_META0_RTR ) { + cf->can_id |=CAN_RTR_FLAG ; + } + +/* Timesamp */
^^^^^^^^
Typo: timestamp.
drivers/net/can/loongson_canfd.c line 1058
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+ cf->__res0 = meta1; + cf->__res1 = meta1 >>8 ;
No, you can not use the canfd_frame->__res0 and canfd_frame->__res1 fields at all. These are *reserved*. Refer to what the other CAN drivers are doing for the hardware timestamps and use the existing framework.
Quoted 290 lines
drivers/net/can/loongson_canfd.c new file +290
-0+ 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 ®_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 ®_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 ®_INT_STAT_FCSI ) || (isr ®_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 ®_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 ®_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 ®_STAT_DOR ) { +struct net_device_stats *stats = &ndev->stats; +struct can_frame *cf; +struct sk_buff *skb; +
drivers/net/can/loongson_canfd.c line 1359
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+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;
The socket CAN error frames do not correspond to actual frames on the bus. Do not increase stats->rx_packets and stats->rx_bytes.
Quoted 91 lines
drivers/net/can/loongson_canfd.c new file +91
-0+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)
drivers/net/can/loongson_canfd.c line 1460
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+{ +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 ;
if (irq_loops) return IRQ_HANDLED; else return IRQ_NONE;
Quoted 126 lines
drivers/net/can/loongson_canfd.c new file +126
-0+ +/* Receive Buffer Not Empty Interrupt */ +if (isr ®_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 ®_INT_STAT_TXBHCI ) +loongson_canfd_tx_interrupt (ndev); + +/* Error interrupts */ + imask = isr ®_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 ®_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);
drivers/net/can/loongson_canfd.c line 1596
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+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, +};
Also add a struct ethtool_ops and populate
ethtool_ops.get_ts_info. Something like:
static const struct ethtool_ops es58x_ethtool_ops = {
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
};Refer to what the other CAN drivers with hardware timestamps are doing.
Quoted 104 lines
drivers/net/can/loongson_canfd.c new file +104
-0+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;
drivers/net/can/loongson_canfd.c line 1711
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+ 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 ;
Does your device allow to send and receive Classical CAN frames with a DLC greater than 8? c.f. CAN_CTRLMODE_CC_LEN8_DLC.
Quoted 44 lines
drivers/net/can/loongson_canfd.c new file +44
-0+ 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,
drivers/net/can/loongson_canfd.c line 1766
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+ .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" );
Yours sincerely,
Vincent Mailhol
Re: [PATCH v2 1/2] can: Add Loongson CAN-FD controller driver
Hi Vincent:
Thanks for your detailed review and sorry for the late reply.
Quoted 634 lines · Vincent Mailhol
Quoted 600 lines · 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 bitratesCo-developed-by Bingxiong Li <[email protected]>Signed-off-by Bingxiong Li <[email protected]>Signed-off-by Binbin Zhou <[email protected]>--- 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.cMAINTAINERS +7
-0@@ -14935,6 +14935,13 @@ F: arch/loongarch/ F: drivers/*/*loongarch* F: drivers/cpufreq/loongson3_cpufreq.c +LOONGSON CAN FD DRIVER +M: Bingxiong Li <[email protected]> +M: Binbin Zhou <[email protected]> +L: [email protected] +S: Maintained +F: drivers/net/can/loongson_canfd.c + LOONGSON GPIO DRIVER M: Yinbo Zhu <[email protected]> L: [email protected]drivers/net/can/Kconfig +15
-0@@ -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 TTYdrivers/net/can/Makefile +1
-0@@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd/ +obj-$(CONFIG_CAN_LOONGSON_CANFD) += loongson_canfd.o obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_M_CAN) += m_can/ obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/drivers/net/can/loongson_canfd.c new file +515
-0@@ -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 ;drivers/net/can/loongson_canfd.c line 525
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+break ; +case 7 : + mask =REG_TX_STAT_BS_TX7 ; +break ; + } + +regmap_read (priv->regmap,LOONGSON_CANFD_TX_STAT , &sts); + +return field_get (mask, sts); +}I think it is easier to compute the mask than doing this switch case. Maybe something like this:
#define REG_TX_STAT_BS_TX_BASE 16 /* ... */ static enum loongson_canfd_txbuf_sts loongson_canfd_get_txbuf_sts(struct loongson_canfd_priv *priv, u8 buf_id) { u32 mask, sts; mask = GENMASK(REG_TX_STAT_BS_TX_BASE + 2 * buf_id + 1, REG_TX_STAT_BS_TX_BASE + 2 * buf_id); regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &sts); return field_get(mask, sts); }Or equivalent:
Quoted 14 lines
#define REG_TX_STAT_BS_TX_MASK_BASE GENMASK(17, 16)
/* ... */
static enum loongson_canfd_txbuf_sts
loongson_canfd_get_txbuf_sts(struct loongson_canfd_priv *priv, u8 buf_id)
{
u32 mask, sts;
mask = REG_TX_STAT_BS_TX_MASK_BASE << 2 * buf_id;
regmap_read(priv->regmap, LOONGSON_CANFD_TX_STAT, &sts);
return field_get(mask, sts);
}Yes, this way is much clearer and more concise.
Quoted 68 lines
Quoted 68 lines
drivers/net/can/loongson_canfd.c new file +67
-0+/** +* 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 :
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 598
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+netdev_err (ndev,"Unknown command id: %x\n" , cmd); +return ; + } + +regmap_write (priv->regmap,LOONGSON_CANFD_TX_CMD ,field_prep (mask,0x1 << buf_id));^^^^^^^^^^^^^ Nitpick: regmap_write(priv->regmap, LOONGSON_CANFD_TX_CMD, field_prep(mask, BIT(buf_id)));
ok.
Quoted 10 lines
drivers/net/can/loongson_canfd.c line 605
Quoted 8 lines
drivers/net/can/loongson_canfd.c new file +7
-0+} + +/** +* 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 ^^^^^^^^^^^This part of the documentation does not match the code.
This function appears to not require a return value; void should suffice.
Quoted 44 lines
Quoted 15 lines
drivers/net/can/loongson_canfd.c new file +14
-0+*/ +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 drivers/net/can/loongson_canfd.c line 629
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+* @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;No need for those
phase_seg1andprop_segvariables. Directly do the math onbt->phase_seg1andbt->prop_seg.drivers/net/can/loongson_canfd.c line 630
Quoted 1 line
drivers/net/can/loongson_canfd.c new file +1
-0+int max_ph1_len =31 ;Replace this magic value by a macro. If I understand correctly your intent, this 31 value correspond to the maximum value which can be taken by your phase 1 register. So the correct code is:
int max_ph1_len = FIELD_MAX(REG_BTR_FD_PH1);drivers/net/can/loongson_canfd.c line 636
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+u32 btr =0 ; + +if (loongson_canfd_enabled (priv)) { +netdev_err (ndev,"BUG! Cannot set bittiming - CAN is enabled\n" ); +return -EPERM ; + }
Quoted 6 lines
The framework should already prevent this from occuring. You can drop this check (and other similar checks) and change the return type to such functions to void.
If you were somehow able to reach trigger this function while the CAN device is enabled, let us know!
Just drop it, and the function’s return type can be changed to void.
Quoted 17 lines
drivers/net/can/loongson_canfd.c line 639
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +2
-0+if (nominal) + max_ph1_len =63 ;It is disturbing to have the data bittiming value and the nominal bittiming value separated. Group them together. With the magic number replaced by the adequate macros, this gives you something like:
int ph1_max; /* ... */ if (nominal) ph1_max = FIELD_MAX(REG_BTR_PH1); else ph1_max = FIELD_MAX(REG_BTR_FD_PH1);
Quoted 2 lines
(while at it, I renamed to
ph1_maxbecause the this is not a length, so I am not sure why you put a_lensuffix).
This was my mistake; this part of the code wasn’t updated in sync. The bit fields for these two registers differed in older versions of the controller, but they are now consistent—please see the relevant macro definitions.
Therefore, try modifying it as follows:
u32 ph1_max = FIELD_MAX(REG_BTR_PH1);
u32 btr = 0;
/*
* 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 7 bits wide but PH1 only 6, so we must
* re-distribute the values here.
*/
if (bt->phase_seg1 > ph1_max) {
bt->prop_seg += bt->phase_seg1 - ph1_max;
bt->phase_seg1 = ph1_max;
}Quoted 113 lines
Quoted 113 lines
drivers/net/can/loongson_canfd.c new file +112
-0+/* +* 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
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 757
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+* @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)Rename this to
loongson_canfd_set_ctrlmode(). Otherwhise there is a risk of confusion withloongson_canfd_do_set_mode()
Actually, this function sets the LOONGSON_CANFD_MODE and LOONGSON_CANFD_CONF registers based on priv->can.ctrlmode.
How about rewriting it as follows:
static void loongson_canfd_set_confmode(struct loongson_canfd_priv *priv)
{
u32 ctrlmode = priv->can.ctrlmode;.....
}
Quoted 78 lines
Quoted 78 lines
drivers/net/can/loongson_canfd.c new file +77
-0+{ +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; +
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 838
Quoted 4 lines
drivers/net/can/loongson_canfd.c new file +4
-0+/* Configure modes */ + mode.flags = priv->can.ctrlmode; + mode.mask =0xFFFFFFFF ; +loongson_canfd_set_mode (priv, &mode);Why do you need to set the mask to
0xFFFFFFFF? It seems that you are not even using it inloongson_canfd_set_mode(). Isn't it possible to directly passpriv->can.ctrlmode?
As mentioned earlier, discard mode and use priv->can.ctrlmode directly.
Quoted 16 lines
drivers/net/can/loongson_canfd.c line 851
Quoted 13 lines
drivers/net/can/loongson_canfd.c new file +12
-0+/* 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);Nitpick: you can directly do:
Quoted 3 lines
regmap_write(priv->regmap, LOONGSON_CANFD_INT_MASK, ~int_ena);and remove your
int_mskvariable.
OK..
Quoted 110 lines
Quoted 96 lines
drivers/net/can/loongson_canfd.c new file +95
-0+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); +drivers/net/can/loongson_canfd.c line 956
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+/* 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)));^^^^^^^^^^This cast is just wrong. What if the code is run on a big endian machine?
Quoted 6 lines
To begin with, here, you are writing to your registers. So it should be the other way around:
cpu_to_le32(). And to add to it, if you need endian conversion, populate regmap_config.val_format_endian.Also, why do you need some endian conversion only here and not on the other registers?
Sorry, this is the old test code—I forgot to update it. Just use u32:
for (i = 0; i < len; i += LOONGSON_CANFD_DW_BYTE)
regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, (u32
*)(cf->data + i));
Quoted 407 lines
Quoted 91 lines
drivers/net/can/loongson_canfd.c new file +90
-0+ } + } + +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 ®_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 ®_FRAME_META1_FDF ) {drivers/net/can/loongson_canfd.c line 1056
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+if (meta1 ®_FRAME_META1_BRS ) + cf->flags |=CANFD_BRS ; + +if (meta0 ®_FRAME_META0_ESI ) + cf->flags |=CANFD_ESI ; + }else if (meta0 ®_FRAME_META0_RTR ) { + cf->can_id |=CAN_RTR_FLAG ; + } + +/* Timesamp */ ^^^^^^^^Typo: timestamp.
drivers/net/can/loongson_canfd.c line 1058
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+ cf->__res0 = meta1; + cf->__res1 = meta1 >>8 ;No, you can not use the
canfd_frame->__res0andcanfd_frame->__res1fields at all. These are *reserved*. Refer to what the other CAN drivers are doing for the hardware timestamps and use the existing framework.Quoted 295 lines
drivers/net/can/loongson_canfd.c new file +295
-0+ 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 ®_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 ®_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 ®_INT_STAT_FCSI ) || (isr ®_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 ®_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 ®_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 ®_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);
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 1359
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+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;The socket CAN error frames do not correspond to actual frames on the bus. Do not increase
stats->rx_packetsandstats->rx_bytes.
OK.
Quoted 99 lines
Quoted 99 lines
drivers/net/can/loongson_canfd.c new file +98
-0+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 */
Quoted 9 lines
drivers/net/can/loongson_canfd.c line 1460
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+regmap_read (priv->regmap,LOONGSON_CANFD_INT_STAT , &isr); +if (!isr) +return irq_loops ?IRQ_HANDLED :IRQ_NONE ;if (irq_loops) return IRQ_HANDLED; else return IRQ_NONE;
Emm...
Is the ternary operator here more concise than if-else?
if (!isr) {
if (irq_loops)
return IRQ_HANDLED;
else
return IRQ_NONE;
}vs
if (!isr)
return irq_loops ? IRQ_HANDLED : IRQ_NONE;Quoted 140 lines
Quoted 126 lines
drivers/net/can/loongson_canfd.c new file +126
-0+ +/* Receive Buffer Not Empty Interrupt */ +if (isr ®_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 ®_INT_STAT_TXBHCI ) +loongson_canfd_tx_interrupt (ndev); + +/* Error interrupts */ + imask = isr ®_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 ®_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);drivers/net/can/loongson_canfd.c line 1596
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+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, +};Also add a struct
ethtool_opsand populate
ethtool_ops.get_ts_info. Something like:
Quoted 6 lines
static const struct ethtool_ops es58x_ethtool_ops = { .get_ts_info = can_ethtool_op_get_ts_info_hwts, };Refer to what the other CAN drivers with hardware timestamps are doing.
Regarding the hardware timestamp, could this be submitted as a separate feature patch? I need some time to resolve the related issues.
Could we proceed as follows for now:
static const struct ethtool_ops loongson_canfd_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
Quoted 110 lines
Quoted 110 lines
drivers/net/can/loongson_canfd.c new file +109
-0+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; +
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 1711
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+ 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 ;Does your device allow to send and receive Classical CAN frames with a DLC greater than 8? c.f.
CAN_CTRLMODE_CC_LEN8_DLC.
I've checked and tested it, and the controller supports this mode. I'll add this feature.
Quoted 51 lines
Quoted 51 lines
drivers/net/can/loongson_canfd.c new file +50
-0+ 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);
Quoted 8 lines
drivers/net/can/loongson_canfd.c line 1766
Quoted 4 lines
drivers/net/can/loongson_canfd.c new file +4
-0+ +MODULE_AUTHOR ("Loongson Technology Corporation Limited" ); +MODULE_DESCRIPTION ("Loongson CAN-FD Controller driver" ); +MODULE_LICENSE ("GPL" );Yours sincerely,
Vincent Mailhol
--
Thanks.
Binbin
Vincent Mailhol
maintainerRe: [PATCH v2 1/2] can: Add Loongson CAN-FD controller driver
Quoted 7 lines · Binbin Zhou
Hi Vincent:
Thanks for your detailed review and sorry for the late reply.
Quoted 2 lines · Vincent Mailhol
On 08/06/2026 at 10:49, Binbin Zhou wrote:
(...)
Quoted 9 lines
Quoted 5 lines
drivers/net/can/loongson_canfd.c line 757
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+static void loongson_canfd_set_mode (struct loongson_canfd_priv *priv, +const struct can_ctrlmode *ctrlmode)Rename this to
loongson_canfd_set_ctrlmode(). Otherwhise there is a risk of confusion withloongson_canfd_do_set_mode()Actually, this function sets the
LOONGSON_CANFD_MODEandLOONGSON_CANFD_CONFregisters based onpriv->can.ctrlmode.
Quoted 7 lines
How about rewriting it as follows:
static void
loongson_canfd_set_confmode(struct loongson_canfd_priv *priv){ u32 ctrlmode = priv->can.ctrlmode;.....
}
That also works. My point was to avoid the confusion with loongson_canfd_do_set_mode(). As long as there is enough disambiguation, it is OK for me.
(...)
Quoted 14 lines
Quoted 14 lines
drivers/net/can/loongson_canfd.c line 956
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+/* 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)));^^^^^^^^^^This cast is just wrong. What if the code is run on a big endian machine?
To begin with, here, you are writing to your registers. So it should be the other way around:
cpu_to_le32(). And to add to it, if you need endian conversion, populate regmap_config.val_format_endian.
Quoted 8 lines
Quoted 2 lines
Also, why do you need some endian conversion only here and not on the other registers?
Sorry, this is the old test code—I forgot to update it. Just use
u32:for (i = 0; i < len; i +=
LOONGSON_CANFD_DW_BYTE)regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, (u32*)(cf->data + i));
OK. Note that I don't mind if you want to keep the declaration of i in the for loop:
for (unsigned int i = 0; i < len; i += LOONGSON_CANFD_DW_BYTE)
/* ... */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+ } + } + +return true; +}
(...)
Quoted 20 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/can/loongson_canfd.c new file +8
-0+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 */ Quoted 9 lines
drivers/net/can/loongson_canfd.c line 1460
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+regmap_read (priv->regmap,LOONGSON_CANFD_INT_STAT , &isr); +if (!isr) +return irq_loops ?IRQ_HANDLED :IRQ_NONE ;if (irq_loops) return IRQ_HANDLED; else return IRQ_NONE;Emm...
Is the ternary operator here more concise thanif-else?
Quoted 6 lines
if (!isr) {
if (irq_loops)
return IRQ_HANDLED;
else
return IRQ_NONE;
}Unless you are getting an actual checkpatch.pl warning here, if I record correctly, the curly brackets can be ommitted here:
if (!isr) if (irq_loops) return IRQ_HANDLED; else return IRQ_NONE;
Quoted 4 lines
vs
if (!isr) return irq_loops ? IRQ_HANDLED : IRQ_NONE;
Yes, it is more consise, but is it more readable?
Actually, you might say that which one is the most readable is a subjective topic and you would be right.
But it is the prefered style here. The indentation of the if/else makes it more visual. And when you review thousands of line of code, it starts to make a difference.
And I this is not my personnal opinion. For example, see this message from Greg:
https://lore.kernel.org/all/20250311150130.7a875e63@bahia/
So, even if this is an arguable case, let this be an if/else.
(...)
Quoted 16 lines
Quoted 9 lines
drivers/net/can/loongson_canfd.c line 1596
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-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, +};Also add a struct
ethtool_opsand populate
ethtool_ops.get_ts_info. Something like:Quoted 6 lines
static const struct ethtool_ops es58x_ethtool_ops = { .get_ts_info = can_ethtool_op_get_ts_info_hwts, };Refer to what the other CAN drivers with hardware timestamps are doing.
Quoted 8 lines
Regarding the hardware timestamp, could this be submitted as a separate feature patch? I need some time to resolve the related issues.
Could we proceed as follows for now:static const struct
ethtool_opsloongson_canfd_ethtool_ops= {
.get_ts_info =ethtool_op_get_ts_info,
};
OK, but make sure to remove all your local hacks. We will not accept the use of the reserved fields in sturct canfd_frame for that.
Note that once you undertsand the timestamp framework, I would expect the patch to be rather tiny.
Yours sincerely,
Vincent Mailhol
[email protected]
AI reviewRe: [PATCH v2 1/2] can: Add Loongson CAN-FD controller driver
In reply to Binbin ZhouThank you for your contribution! Sashiko AI review found 14 potential issue(s) to consider: - [Critical] Missing bounds checks on the hardware-provided RX word count (`RWCNT`) causes severe heap…
Thank you for your contribution! Sashiko AI review found 14 potential issue(s) to consider:
- [Critical] Missing bounds checks on the hardware-provided RX word count (RWCNT) causes severe heap buffer overflow.
- [High] Uninitialized variable buf_id in loongson_canfd_start_xmit() causes packet drops and potential out-of-bounds array access.
- [High] Unhandled Bus Error Interrupts (BEI) and overwritten ISR variables lead to permanent loss of interrupts and device lockup.
- [High] Missing NULL pointer check in CAN_STATE_ERROR_ACTIVE handling causes a kernel panic.
- [High] Failing to drain the RX FIFO upon SKB allocation failure permanently desynchronizes the controller's packet stream.
- [High] Incorrect NAPI exit logic causes list corruption when work_done == quota.
- [High] The NAPI poll loop permanently stalls the RX path if loongson_canfd_rx() encounters an error.
- [High] Race condition in driver initialization permanently drops RX capability if an interrupt fires early.
- [High] The driver misuses strictly reserved SocketCAN UAPI fields, corrupting the length indicator for Classic CAN frames.
- [High] Syntax Error: Declarations immediately follow a label, violating C11 standard requirements.
- [High] The driver violates the SocketCAN standard by prematurely resetting the hardware error counters upon entering BUS_OFF.
- [Medium] Incorrect logic in loongson_canfd_txbuf_freed forces a strict queue depth of 1, severely degrading transmission throughput.
- [Medium] Polling of MMIO asynchronous TX status without proper flow control risks processing the same transmission multiple times.
- [Medium] Lost increments on stats->rx_errors across softirq and hardirq contexts.
--
commit da73fa842fa0bacd63f1ec58f9a813c7b28476d3
Author: Binbin Zhou <[email protected]>
Subject: can: Add Loongson CAN-FD controller driver
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.).
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +0
-0
[ ... ]
drivers/net/can/loongson_canfd.c line 481
Quoted 4 lines
drivers/net/can/loongson_canfd.c new file +4
-0+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 ); +}
[Severity: Medium]
Does this logic overly restrict the transmission queue? Since regmap_test_bits() returns true if ANY bit is set in the mask, checking it with ! means this returns true only when ALL hardware buffers are completely free. This forces a strict queue depth of 1 and prevents utilizing the 8-buffer hardware pipeline.
[ ... ]
drivers/net/can/loongson_canfd.c line 1007
Quoted 10 lines
drivers/net/can/loongson_canfd.c new file +10
-0+for_each_clear_bit (i, &tx_brp,LOONGSON_CANFD_TXBUF_NUM ) { +u32 transmission_complete_mask =0x3 << (i *2 ); + +if (!(tx_bs & transmission_complete_mask)) { + buf_id = i; +break ; + } + } + +if (!loongson_canfd_insert_frame (priv, cf, buf_id,can_is_canfd_skb (skb))) {
[Severity: High]
What happens in loongson_canfd_start_xmit() if the conditional !(tx_bs & transmission_complete_mask) is false for all clear bits?
The loop would exit without assigning a value to buf_id. Passing an uninitialized buf_id to loongson_canfd_insert_frame() could lead to silent packet drops or unpredictable out-of-bounds array access.
[ ... ]
drivers/net/can/loongson_canfd.c line 1058
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+/* Timesamp */ + cf->__res0 = meta1; + cf->__res1 = meta1 >>8 ;
[Severity: High]
Is it safe to write to cf->__res1 here?
For Classic CAN frames, alloc_can_skb() returns a struct can_frame where the offset of __res1 physically aliases with the len8_dlc field. Overwriting this memory corrupts the length indicator for 8-byte frames in the upstream networking stack.
[ ... ]
drivers/net/can/loongson_canfd.c line 1076
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+ 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 ) {
[Severity: Critical]
Is it possible for the hardware-provided RX word count to exceed expected bounds here?
The wc variable is derived from RWCNT - 2. If RWCNT is large, len could exceed CANFD_MAX_DLEN, leading to a massive buffer overflow when writing directly into cf->data. Furthermore, if RWCNT is 0 or 1, wc would underflow, resulting in an infinite loop and massive memory corruption.
[ ... ]
drivers/net/can/loongson_canfd.c line 1117
Quoted 7 lines
drivers/net/can/loongson_canfd.c new file +7
-0+/* Flexible Data-rate Format */ +if (meta1 ®_FRAME_META1_FDF ) + skb =alloc_canfd_skb (ndev, &cf); +else + skb =alloc_can_skb (ndev, (struct can_frame **)&cf); +if (unlikely (!skb)) +return -ENOMEM ;
[Severity: High]
If this allocation fails, loongson_canfd_rx() returns early without draining the remaining data payload words for this frame from the RX FIFO. Will this leave unread payload words in the stream that get mistakenly parsed as metadata headers for the next frame, permanently misaligning the parser?
[ ... ]
drivers/net/can/loongson_canfd.c line 1142
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+switch (FIELD_GET (REG_FSTAT_MASK , fstat)) { +case REG_FSTAT_ERA : +u32 ewl, erl, rec_tec, max_tec;
[Severity: High]
Does this compile? Under the C11 standard (-std=gnu11), a label cannot be followed immediately by a variable declaration. This needs to be wrapped in a block or the variables must be declared earlier.
[ ... ]
drivers/net/can/loongson_canfd.c line 1246
Quoted 5 lines
drivers/net/can/loongson_canfd.c new file +5
-0+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;
[Severity: High]
Overwriting the isr variable here discards any other concurrent interrupt flags (such as REG_INT_STAT_ALI) that were present. Since this function later writes the overwritten isr value to LOONGSON_CANFD_INT_MASK, does this permanently fail to unmask those erased interrupts?
drivers/net/can/loongson_canfd.c line 1252
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+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 );
[Severity: High]
Does issuing a hardware reset immediately upon detecting BUS_OFF bypass the standard CAN bus backoff mechanism?
The kernel's CAN core manages the auto-restart delay using a timer for restart_ms. Resetting the controller's error counters here causes it to rejoin the bus immediately, bypassing the configured recovery delay.
[ ... ]
drivers/net/can/loongson_canfd.c line 1284
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+case CAN_STATE_ERROR_ACTIVE : + cf->can_id |=CAN_ERR_CNT ; + cf->data[1 ] =CAN_ERR_CRTL_ACTIVE ;
[Severity: High]
If alloc_can_err_skb() failed earlier due to memory pressure, cf will be NULL here. The other error state cases guard their writes with if (skb), but this case writes unconditionally, which would cause a kernel panic.
[ ... ]
drivers/net/can/loongson_canfd.c line 1311
Quoted 6 lines
drivers/net/can/loongson_canfd.c new file +6
-0+/* Check for Bus Error interrupt */ +if (isr ®_INT_STAT_BEI ) { + isr =REG_INT_STAT_BEI ; +netdev_err (ndev,"Bus Error interrupt\n" ); + priv->can.can_stats.bus_error++; + stats->rx_errors++;
[Severity: Medium]
Could this increment of stats->rx_errors race with the identical increment in loongson_canfd_rx_napi()?
This runs in hardirq context, while the other runs in softirq context. A hardirq interrupting the softirq's read-modify-write cycle on the exact same statistic could cause the hardirq's increment to be overwritten and lost.
[ ... ]
drivers/net/can/loongson_canfd.c line 1337
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+while (rx_frc && work_done < quota && ret >0 ) { + ret =loongson_canfd_rx (ndev);
[Severity: High]
If loongson_canfd_rx() encounters an error (e.g. -ENOMEM), ret becomes negative and the loop terminates early. Because rx_frc remains non-zero, the logic below will skip napi_complete_done() and return work_done < quota.
Returning less than the quota without completing NAPI puts it into an invalid state, removing the device from the poll list but leaving the SCHED bit set, which will silently stall the RX path.
[ ... ]
drivers/net/can/loongson_canfd.c line 1352
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+netdev_info (ndev,"Loongson canfd RX overflow\n" ); + stats->rx_over_errors++; + stats->rx_errors++;
[Severity: Medium]
As mentioned earlier, could this unprotected increment in softirq context race with the identical increment in the hardirq error handler, resulting in lost updates to stats->rx_errors?
[ ... ]
drivers/net/can/loongson_canfd.c line 1368
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+if (!rx_frc && ret !=0 ) { +if (napi_complete_done (napi, work_done)) {
[Severity: High]
Is it safe to call napi_complete_done() when work_done equals quota?
If the FIFO happens to empty on exactly the last frame of the budget, this will call napi_complete_done() and still return quota to the caller. Returning quota indicates to the core networking stack that the driver consumed its budget and remains scheduled, but napi_complete_done() detaches it from the poll list, leading to list corruption.
[ ... ]
drivers/net/can/loongson_canfd.c line 1393
Quoted 4 lines
drivers/net/can/loongson_canfd.c new file +4
-0+guard (spinlock_irqsave)(&priv->tx_lock); + +while ((buf_id =loongson_canfd_get_txbuf_id (priv, &sts)) <LOONGSON_CANFD_TXBUF_NUM ) { +switch (sts) {
[Severity: Medium]
Could this tight loop re-process the exact same TX buffer multiple times?
The loop sends a hardware clean command (TXT_CMD_SR_CLEAN) at the end of the iteration and immediately polls the live status via loongson_canfd_get_txbuf_id() on the next pass. Since MMIO propagation may take multiple cycles, the read might fetch the un-cleared stale status, leading to redundant register writes and double increments of stats->tx_packets.
drivers/net/can/loongson_canfd.c line 1399
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+case TX_BS_FAIL : +u32 cnt;
[Severity: High]
Similar to the error handler earlier, does this code compile under C11? A variable declaration immediately following a case label is a syntax error.
[ ... ]
drivers/net/can/loongson_canfd.c line 1478
Quoted 2 lines
drivers/net/can/loongson_canfd.c new file +2
-0+/* Error interrupts */ + imask = isr ®_INT_STAT_ERRORI ;
[Severity: High]
Does this logic handle Bus Error Interrupts (BEI) correctly?
REG_INT_STAT_BEI is enabled during setup, but it is not included in the REG_INT_STAT_ERRORI mask. Consequently, if a BEI fires, imask evaluates to 0, skipping the handler and failing to clear the interrupt in the hardware, which would generate an interrupt storm and lock up the device.
[ ... ]
drivers/net/can/loongson_canfd.c line 1562
Quoted 3 lines
drivers/net/can/loongson_canfd.c new file +3
-0+netdev_info (ndev,"loongson_canfd_device registered\n" ); +napi_enable (&priv->napi); +netif_start_queue (ndev);
[Severity: High]
Is there a race condition between unmasking the hardware interrupts and enabling NAPI?
loongson_canfd_chip_start() fully arms the hardware interrupts before napi_enable() is called. If a frame is received in this narrow window, the ISR will fire, mask the interrupt, and call napi_schedule(). Since NAPI is still disabled, the schedule request is silently ignored. When napi_enable() subsequently executes, the interrupt remains masked, resulting in a completely dead RX path.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
PATCH v2 2/2 can: loongson_canfd: Add RXDMA support
In reply to Binbin ZhouAdd 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.
--- drivers/net/can/Kconfig | 2 +- drivers/net/can/loongson_canfd.c | 209 ++++++++++++++++++++++++++++--- 2 files changed, 190 insertions(+), 21 deletions(-)
drivers/net/can/Kconfig +1 -1
@@ -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,
drivers/net/can/loongson_canfd.c +189 -20
341 lines not on this page · raw message
Signature · 1 line
2.52.0
Vincent Mailhol
maintainerRe: [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
Quoted 10 lines · 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
Quoted 7 lines
This significantly reduces CPU intervention under high RX load, especially beneficial for CAN FD at higher data rates.
Co-developed-by Bingxiong Li <[email protected]>Signed-off-by Bingxiong Li <[email protected]>Signed-off-by Binbin Zhou <[email protected]>---
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 */
| ^~~~~~~~~~~~~~~~~~~~~~~~~Quoted 9 lines
drivers/net/can/Kconfig | 2 +- drivers/net/can/loongson_canfd.c | 209 ++++++++++++++++++++++++++++--- 2 files changed, 190 insertions(+), 21 deletions(-)drivers/net/can/Kconfig +0
-0
drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 194
Quoted 5 lines
drivers/net/can/Kconfig +1
-1@@ -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.
drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 197
Quoted 3 lines
drivers/net/can/Kconfig +0
-0select REGMAP_MMIO help This is a canfd driver switch for the Loongson platform,
Yours sincerely,
Vincent Mailhol
Re: [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
Hi Vincent:
Thanks for your detailed review and sorry for my late reply.
Quoted 15 lines · Vincent Mailhol
Quoted 13 lines · 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 availabilityThis significantly reduces CPU intervention under high RX load, especially beneficial for CAN FD at higher data rates.
Quoted 6 lines
Quoted 4 lines
Co-developed-by Bingxiong Li <[email protected]>Signed-off-by Bingxiong Li <[email protected]>Signed-off-by Binbin Zhou <[email protected]>---
Please check the W=2 warnings:
OK. I usually compile with W=1 and didn't notice these issues.
Quoted 32 lines
$ 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;Quoted 8 lines
| ^~~
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 */
| ^~~~~~~~~~~~~~~~~~~~~~~~Regarding the definitions of these controller registers, even though they aren’t currently referenced, can they be retained to make the code seem more complete?
Quoted 487 lines
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 */ | ^~~~~~~~~~~~~~~~~~~~~~~~~Quoted 9 lines
drivers/net/can/Kconfig | 2 +- drivers/net/can/loongson_canfd.c | 209 ++++++++++++++++++++++++++++--- 2 files changed, 190 insertions(+), 21 deletions(-)drivers/net/can/Kconfig +0
-0drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 194
Quoted 5 lines
drivers/net/can/Kconfig +1
-1@@ -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_TESTedwithoutHAS_IOMEM, then patch 1 should be:depends on HAS_IOMEM || COMPILE_TESTand patch 2 should be:
depends on (HAS_IOMEM && LOONGSON2_APB_CMC_DMA) || COMPILE_TEST
Quoted 8 lines
If your driver need
HAS_IOMEMeven for a compile test, then patch 1 should be:depends on
HAS_IOMEMand patch 2 should be:
depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)
For me, the 2nd way is correct.
Quoted 10 lines
Here, you are doing a weird mix.
drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 197
Quoted 3 lines
drivers/net/can/Kconfig +0
-0select REGMAP_MMIO help This is a canfd driver switch for the Loongson platform,Yours sincerely,
Vincent Mailhol
--
Thanks.
Binbin
Vincent Mailhol
maintainerRe: [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
Quoted 20 lines · Binbin Zhou
Hi Vincent:
Thanks for your detailed review and sorry for my late reply.
Quoted 15 lines · Vincent Mailhol
Quoted 13 lines · 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 availabilityThis significantly reduces CPU intervention under high RX load, especially beneficial for CAN FD at higher data rates.
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Co-developed-by Bingxiong Li <[email protected]>Signed-off-by Bingxiong Li <[email protected]>Signed-off-by Binbin Zhou <[email protected]>---
Please check the W=2 warnings:
OK. I usually compile with
W=1and didn't notice these issues.
The W=2 used to be too spammy and people simply ignored it. I went through a quest to reduce that noise. See
660e899103e2 ("kbuild: remove gcc's -Wtype-limits")
with this, the output is less bloated and I think a bit more useful. Not that you need to systematically address all warnings, but at least, review the list.
Quoted 40 lines
Quoted 31 lines
$ 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;Quoted 8 lines
| ^~~ 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 */ | ^~~~~~~~~~~~~~~~~~~~~~~~
Quoted 3 lines
Regarding the definitions of these controller registers, even though they aren’t currently referenced, can they be retained to make the code seem more complete?
Only keep the registers for features which are not yet implemented. For the register which are already handled in a different way without relying on the macro, please remove.
I can think, for example, of:
LOONGSON_CANFD_TX_DATA_10
You handled the tx data in a for loop and this macro is purely dead and do not serve anymore documentation purpose. The only thing it does now is to add confusion.
(...)
Quoted 17 lines
Quoted 17 lines
drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 194
Quoted 4 lines
config
CAN_LOONGSON_CANFD
tristate "Loongson CAN-FD controller"drivers/net/can/Kconfig +1
-1- 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_TESTedwithoutHAS_IOMEM, then patch 1 should be:depends on HAS_IOMEM || COMPILE_TESTand patch 2 should be:
depends on (HAS_IOMEM && LOONGSON2_APB_CMC_DMA) || COMPILE_TESTIf your driver need
HAS_IOMEMeven for a compile test, then patch 1 should be:
Quoted 7 lines
Quoted 5 lines
depends on
HAS_IOMEMand patch 2 should be:
depends on HAS_IOMEM && (LOONGSON2_APB_CMC_DMA || COMPILE_TEST)For me, the 2nd way is correct.
Ack.
Just for confirmation, do you think that your device will ever be used in production on a board which would not have LOONGSON2_APB_CMC_DMA? If yes, it could make sense to add the RXDMA as a separate module. Otherwise, it is good as-is.
Quoted 6 lines
Quoted 6 lines
Here, you are doing a weird mix.
Quoted 3 lines
select
REGMAP_MMIO
help
This is a canfd driver switch for the Loongson platform,
Yours sincerely,
Vincent Mailhol
[email protected]
AI reviewRe: [PATCH v2 2/2] can: loongson_canfd: Add RXDMA support
In reply to Binbin ZhouThank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
New issues:
- [Critical] Incorrect teardown order causes Use-After-Free and DMA memory corruption.
- [Critical] Flawed DMA synchronization logic leads to data corruption and complete pointer desynchronization.
- [High] Uninitialized variable ret returned on probe failure leads to random probe status.
- [High] Memory leak of DMA buffer and unterminated cyclic transfer on probe failure.
- [Medium] Probe incorrectly aborted on DMA initialization failure instead of falling back to PIO.
- [Medium] Artificial Kconfig dependency arbitrarily breaks driver functionality on systems without the Loongson DMA driver.
Pre-existing issues:
- [High] Memory allocation failure causes a permanent NAPI hang.
- [High] Missing bounds check on frame payload length allows heap buffer overflow. --
commit 33782565e156b12b3812d0b21ca4a945e50adf11
Author: Bingxiong Li <[email protected]>
Add optional DMA support for RX path using the Loongson APB CMC DMA engine
This patch adds optional DMA support for the RX path in the Loongson CAN-FD driver. It requests a DMA channel and uses cyclic transfers to directly write incoming frames to a coherent buffer, falling back to PIO mode if unavailable.
drivers/net/can/Kconfig config CAN_KVASER_PCIEFD · line 194
Quoted 9 lines
drivers/net/can/Kconfig +1
-1@@ -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)
[Severity: Medium]
Does this introduce a hard dependency that unnecessarily breaks compilation for systems that only want to use PIO mode? Because the driver uses the generic dmaengine framework, there shouldn't be a strict compile-time requirement on the specific LOONGSON2_APB_CMC_DMA module.
[ ... ]
Quoted 4 lines
drivers/net/can/loongson_canfd.c +0
-0@@ -614,6 +632,125 @@ static int loongson_canfd_reset(struct net_device *ndev)
[ ... ]
drivers/net/can/loongson_canfd.c static int loongson_canfd_reset(struct net_device *ndev) · line 667
Quoted 10 lines
drivers/net/can/loongson_canfd.c +10
-0+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 ); +}
[Severity: Critical]
Does this cause data corruption by triggering reads for partial DMA transfers?
If the DMA engine writes just a single word, this condition evaluates to true, but loongson_canfd_rx() will unconditionally read an entire frame consisting of multiple words. If the CPU outpaces the DMA transfer, could it read stale unwritten memory and permanently desynchronize the pointers?
Also, when residue reaches 0, does rx_frc != 0 evaluate to true indefinitely because rx_frc wraps from 1 to LOONGSON_CANFD_RXDMA_NUM, potentially causing an infinite NAPI loop reading garbage?
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +0
-0@@ -1074,12 +1211,12 @@ static void loongson_canfd_read_rx_frame(struct loongson_canfd_priv *priv, struc
[ ... ]
drivers/net/can/loongson_canfd.c static void loongson_canfd_read_rx_frame(struct loongson_canfd_priv *priv, struc · line 1216
Quoted 6 lines
drivers/net/can/loongson_canfd.c +1
-1/* 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); }
[Severity: High]
This is a pre-existing issue, but does the lack of bounds checking on len allow a heap buffer overflow?
The len is calculated from the word count in the frame metadata. Without validation ensuring it is bounded by CANFD_MAX_DLEN, could a corrupted word count cause this loop to write out-of-bounds into the skb data buffer?
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +0
-0@@ -1328,16 +1465,16 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
[ ... ]
Quoted 7 lines
drivers/net/can/loongson_canfd.c +1
-2while (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); }
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +0
-0@@ -1367,13 +1504,11 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
[ ... ]
drivers/net/can/loongson_canfd.c static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota) · line 1505
Quoted 2 lines
drivers/net/can/loongson_canfd.c +0
-0if (!rx_frc && ret !=0 ) {if (napi_complete_done (napi, work_done)) {
[Severity: High]
This is a pre-existing issue, but does a memory allocation failure cause a permanent NAPI hang here?
If loongson_canfd_rx() fails to allocate an skb, it returns -ENOMEM. The loop breaks while rx_frc remains true, which makes the check "if (!rx_frc && ret != 0)" evaluate to false. Doesn't this bypass napi_complete_done() and leave NAPI permanently in the SCHED state without re-enabling interrupts?
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +0
-0@@ -1663,6 +1799,7 @@ static int loongson_canfd_probe(struct platform_device *pdev)
[ ... ]
drivers/net/can/loongson_canfd.c static int loongson_canfd_probe(struct platform_device *pdev) · line 1835
Quoted 5 lines
drivers/net/can/loongson_canfd.c +1
-1/* Create a CAN device instance */ ndev =alloc_candev (sizeof (*priv),LOONGSON_CANFD_TXBUF_NUM );if (!ndev) -return -ENOMEM ; + goto err_dma_rx;
[Severity: High]
Does this return an uninitialized variable on probe failure?
The variable ret is declared at the top of the function but not initialized. If alloc_candev() fails, jumping to err_dma_rx will return the uninitialized ret, potentially signaling a false success to the device core.
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +0
-0@@ -1720,6 +1867,19 @@ static int loongson_canfd_probe(struct platform_device *pdev)
[ ... ]
Quoted 1 line
drivers/net/can/loongson_canfd.c +1
-0+if (priv->rx_ch) {
[ ... ]
drivers/net/can/loongson_canfd.c static int loongson_canfd_probe(struct platform_device *pdev) · line 1878
Quoted 5 lines
drivers/net/can/loongson_canfd.c +5
-0+ ret =loongson_canfd_rxdma_init (ndev); +if (ret) { +dev_err (dev,"interrupt mode used for rx (no dma)\n" ); + goto err_candev_free; + }
[Severity: Medium]
Is it intentional to abort the probe entirely here?
The error message indicates an intent to fall back to interrupt (PIO) mode if DMA setup fails, but jumping to err_candev_free will cause the probe to fail and leave the driver unusable instead of gracefully falling back.
[ ... ]
drivers/net/can/loongson_canfd.c static int loongson_canfd_probe(struct platform_device *pdev) · line 1899
Quoted 9 lines
drivers/net/can/loongson_canfd.c +3
-0@@ -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; }
[Severity: High]
Does this error path leak memory and leave a cyclic DMA transfer active?
If register_candev() fails, this path frees the device and releases the channel, but it does not call loongson_canfd_rxdma_remove() to free the coherent DMA memory.
Also, isn't a dmaengine_terminate_sync() call needed to stop the hardware from actively writing to the leaked memory?
[ ... ]
drivers/net/can/loongson_canfd.c static void loongson_canfd_remove(struct platform_device *pdev) · line 1913
Quoted 12 lines
drivers/net/can/loongson_canfd.c +5
-0@@ -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);
[Severity: Critical]
Does freeing the DMA memory before unregistering the device cause a use-after-free and memory corruption?
While unregister_candev() is executing, the network device and NAPI are still active. If a CAN interrupt fires, couldn't the NAPI poll loop (loongson_canfd_rx_napi) read from the freed priv->rx_buf?
Additionally, since the cyclic DMA transfer is never stopped via dmaengine_terminate_sync() before releasing the channel, could the hardware continue writing network frames into freed system memory?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2