mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
can: sja1000: sja1000_err(): fix {rx,tx}_errors statistics
[ Upstream commit 2c4ef3af4b028a0eaaf378df511d3b425b1df61f ]
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: 429da1cc84 ("can: Driver for the SJA1000 CAN controller")
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20241122221650.633981-10-dario.binacchi@amarulasolutions.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
4a76e5e83e
commit
94f2bb4386
@@ -399,8 +399,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
uint8_t ecc, alc;
|
uint8_t ecc, alc;
|
||||||
|
|
||||||
skb = alloc_can_err_skb(dev, &cf);
|
skb = alloc_can_err_skb(dev, &cf);
|
||||||
if (skb == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
txerr = priv->read_reg(priv, SJA1000_TXERR);
|
txerr = priv->read_reg(priv, SJA1000_TXERR);
|
||||||
rxerr = priv->read_reg(priv, SJA1000_RXERR);
|
rxerr = priv->read_reg(priv, SJA1000_RXERR);
|
||||||
@@ -408,8 +406,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
if (isrc & IRQ_DOI) {
|
if (isrc & IRQ_DOI) {
|
||||||
/* data overrun interrupt */
|
/* data overrun interrupt */
|
||||||
netdev_dbg(dev, "data overrun interrupt\n");
|
netdev_dbg(dev, "data overrun interrupt\n");
|
||||||
cf->can_id |= CAN_ERR_CRTL;
|
if (skb) {
|
||||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
cf->can_id |= CAN_ERR_CRTL;
|
||||||
|
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
stats->rx_over_errors++;
|
stats->rx_over_errors++;
|
||||||
stats->rx_errors++;
|
stats->rx_errors++;
|
||||||
sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */
|
sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */
|
||||||
@@ -426,7 +427,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
else
|
else
|
||||||
state = CAN_STATE_ERROR_ACTIVE;
|
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->can_id |= CAN_ERR_CNT;
|
||||||
cf->data[6] = txerr;
|
cf->data[6] = txerr;
|
||||||
cf->data[7] = rxerr;
|
cf->data[7] = rxerr;
|
||||||
@@ -434,33 +435,38 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
if (isrc & IRQ_BEI) {
|
if (isrc & IRQ_BEI) {
|
||||||
/* bus error interrupt */
|
/* bus error interrupt */
|
||||||
priv->can.can_stats.bus_error++;
|
priv->can.can_stats.bus_error++;
|
||||||
stats->rx_errors++;
|
|
||||||
|
|
||||||
ecc = priv->read_reg(priv, SJA1000_ECC);
|
ecc = priv->read_reg(priv, SJA1000_ECC);
|
||||||
|
if (skb) {
|
||||||
|
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||||
|
|
||||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
/* set error type */
|
||||||
|
switch (ecc & ECC_MASK) {
|
||||||
|
case ECC_BIT:
|
||||||
|
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||||
|
break;
|
||||||
|
case ECC_FORM:
|
||||||
|
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||||
|
break;
|
||||||
|
case ECC_STUFF:
|
||||||
|
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* set error type */
|
/* set error location */
|
||||||
switch (ecc & ECC_MASK) {
|
cf->data[3] = ecc & ECC_SEG;
|
||||||
case ECC_BIT:
|
|
||||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
|
||||||
break;
|
|
||||||
case ECC_FORM:
|
|
||||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
|
||||||
break;
|
|
||||||
case ECC_STUFF:
|
|
||||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set error location */
|
|
||||||
cf->data[3] = ecc & ECC_SEG;
|
|
||||||
|
|
||||||
/* Error occurred during transmission? */
|
/* Error occurred during transmission? */
|
||||||
if ((ecc & ECC_DIR) == 0)
|
if ((ecc & ECC_DIR) == 0) {
|
||||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
stats->tx_errors++;
|
||||||
|
if (skb)
|
||||||
|
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||||
|
} else {
|
||||||
|
stats->rx_errors++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isrc & IRQ_EPI) {
|
if (isrc & IRQ_EPI) {
|
||||||
/* error passive interrupt */
|
/* error passive interrupt */
|
||||||
@@ -476,8 +482,10 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
netdev_dbg(dev, "arbitration lost interrupt\n");
|
netdev_dbg(dev, "arbitration lost interrupt\n");
|
||||||
alc = priv->read_reg(priv, SJA1000_ALC);
|
alc = priv->read_reg(priv, SJA1000_ALC);
|
||||||
priv->can.can_stats.arbitration_lost++;
|
priv->can.can_stats.arbitration_lost++;
|
||||||
cf->can_id |= CAN_ERR_LOSTARB;
|
if (skb) {
|
||||||
cf->data[0] = alc & 0x1f;
|
cf->can_id |= CAN_ERR_LOSTARB;
|
||||||
|
cf->data[0] = alc & 0x1f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state != priv->can.state) {
|
if (state != priv->can.state) {
|
||||||
@@ -490,6 +498,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||||||
can_bus_off(dev);
|
can_bus_off(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
netif_rx(skb);
|
netif_rx(skb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user