lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251113-slim-foamy-gecko-2dc389-mkl@pengutronix.de>
Date: Thu, 13 Nov 2025 15:14:56 +0100
From: Marc Kleine-Budde <mkl@...gutronix.de>
To: Elaine Zhang <zhangqing@...k-chips.com>
Cc: kernel@...gutronix.de, mailhol.vincent@...adoo.fr, robh@...nel.org, 
	krzk+dt@...nel.org, conor+dt@...nel.org, heiko@...ech.de, cl@...k-chips.com, 
	linux-can@...r.kernel.org, linux-arm-kernel@...ts.infradead.org, 
	linux-rockchip@...ts.infradead.org, linux-kernel@...r.kernel.org, devicetree@...r.kernel.org
Subject: Re: [PATCH v9 3/3] net: can: rockchip: add can for RK3576 Soc

On 13.11.2025 15:54:19, Elaine Zhang wrote:
> Is new controller, new register layout and Bit position definition:

Let's improve the patch description a bit. What about:

The CAN FD cores in the rk3576 SoC are a newer revision than those in
the rk3568. The main differences are:

- changed register layout
- different bit position
- ...

I remember:
- time stamp register removed

Please go through this list and remove everything that was unchanged and
add it to the list I started above.

> Support CAN protocol, ISO 11898-1
> Support transmit or receive error count
> Support acceptance filter, more functional
> Support interrupt and all interrupt can be masked
> Support error code check
> Support self test\silent\loop-back mode
> Support auto retransmission mode
> Support auto bus on after bus-off state
> Support 2 transmit buffers
> Support Internal Storage Mode
>
> Signed-off-by: Elaine Zhang <zhangqing@...k-chips.com>
> ---
>  .../net/can/rockchip/rockchip_canfd-core.c    | 419 ++++++++++++++++++
>  drivers/net/can/rockchip/rockchip_canfd-rx.c  | 103 +++++
>  drivers/net/can/rockchip/rockchip_canfd-tx.c  |  20 +
>  drivers/net/can/rockchip/rockchip_canfd.h     | 258 +++++++++++
>  4 files changed, 800 insertions(+)
>
> diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c
> index 761cb36148ff..58fffcf97b20 100644
> --- a/drivers/net/can/rockchip/rockchip_canfd-core.c
> +++ b/drivers/net/can/rockchip/rockchip_canfd-core.c
> @@ -31,6 +31,8 @@ static const char *__rkcanfd_get_model_str(enum rkcanfd_model model)
>  		return "rk3568v2";
>  	case RKCANFD_MODEL_RK3568V3:
>  		return "rk3568v3";
> +	case RKCAN_MODEL_RK3576:
> +		return "rk3576";
>  	}
>
>  	return "<unknown>";
> @@ -176,6 +178,27 @@ static void rkcanfd_get_berr_counter_corrected(struct rkcanfd_priv *priv,
>  		    !!(reg_state & RKCANFD_REG_STATE_ERROR_WARNING_STATE));
>  }
>
> +static void rk3576can_get_berr_counter_corrected(struct rkcanfd_priv *priv,
> +						 struct can_berr_counter *bec)
> +{
> +	struct can_berr_counter bec_raw;

You've removed the workaround handling for the berr_counter. This means
your SoC is not affected by it. So the bec_raw and taking care of
priv->bec is not needed.

> +	u32 reg_state;
> +
> +	bec->rxerr = rkcanfd_read(priv, RK3576CAN_REG_RXERRORCNT);
> +	bec->txerr = rkcanfd_read(priv, RK3576CAN_REG_TXERRORCNT);

> +	bec_raw = *bec;
remove, see above

> +
> +	priv->bec = *bec;

remove, see above

> +
> +	reg_state = rkcanfd_read(priv, RKCANFD_REG_STATE);
> +	netdev_vdbg(priv->ndev,
> +		    "%s: Raw/Cor: txerr=%3u/%3u rxerr=%3u/%3u Bus Off=%u Warning=%u\n",
> +		    __func__,
> +		    bec_raw.txerr, bec->txerr, bec_raw.rxerr, bec->rxerr,
> +		    !!(reg_state & RK3576CAN_REG_STATE_BUS_OFF_STATE),
> +		    !!(reg_state & RK3576CAN_REG_STATE_ERROR_WARNING_STATE));

I think the vdbg can be removed, if the IP core is not affected by the
problem.

> +}
> +
>  static int rkcanfd_get_berr_counter(const struct net_device *ndev,
>  				    struct can_berr_counter *bec)
>  {
> @@ -206,6 +229,11 @@ static void rkcanfd_chip_interrupts_disable(const struct rkcanfd_priv *priv)
>  	rkcanfd_write(priv, RKCANFD_REG_INT_MASK, RKCANFD_REG_INT_ALL);
>  }
>
> +static void rk3576can_chip_interrupts_disable(const struct rkcanfd_priv *priv)
> +{
> +	rkcanfd_write(priv, RK3576CAN_REG_INT_MASK, RK3576CAN_REG_INT_ALL);
> +}
> +
>  static void rkcanfd_chip_fifo_setup(struct rkcanfd_priv *priv)
>  {
>  	u32 reg;
> @@ -220,6 +248,48 @@ static void rkcanfd_chip_fifo_setup(struct rkcanfd_priv *priv)
>  	netdev_reset_queue(priv->ndev);
>  }
>
> +static void rk3576can_chip_fifo_setup(struct rkcanfd_priv *priv)
> +{
> +	u32 reg_ism, reg_water;
> +
> +	reg_ism = FIELD_PREP(RK3576CAN_REG_STR_CTL_ISM_SEL,
> +			     RK3576CAN_REG_STR_CTL_ISM_SEL_CANFD_FIXED) |
> +		  RK3576CAN_REG_STR_CTL_STORAGE_TIMEOUT_MODE;
> +	reg_water = RK3576CAN_ISM_WATERMASK_CANFD;
> +
> +	/* internal sram mode */
> +	rkcanfd_write(priv, RK3576CAN_REG_STR_CTL, reg_ism);
> +	rkcanfd_write(priv, RK3576CAN_REG_STR_WTM, reg_water);
> +	WRITE_ONCE(priv->tx_head, 0);
> +	WRITE_ONCE(priv->tx_tail, 0);
> +	netdev_reset_queue(priv->ndev);
> +}
> +
> +static void rk3576can_atf_config(struct rkcanfd_priv *priv, int mode)
> +{
> +	int i;
> +
> +	switch (mode) {
> +	case RK3576CAN_REG_ATFM_MASK_SEL_MASK_MODE:
> +		for (i = 0; i < 5; i++) {
> +			rkcanfd_write(priv, RK3576CAN_REG_ATF(i), 0);
> +			rkcanfd_write(priv, RK3576CAN_REG_ATFM(i), RK3576CAN_REG_ATFM_ID);
> +		}
> +		break;
> +	case RK3576CAN_REG_ATFM_MASK_SEL_LIST_MODE:
> +		for (i = 0; i < 5; i++) {
> +			rkcanfd_write(priv, RK3576CAN_REG_ATF(i), 0);
> +			rkcanfd_write(priv, RK3576CAN_REG_ATFM(i), RK3576CAN_REG_ATFM_MASK_SEL);
> +		}
> +		break;
> +	default:
> +		rkcanfd_write(priv, RK3576CAN_REG_ATF_CTL, RK3576CAN_REG_ATF_CTL_ATF_DIS_ALL);
> +		return;
> +	}
> +
> +	rkcanfd_write(priv, RK3576CAN_REG_ATF_CTL, 0);
> +}
> +
>  static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
>  {
>  	u32 reg;
> @@ -285,6 +355,61 @@ static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
>  		   rkcanfd_read(priv, RKCANFD_REG_MODE));
>  }
>
> +static void rk3576can_chip_start(struct rkcanfd_priv *priv)
> +
> +{
> +	u32 reg;
> +
> +	rkcanfd_chip_set_reset_mode(priv);
> +
> +	/* Receiving Filter: accept all */
> +	rk3576can_atf_config(priv, RK3576CAN_REG_ATFM_MASK_SEL_MASK_MODE);
> +
> +	/* enable:
> +	 * - WORK_MODE: transition from reset to working mode
> +	 */
> +	reg = rkcanfd_read(priv, RKCANFD_REG_MODE);
> +	priv->reg_mode_default = reg | RKCANFD_REG_MODE_WORK_MODE;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
> +		priv->reg_mode_default |= RKCANFD_REG_MODE_LBACK_MODE;
> +		rkcanfd_write(priv, RK3576CAN_REG_ERROR_MASK,
> +			      RK3576CAN_REG_ERROR_MASK_ACK_ERROR);
> +	}
> +
> +	/* mask, i.e. ignore:
> +	 * - RX_FINISH_INT - Rx finish interrupt
> +	 */
> +	priv->reg_int_mask_default = RK3576CAN_REG_INT_RX_FINISH_INT;
> +
> +	/* Do not mask the bus error interrupt if the bus error
> +	 * reporting is requested.
> +	 */
> +	if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
> +		priv->reg_int_mask_default |= RKCANFD_REG_INT_ERROR_INT;
> +
> +	memset(&priv->bec, 0x0, sizeof(priv->bec));
> +
> +	rk3576can_chip_fifo_setup(priv);
> +
> +	rkcanfd_write(priv, RK3576CAN_REG_AUTO_RETX_CFG,
> +		      RK3576CAN_REG_AUTO_RETX_CFG_AUTO_RETX_EN);
> +
> +	rkcanfd_write(priv, RK3576CAN_REG_BRS_CFG,
> +		      RK3576CAN_REG_BRS_CFG_BRS_NEGSYNC_EN |
> +		      RK3576CAN_REG_BRS_CFG_BRS_POSSYNC_EN);
> +
> +	rkcanfd_set_bittiming(priv);
> +
> +	priv->devtype_data.interrupts_disable(priv);
> +	rkcanfd_chip_set_work_mode(priv);
> +
> +	priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> +	netdev_dbg(priv->ndev, "%s: reg_mode=0x%08x\n", __func__,
> +		   rkcanfd_read(priv, RKCANFD_REG_MODE));
> +}
> +
>  static void __rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state state)
>  {
>  	priv->can.state = state;
> @@ -301,6 +426,13 @@ static void rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state st
>  	__rkcanfd_chip_stop(priv, state);
>  }
>
> +static void rk3576can_chip_stop(struct rkcanfd_priv *priv, const enum can_state state)
> +{
> +	priv->can.state = state;
> +
> +	__rkcanfd_chip_stop(priv, state);
> +}
> +
>  static void rkcanfd_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_state state)
>  {
>  	priv->can.state = state;
> @@ -309,6 +441,13 @@ static void rkcanfd_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_sta
>  	__rkcanfd_chip_stop(priv, state);
>  }
>
> +static void rk3576can_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_state state)
> +{
> +	priv->can.state = state;
> +
> +	__rkcanfd_chip_stop(priv, state);
> +}
> +
>  static int rkcanfd_set_mode(struct net_device *ndev,
>  			    enum can_mode mode)
>  {
> @@ -364,6 +503,9 @@ static const char *rkcanfd_get_error_type_str(unsigned int type)
>  #define RKCAN_ERROR_CODE(reg_ec, code) \
>  	((reg_ec) & RKCANFD_REG_ERROR_CODE_##code ? __stringify(code) " " : "")
>
> +#define RK3576CAN_ERROR_CODE(reg_ec, code) \
> +	((reg_ec) & RK3576CAN_REG_ERROR_CODE_##code ? __stringify(code) " " : "")
> +
>  static void
>  rkcanfd_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
>  				const u32 reg_ec)
> @@ -493,6 +635,128 @@ rkcanfd_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
>  	}
>  }
>
> +static void
> +rk3576can_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
> +				  const u32 reg_ec)
> +{
> +	struct net_device_stats *stats = &priv->ndev->stats;
> +	unsigned int type;
> +	u32 reg_state, reg_cmd;
> +
> +	type = FIELD_GET(RK3576CAN_REG_ERROR_CODE_TYPE, reg_ec);
> +	reg_cmd = rkcanfd_read(priv, RK3576CAN_REG_CMD);
> +	reg_state = rkcanfd_read(priv, RK3576CAN_REG_STATE);
> +
> +	netdev_dbg(priv->ndev, "%s Error in %s %s Phase: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s(0x%08x) CMD=%u RX=%u TX=%u Error-Warning=%u Bus-Off=%u\n",
> +		   rkcanfd_get_error_type_str(type),
> +		   reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX ? "RX" : "TX",
> +		   reg_ec & RK3576CAN_REG_ERROR_CODE_PHASE ? "Data" : "Arbitration",
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_ACK_EOF),
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_CRC),
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_STUFF_COUNT),
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_DATA),
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_SOF_DLC),
> +		   RK3576CAN_ERROR_CODE(reg_ec, TX_IDLE),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_ERROR),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_OVERLOAD),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_SPACE),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_EOF),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_ACK_LIM),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_ACK),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_CRC_LIM),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_CRC),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_STUFF_COUNT),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_DATA),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_DLC),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_BRS_ESI),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_RES),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_FDF),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_ID2_RTR),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_SOF_IDE),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_BUS_IDLE),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_BUS_INT),
> +		   RK3576CAN_ERROR_CODE(reg_ec, RX_STOP),
> +		   reg_ec, reg_cmd,
> +		   !!(reg_state & RK3576CAN_REG_STATE_RX_PERIOD),
> +		   !!(reg_state & RK3576CAN_REG_STATE_TX_PERIOD),
> +		   !!(reg_state & RK3576CAN_REG_STATE_ERROR_WARNING_STATE),
> +		   !!(reg_state & RK3576CAN_REG_STATE_BUS_OFF_STATE));
> +
> +	priv->can.can_stats.bus_error++;
> +
> +	if (reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX)
> +		stats->rx_errors++;
> +	else
> +		stats->tx_errors++;
> +
> +	if (!cf)
> +		return;
> +
> +	if (reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX) {
> +		if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_SOF_IDE)
> +			cf->data[3] = CAN_ERR_PROT_LOC_SOF;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ID2_RTR)
> +			cf->data[3] = CAN_ERR_PROT_LOC_RTR;
> +		/* RKCANFD_REG_ERROR_CODE_RX_FDF */
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_RES)
> +			cf->data[3] = CAN_ERR_PROT_LOC_RES0;
> +		/* RKCANFD_REG_ERROR_CODE_RX_BRS_ESI */
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_DLC)
> +			cf->data[3] = CAN_ERR_PROT_LOC_DLC;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_DATA)
> +			cf->data[3] = CAN_ERR_PROT_LOC_DATA;
> +		/* RKCANFD_REG_ERROR_CODE_RX_STUFF_COUNT */
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_CRC)
> +			cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_CRC_LIM)
> +			cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ACK)
> +			cf->data[3] = CAN_ERR_PROT_LOC_ACK;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ACK_LIM)
> +			cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_EOF)
> +			cf->data[3] = CAN_ERR_PROT_LOC_EOF;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_SPACE)
> +			cf->data[3] = CAN_ERR_PROT_LOC_EOF;
> +	} else {
> +		cf->data[2] |= CAN_ERR_PROT_TX;
> +
> +		if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_SOF_DLC)
> +			cf->data[3] = CAN_ERR_PROT_LOC_SOF;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_DATA)
> +			cf->data[3] = CAN_ERR_PROT_LOC_DATA;
> +		/* RKCANFD_REG_ERROR_CODE_TX_STUFF_COUNT */
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_CRC)
> +			cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
> +		else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_ACK_EOF)
> +			cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
> +	}
> +
> +	switch (reg_ec & RK3576CAN_REG_ERROR_CODE_TYPE) {
> +	case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
> +			      RK3576CAN_REG_ERROR_CODE_TYPE_BIT):
> +
> +		cf->data[2] |= CAN_ERR_PROT_BIT;
> +		break;
> +	case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
> +			      RK3576CAN_REG_ERROR_CODE_TYPE_STUFF):
> +		cf->data[2] |= CAN_ERR_PROT_STUFF;
> +		break;
> +	case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
> +			      RK3576CAN_REG_ERROR_CODE_TYPE_FORM):
> +		cf->data[2] |= CAN_ERR_PROT_FORM;
> +		break;
> +	case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
> +			      RK3576CAN_REG_ERROR_CODE_TYPE_ACK):
> +		cf->can_id |= CAN_ERR_ACK;
> +		break;
> +	case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
> +			      RK3576CAN_REG_ERROR_CODE_TYPE_CRC):
> +		cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
> +		break;
> +	}
> +}
> +
>  static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
>  {
>  	struct net_device_stats *stats = &priv->ndev->stats;
> @@ -530,6 +794,41 @@ static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
>  	return 0;
>  }
>
> +static int rkcanfd_handle_rk3576_error_int(struct rkcanfd_priv *priv)
> +{
> +	struct net_device_stats *stats = &priv->ndev->stats;
> +	struct can_frame *cf = NULL;
> +	u32 reg_ec;
> +	struct sk_buff *skb;
> +	int err;
> +
> +	reg_ec = rkcanfd_read(priv, RK3576CAN_REG_ERROR_CODE);
> +	if (!reg_ec)
> +		return 0;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
> +		skb = alloc_can_err_skb(priv->ndev, &cf);
> +		if (cf) {
> +			struct can_berr_counter bec;
> +
> +			priv->devtype_data.get_berr_counter(priv, &bec);
> +			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT;
> +			cf->data[6] = bec.txerr;
> +			cf->data[7] = bec.rxerr;
> +		}
> +	}
> +
> +	rk3576can_handle_error_int_reg_ec(priv, cf, reg_ec);
> +	if (!cf)
> +		return 0;
> +
> +	err = can_rx_offload_queue_tail(&priv->offload, skb);
> +	if (err)
> +		stats->rx_fifo_errors++;
> +
> +	return 0;
> +}
> +
>  static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
>  {
>  	struct net_device_stats *stats = &priv->ndev->stats;
> @@ -575,6 +874,50 @@ static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
>  	return 0;
>  }
>
> +static int rkcanfd_handle_rk3576_state_error_int(struct rkcanfd_priv *priv)
> +{
> +	struct net_device_stats *stats = &priv->ndev->stats;
> +	enum can_state new_state, rx_state, tx_state;
> +	struct net_device *ndev = priv->ndev;
> +	struct can_berr_counter bec;
> +	struct can_frame *cf = NULL;
> +	struct sk_buff *skb;
> +	int err;
> +
> +	priv->devtype_data.get_berr_counter(priv, &bec);

You're already in the rk3576 specific code.

> +	can_state_get_by_berr_counter(ndev, &bec, &tx_state, &rx_state);
> +
> +	new_state = max(tx_state, rx_state);
> +	if (new_state == priv->can.state)
> +		return 0;
> +
> +	/* The skb allocation might fail, but can_change_state()
> +	 * handles cf == NULL.
> +	 */
> +	skb = alloc_can_err_skb(priv->ndev, &cf);
> +	can_change_state(ndev, cf, tx_state, rx_state);
> +
> +	if (new_state == CAN_STATE_BUS_OFF) {
> +		priv->devtype_data.chip_stop(priv, CAN_STATE_BUS_OFF);
> +		can_bus_off(ndev);
> +	}
> +
> +	if (!skb)
> +		return 0;
> +
> +	if (new_state != CAN_STATE_BUS_OFF) {
> +		cf->can_id |= CAN_ERR_CNT;
> +		cf->data[6] = bec.txerr;
> +		cf->data[7] = bec.rxerr;
> +	}
> +
> +	err = can_rx_offload_queue_tail(&priv->offload, skb);
> +	if (err)
> +		stats->rx_fifo_errors++;
> +
> +	return 0;
> +}
> +
>  static int
>  rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
>  {
> @@ -621,6 +964,55 @@ rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
>  	err; \
>  })
>
> +static irqreturn_t rk3576can_irq(int irq, void *dev_id)
> +{
> +	struct rkcanfd_priv *priv = dev_id;
> +	u32 reg_int_unmasked, reg_int;
> +
> +	reg_int_unmasked = rkcanfd_read(priv, RK3576CAN_REG_INT);
> +	reg_int = reg_int_unmasked & ~priv->reg_int_mask_default;
> +
> +	if (!reg_int)
> +		return IRQ_NONE;
> +
> +	rkcanfd_write(priv, RK3576CAN_REG_INT, reg_int);
> +
> +	if (reg_int & (RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT |
> +		       RK3576CAN_REG_INT_ISM_WTM_INT |
> +		       RK3576CAN_REG_INT_RX_FIFO_FULL_INT)) {
> +		rkcanfd_write(priv, RK3576CAN_REG_INT_MASK,
> +			      priv->reg_int_mask_default | RK3576CAN_REG_INT_ISM_WTM_INT |
> +			      RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT |
> +			      RK3576CAN_REG_INT_RX_FINISH_INT);
> +		rkcanfd_handle(priv, rk3576_rx_int);
> +	}
> +
> +	if (reg_int & RK3576CAN_REG_INT_TX_FINISH_INT)
> +		rkcanfd_handle(priv, rk3576_tx_int);
> +
> +	if (reg_int & RK3576CAN_REG_INT_ERROR_INT)
> +		rkcanfd_handle(priv, rk3576_error_int);
> +
> +	if (reg_int & (RK3576CAN_REG_INT_BUS_OFF_INT |
> +		       RK3576CAN_REG_INT_PASSIVE_ERROR_INT |
> +		       RK3576CAN_REG_INT_ERROR_WARNING_INT) ||
> +	    priv->can.state > CAN_STATE_ERROR_ACTIVE)
> +		rkcanfd_handle(priv, rk3576_state_error_int);
> +
> +	if (reg_int & RK3576CAN_REG_INT_WAKEUP_INT)
> +		netdev_info(priv->ndev, "%s: WAKEUP_INT\n", __func__);
> +
> +	if (reg_int & RK3576CAN_REG_INT_BUS_OFF_RECOVERY_INT)
> +		netdev_info(priv->ndev, "%s: BUS_OFF_RECOVERY_INT\n", __func__);
> +
> +	if (reg_int & RK3576CAN_REG_INT_OVERLOAD_INT)
> +		netdev_info(priv->ndev, "%s: OVERLOAD_INT\n", __func__);
> +
> +	can_rx_offload_irq_finish(&priv->offload);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static irqreturn_t rkcanfd_irq(int irq, void *dev_id)
>  {
>  	struct rkcanfd_priv *priv = dev_id;
> @@ -775,6 +1167,16 @@ static void rkcanfd_register_done(const struct rkcanfd_priv *priv)
>  			    RKCANFD_ERRATUM_5_SYSCLOCK_HZ_MIN / MEGA);
>  }
>
> +static void rk3576can_register_done(const struct rkcanfd_priv *priv)
> +{
> +	u32 dev_id;
> +
> +	dev_id = rkcanfd_read(priv, RK3576CAN_REG_RTL_VERSION);
> +	netdev_info(priv->ndev,
> +		    "Rockchip-CANFD %s rev%u.\n",
> +		    rkcanfd_get_model_str(priv), dev_id);

Please also print the activated errata.

> +}
> +
>  static int rkcanfd_register(struct rkcanfd_priv *priv)
>  {
>  	struct net_device *ndev = priv->ndev;
> @@ -856,6 +1258,20 @@ static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = {
>  	.register_done = rkcanfd_register_done,
>  };
>
> +/* The rk3576 CAN-FD */
> +static const struct rkcanfd_devtype_data rkcan_devtype_data_rk3576 = {
> +	.model = RKCAN_MODEL_RK3576,
> +	.quirks = RKCANFD_QUIRK_CANFD_BROKEN,

Is CAN-FD mode broken on the rk3576?

Please test CAN-FD and please do the tests documented near the
definition of RKCANFD_QUIRK_CANFD_BROKEN:

| Tests on the rk3568v2 and rk3568v3 show that receiving certain
| CAN-FD frames trigger an Error Interrupt.
|
| - Form Error in RX Arbitration Phase: TX_IDLE RX_STUFF_COUNT (0x0a010100) CMD=0 RX=0 TX=0
|   Error-Warning=1 Bus-Off=0
|   To reproduce:
|   host:
|     cansend can0 002##01f
|   DUT:
|     candump any,0:0,#FFFFFFFF -cexdHtA
|
| - Form Error in RX Arbitration Phase: TX_IDLE RX_CRC (0x0a010200) CMD=0 RX=0 TX=0
|   Error-Warning=1 Bus-Off=0
|   To reproduce:
|   host:
|     cansend can0 002##07217010000000000
|   DUT:
|     candump any,0:0,#FFFFFFFF -cexdHtA

regards,
Marc

--
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung Nürnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |

Download attachment "signature.asc" of type "application/pgp-signature" (489 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ