mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 19:13:47 +02:00
can: rockchip_canfd: rkcanfd_get_berr_counter_corrected(): work around broken {RX,TX}ERRORCNT register
Tests show that sometimes both CAN bus error counters read 0x0, even if the controller is in warning mode (RKCANFD_REG_STATE_ERROR_WARNING_STATE in RKCANFD_REG_STATE set). To work around this issue, if both error counters read from hardware are 0x0, use the structure priv->bec, otherwise save the read value in priv->bec. In rkcanfd_handle_rx_int_one() decrement the priv->bec.rxerr for successfully RX'ed CAN frames. In rkcanfd_handle_tx_done_one() decrement the priv->bec.txerr for successfully TX'ed CAN frames. Tested-by: Alibek Omarov <a1ba.omarov@gmail.com> Acked-by: Heiko Stuebner <heiko@sntech.de> Link: https://patch.msgid.link/20240904-rockchip-canfd-v5-14-8ae22bcb27cc@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
parent
83f9bd6bf3
commit
7ba7111b5f
|
|
@ -159,11 +159,47 @@ static int rkcanfd_set_bittiming(struct rkcanfd_priv *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rkcanfd_get_berr_counter_raw(struct rkcanfd_priv *priv,
|
||||
struct can_berr_counter *bec)
|
||||
static void rkcanfd_get_berr_counter_corrected(struct rkcanfd_priv *priv,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
struct can_berr_counter bec_raw;
|
||||
u32 reg_state;
|
||||
|
||||
bec->rxerr = rkcanfd_read(priv, RKCANFD_REG_RXERRORCNT);
|
||||
bec->txerr = rkcanfd_read(priv, RKCANFD_REG_TXERRORCNT);
|
||||
bec_raw = *bec;
|
||||
|
||||
/* Tests show that sometimes both CAN bus error counters read
|
||||
* 0x0, even if the controller is in warning mode
|
||||
* (RKCANFD_REG_STATE_ERROR_WARNING_STATE in RKCANFD_REG_STATE
|
||||
* set).
|
||||
*
|
||||
* In case both error counters read 0x0, use the struct
|
||||
* priv->bec, otherwise save the read value to priv->bec.
|
||||
*
|
||||
* rkcanfd_handle_rx_int_one() handles the decrementing of
|
||||
* priv->bec.rxerr for successfully RX'ed CAN frames.
|
||||
*
|
||||
* Luckily the controller doesn't decrement the RX CAN bus
|
||||
* error counter in hardware for self received TX'ed CAN
|
||||
* frames (RKCANFD_REG_MODE_RXSTX_MODE), so RXSTX doesn't
|
||||
* interfere with proper RX CAN bus error counters.
|
||||
*
|
||||
* rkcanfd_handle_tx_done_one() handles the decrementing of
|
||||
* priv->bec.txerr for successfully TX'ed CAN frames.
|
||||
*/
|
||||
if (!bec->rxerr && !bec->txerr)
|
||||
*bec = priv->bec;
|
||||
else
|
||||
priv->bec = *bec;
|
||||
|
||||
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 & RKCANFD_REG_STATE_BUS_OFF_STATE),
|
||||
!!(reg_state & RKCANFD_REG_STATE_ERROR_WARNING_STATE));
|
||||
}
|
||||
|
||||
static int rkcanfd_get_berr_counter(const struct net_device *ndev,
|
||||
|
|
@ -176,7 +212,7 @@ static int rkcanfd_get_berr_counter(const struct net_device *ndev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
rkcanfd_get_berr_counter_raw(priv, bec);
|
||||
rkcanfd_get_berr_counter_corrected(priv, bec);
|
||||
|
||||
pm_runtime_put(ndev->dev.parent);
|
||||
|
||||
|
|
@ -252,6 +288,8 @@ static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
|
|||
RKCANFD_REG_INT_OVERLOAD_INT |
|
||||
RKCANFD_REG_INT_TX_FINISH_INT;
|
||||
|
||||
memset(&priv->bec, 0x0, sizeof(priv->bec));
|
||||
|
||||
rkcanfd_chip_fifo_setup(priv);
|
||||
rkcanfd_timestamp_init(priv);
|
||||
rkcanfd_set_bittiming(priv);
|
||||
|
|
@ -488,7 +526,7 @@ static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
|
|||
if (cf) {
|
||||
struct can_berr_counter bec;
|
||||
|
||||
rkcanfd_get_berr_counter_raw(priv, &bec);
|
||||
rkcanfd_get_berr_counter_corrected(priv, &bec);
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT;
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
|
|
@ -517,7 +555,7 @@ static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
|
|||
u32 timestamp;
|
||||
int err;
|
||||
|
||||
rkcanfd_get_berr_counter_raw(priv, &bec);
|
||||
rkcanfd_get_berr_counter_corrected(priv, &bec);
|
||||
can_state_get_by_berr_counter(ndev, &bec, &tx_state, &rx_state);
|
||||
|
||||
new_state = max(tx_state, rx_state);
|
||||
|
|
@ -570,7 +608,7 @@ rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
|
|||
if (skb)
|
||||
return 0;
|
||||
|
||||
rkcanfd_get_berr_counter_raw(priv, &bec);
|
||||
rkcanfd_get_berr_counter_corrected(priv, &bec);
|
||||
|
||||
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
|
|
|
|||
|
|
@ -167,6 +167,13 @@ static int rkcanfd_rxstx_filter(struct rkcanfd_priv *priv,
|
|||
|
||||
/* Affected by Erratum 6 */
|
||||
|
||||
/* Manual handling of CAN Bus Error counters. See
|
||||
* rkcanfd_get_corrected_berr_counter() for detailed
|
||||
* explanation.
|
||||
*/
|
||||
if (priv->bec.txerr)
|
||||
priv->bec.txerr--;
|
||||
|
||||
*tx_done = true;
|
||||
|
||||
stats->tx_packets++;
|
||||
|
|
@ -229,6 +236,14 @@ static int rkcanfd_handle_rx_int_one(struct rkcanfd_priv *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Manual handling of CAN Bus Error counters. See
|
||||
* rkcanfd_get_corrected_berr_counter() for detailed
|
||||
* explanation.
|
||||
*/
|
||||
if (priv->bec.rxerr)
|
||||
priv->bec.rxerr = min(CAN_ERROR_PASSIVE_THRESHOLD,
|
||||
priv->bec.rxerr) - 1;
|
||||
|
||||
if (header->frameinfo & RKCANFD_REG_FD_FRAMEINFO_FDF)
|
||||
skb = alloc_canfd_skb(priv->ndev, &skb_cfd);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -113,6 +113,14 @@ void rkcanfd_handle_tx_done_one(struct rkcanfd_priv *priv, const u32 ts,
|
|||
unsigned int tx_tail;
|
||||
|
||||
tx_tail = rkcanfd_get_tx_tail(priv);
|
||||
|
||||
/* Manual handling of CAN Bus Error counters. See
|
||||
* rkcanfd_get_corrected_berr_counter() for detailed
|
||||
* explanation.
|
||||
*/
|
||||
if (priv->bec.txerr)
|
||||
priv->bec.txerr--;
|
||||
|
||||
stats->tx_bytes +=
|
||||
can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
|
||||
tx_tail, ts,
|
||||
|
|
|
|||
|
|
@ -459,6 +459,8 @@ struct rkcanfd_priv {
|
|||
u32 reg_int_mask_default;
|
||||
struct rkcanfd_devtype_data devtype_data;
|
||||
|
||||
struct can_berr_counter bec;
|
||||
|
||||
struct reset_control *reset;
|
||||
struct clk_bulk_data *clks;
|
||||
int clks_num;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user