Commit 2c4ef3af authored by Dario Binacchi's avatar Dario Binacchi Committed by Marc Kleine-Budde
Browse files

can: sja1000: sja1000_err(): fix {rx,tx}_errors statistics



The sja1000_err() function only incremented the receive error counter
and never the transmit error counter, even if the ECC_DIR flag reported
that an error had occurred during transmission.

Increment the receive/transmit error counter based on the value of the
ECC_DIR flag.

Fixes: 429da1cc ("can: Driver for the SJA1000 CAN controller")
Signed-off-by: default avatarDario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20241122221650.633981-10-dario.binacchi@amarulasolutions.com


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 3e464593
Loading
Loading
Loading
Loading
+39 −28
Original line number Diff line number Diff line
@@ -416,8 +416,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
	int ret = 0;

	skb = alloc_can_err_skb(dev, &cf);
	if (skb == NULL)
		return -ENOMEM;

	txerr = priv->read_reg(priv, SJA1000_TXERR);
	rxerr = priv->read_reg(priv, SJA1000_RXERR);
@@ -425,8 +423,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
	if (isrc & IRQ_DOI) {
		/* data overrun interrupt */
		netdev_dbg(dev, "data overrun interrupt\n");
		if (skb) {
			cf->can_id |= CAN_ERR_CRTL;
			cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
		}

		stats->rx_over_errors++;
		stats->rx_errors++;
		sja1000_write_cmdreg(priv, CMD_CDO);	/* clear bit */
@@ -452,7 +453,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
		else
			state = CAN_STATE_ERROR_ACTIVE;
	}
	if (state != CAN_STATE_BUS_OFF) {
	if (state != CAN_STATE_BUS_OFF && skb) {
		cf->can_id |= CAN_ERR_CNT;
		cf->data[6] = txerr;
		cf->data[7] = rxerr;
@@ -460,10 +461,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
	if (isrc & IRQ_BEI) {
		/* bus error interrupt */
		priv->can.can_stats.bus_error++;
		stats->rx_errors++;

		ecc = priv->read_reg(priv, SJA1000_ECC);

		if (skb) {
			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;

			/* set error type */
@@ -483,10 +483,16 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)

			/* set error location */
			cf->data[3] = ecc & ECC_SEG;
		}

		/* Error occurred during transmission? */
		if ((ecc & ECC_DIR) == 0)
		if ((ecc & ECC_DIR) == 0) {
			stats->tx_errors++;
			if (skb)
				cf->data[2] |= CAN_ERR_PROT_TX;
		} else {
			stats->rx_errors++;
		}
	}
	if (isrc & IRQ_EPI) {
		/* error passive interrupt */
@@ -502,9 +508,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
		netdev_dbg(dev, "arbitration lost interrupt\n");
		alc = priv->read_reg(priv, SJA1000_ALC);
		priv->can.can_stats.arbitration_lost++;
		if (skb) {
			cf->can_id |= CAN_ERR_LOSTARB;
			cf->data[0] = alc & 0x1f;
		}
	}

	if (state != priv->can.state) {
		tx_state = txerr >= rxerr ? state : 0;
@@ -516,6 +524,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
			can_bus_off(dev);
	}

	if (!skb)
		return -ENOMEM;

	netif_rx(skb);

	return ret;