On 05/30/2011 03:33 PM, Marc Kleine-Budde wrote:
> On 05/30/2011 03:30 PM, Wolfgang Grandegger wrote:
>> Hi Marc,
>>
>> On 05/30/2011 03:05 PM, Marc Kleine-Budde wrote:
>>> Hello Wolfgang,
>>>
>>> I'm doing some work on the at91 driver, especially the error management,
>>> to support the upcoming 5sereis. Do you have any patches or remarks for
>>> the driver, the patches don't even need to apply any more or must be
>>> tested, I just need some input cause I have to restructure the error
>>> handling anyway.
>>
>> Well, I have a almost (half?) complete patch series to consolidate the
>> error handling of the mainline Socket-CAN device drivers but real
>> bussiness does keep me fully loaded already since a while,
>> unfortunately. I will dig for it later today or tomorrow. More soon...
> 
> Just send me the at91 bit (as soon as possible :P, please). As it turns
> out they changed some bits to clear on read in the new CAN hardware.

Attached is the patch series I'm speaking about. I think there is no
special fix for the AT91. The series tries to make the error handling
consistent for all drivers as discussed some time ago.

Wolfgang.
>From 0d36e12c4c76a2074d34bc9b0f8c176c997b62e2 Mon Sep 17 00:00:00 2001
From: Wolfgang Grandegger <[email protected]>
Date: Wed, 23 Mar 2011 17:34:46 +0100
Subject: [PATCH 1/3] can: consolidate handling of bus error counters

This patch improves and corrects the handling of bus error TX and RX
counters:

- Fill the data[6..7] fields of all error message with the TX and RX
  error counter values in the common function alloc_can_err_skb().

- Add missing do_get_berr_counter callbacks for the ti_hecc and
  bfin_can driver.

- A few other minor fixes, e.g. make sure to fill data[6..7] for all
  error messages.

Signed-off-by: Wolfgang Grandegger <[email protected]>
CC: Marc Kleine-Budde <[email protected]>
CC: Barry Song <[email protected]>
CC: Anant Gole <[email protected]>
---
 drivers/net/can/at91_can.c        |    7 ++-----
 drivers/net/can/bfin_can.c        |   22 ++++++++++++++++------
 drivers/net/can/dev.c             |    8 ++++++++
 drivers/net/can/flexcan.c         |    7 ++-----
 drivers/net/can/pch_can.c         |   14 +++++---------
 drivers/net/can/sja1000/sja1000.c |    8 ++------
 drivers/net/can/ti_hecc.c         |   20 ++++++++++++++++----
 drivers/net/can/usb/ems_usb.c     |    7 ++++---
 drivers/net/can/usb/esd_usb2.c    |    5 +++--
 9 files changed, 58 insertions(+), 40 deletions(-)

diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 57d2ffb..f18cba7 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -803,9 +803,6 @@ static void at91_irq_err_state(struct net_device *dev,
 {
 	struct at91_priv *priv = netdev_priv(dev);
 	u32 reg_idr = 0, reg_ier = 0;
-	struct can_berr_counter bec;
-
-	at91_get_berr_counter(dev, &bec);
 
 	switch (priv->can.state) {
 	case CAN_STATE_ERROR_ACTIVE:
@@ -820,7 +817,7 @@ static void at91_irq_err_state(struct net_device *dev,
 			priv->can.can_stats.error_warning++;
 
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (bec.txerr > bec.rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_WARNING :
 				CAN_ERR_CRTL_RX_WARNING;
 		}
@@ -836,7 +833,7 @@ static void at91_irq_err_state(struct net_device *dev,
 			priv->can.can_stats.error_passive++;
 
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (bec.txerr > bec.rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_PASSIVE :
 				CAN_ERR_CRTL_RX_PASSIVE;
 		}
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index b6e890d..9c3e78e 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -224,6 +224,19 @@ static int bfin_can_set_mode(struct net_device *dev, enum can_mode mode)
 	return 0;
 }
 
+static int bfin_get_berr_counter(const struct net_device *dev,
+				 struct can_berr_counter *bec)
+{
+	struct bfin_can_priv *priv = netdev_priv(dev);
+	struct bfin_can_regs __iomem *reg = priv->membase;
+	u16 cec = bfin_read16(&reg->cec);
+
+	bec->txerr = cec & 0xff;
+	bec->rxerr = (cec >> 8) & 0xff;
+
+	return 0;
+}
+
 static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct bfin_can_priv *priv = netdev_priv(dev);
@@ -368,19 +381,15 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
 
 	if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
 				state == CAN_STATE_ERROR_PASSIVE)) {
-		u16 cec = bfin_read16(&reg->cec);
-		u8 rxerr = cec;
-		u8 txerr = cec >> 8;
-
 		cf->can_id |= CAN_ERR_CRTL;
 		if (state == CAN_STATE_ERROR_WARNING) {
 			priv->can.can_stats.error_warning++;
-			cf->data[1] = (txerr > rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_WARNING :
 				CAN_ERR_CRTL_RX_WARNING;
 		} else {
 			priv->can.can_stats.error_passive++;
-			cf->data[1] = (txerr > rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_PASSIVE :
 				CAN_ERR_CRTL_RX_PASSIVE;
 		}
@@ -517,6 +526,7 @@ struct net_device *alloc_bfin_candev(void)
 	priv->dev = dev;
 	priv->can.bittiming_const = &bfin_can_bittiming_const;
 	priv->can.do_set_bittiming = bfin_can_set_bittiming;
+	priv->can.do_get_berr_counter = bfin_get_berr_counter;
 	priv->can.do_set_mode = bfin_can_set_mode;
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index d0f8c7e..e2f8e04 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -465,6 +465,7 @@ EXPORT_SYMBOL_GPL(alloc_can_skb);
 
 struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
 {
+	struct can_priv *priv = netdev_priv(dev);
 	struct sk_buff *skb;
 
 	skb = alloc_can_skb(dev, cf);
@@ -473,6 +474,13 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
 
 	(*cf)->can_id = CAN_ERR_FLAG;
 	(*cf)->can_dlc = CAN_ERR_DLC;
+	if (priv->do_get_berr_counter) {
+		struct can_berr_counter bec;
+
+		priv->do_get_berr_counter(dev, &bec);
+		(*cf)->data[6] = bec.txerr;
+		(*cf)->data[7] = bec.rxerr;
+	}
 
 	return skb;
 }
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index d499056..731764f 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -356,9 +356,6 @@ static void do_state(struct net_device *dev,
 		     struct can_frame *cf, enum can_state new_state)
 {
 	struct flexcan_priv *priv = netdev_priv(dev);
-	struct can_berr_counter bec;
-
-	flexcan_get_berr_counter(dev, &bec);
 
 	switch (priv->can.state) {
 	case CAN_STATE_ERROR_ACTIVE:
@@ -373,7 +370,7 @@ static void do_state(struct net_device *dev,
 			priv->can.can_stats.error_warning++;
 
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (bec.txerr > bec.rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_WARNING :
 				CAN_ERR_CRTL_RX_WARNING;
 		}
@@ -389,7 +386,7 @@ static void do_state(struct net_device *dev,
 			priv->can.can_stats.error_passive++;
 
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[1] = (bec.txerr > bec.rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_PASSIVE :
 				CAN_ERR_CRTL_RX_PASSIVE;
 		}
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index e54712b..042ecff 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -493,7 +493,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
 	struct sk_buff *skb;
 	struct pch_can_priv *priv = netdev_priv(ndev);
 	struct can_frame *cf;
-	u32 errc, lec;
+	u32 lec;
 	struct net_device_stats *stats = &(priv->ndev->stats);
 	enum can_state state = priv->can.state;
 
@@ -509,15 +509,14 @@ static void pch_can_error(struct net_device *ndev, u32 status)
 		can_bus_off(ndev);
 	}
 
-	errc = ioread32(&priv->regs->errc);
 	/* Warning interrupt. */
 	if (status & PCH_EWARN) {
 		state = CAN_STATE_ERROR_WARNING;
 		priv->can.can_stats.error_warning++;
 		cf->can_id |= CAN_ERR_CRTL;
-		if (((errc & PCH_REC) >> 8) > 96)
+		if (cf->data[7] > 96)
 			cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
-		if ((errc & PCH_TEC) > 96)
+		if (cf->data[6] > 96)
 			cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
 		netdev_dbg(ndev,
 			"%s -> Error Counter is more than 96.\n", __func__);
@@ -527,9 +526,9 @@ static void pch_can_error(struct net_device *ndev, u32 status)
 		priv->can.can_stats.error_passive++;
 		state = CAN_STATE_ERROR_PASSIVE;
 		cf->can_id |= CAN_ERR_CRTL;
-		if (((errc & PCH_REC) >> 8) > 127)
+		if (cf->data[7] > 127)
 			cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
-		if ((errc & PCH_TEC) > 127)
+		if (cf->data[7] > 127)
 			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
 		netdev_dbg(ndev,
 			"%s -> CAN controller is ERROR PASSIVE .\n", __func__);
@@ -568,9 +567,6 @@ static void pch_can_error(struct net_device *ndev, u32 status)
 		break;
 	}
 
-	cf->data[6] = errc & PCH_TEC;
-	cf->data[7] = (errc & PCH_REC) >> 8;
-
 	priv->can.state = state;
 	netif_receive_skb(skb);
 
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 0a8de01..1e6b3dd 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -449,22 +449,18 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
 
 	if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
 					 state == CAN_STATE_ERROR_PASSIVE)) {
-		uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
-		uint8_t txerr = priv->read_reg(priv, REG_TXERR);
 		cf->can_id |= CAN_ERR_CRTL;
 		if (state == CAN_STATE_ERROR_WARNING) {
 			priv->can.can_stats.error_warning++;
-			cf->data[1] = (txerr > rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_WARNING :
 				CAN_ERR_CRTL_RX_WARNING;
 		} else {
 			priv->can.can_stats.error_passive++;
-			cf->data[1] = (txerr > rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 				CAN_ERR_CRTL_TX_PASSIVE :
 				CAN_ERR_CRTL_RX_PASSIVE;
 		}
-		cf->data[6] = txerr;
-		cf->data[7] = rxerr;
 	}
 
 	priv->can.state = state;
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 4d07f1e..d16dd00 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -457,6 +457,17 @@ static int ti_hecc_do_set_mode(struct net_device *ndev, enum can_mode mode)
 	return ret;
 }
 
+static int ti_hecc_get_berr_counter(const struct net_device *dev,
+				    struct can_berr_counter *bec)
+{
+	struct ti_hecc_priv *priv = netdev_priv(dev);
+
+	bec->txerr = hecc_read(priv, HECC_CANTEC);
+	bec->rxerr = hecc_read(priv, HECC_CANREC);
+
+	return 0;
+}
+
 /*
  * ti_hecc_xmit: HECC Transmit
  *
@@ -677,9 +688,9 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
 			priv->can.state = CAN_STATE_ERROR_WARNING;
 			++priv->can.can_stats.error_warning;
 			cf->can_id |= CAN_ERR_CRTL;
-			if (hecc_read(priv, HECC_CANTEC) > 96)
+			if (cf->data[6] > 96)
 				cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
-			if (hecc_read(priv, HECC_CANREC) > 96)
+			if (cf->data[7] > 96)
 				cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
 		}
 		hecc_set_bit(priv, HECC_CANES, HECC_CANES_EW);
@@ -692,9 +703,9 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
 			priv->can.state = CAN_STATE_ERROR_PASSIVE;
 			++priv->can.can_stats.error_passive;
 			cf->can_id |= CAN_ERR_CRTL;
-			if (hecc_read(priv, HECC_CANTEC) > 127)
+			if (cf->data[6] > 127)
 				cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
-			if (hecc_read(priv, HECC_CANREC) > 127)
+			if (cf->data[7] > 127)
 				cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
 		}
 		hecc_set_bit(priv, HECC_CANES, HECC_CANES_EP);
@@ -921,6 +932,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
 	priv->can.bittiming_const = &ti_hecc_bittiming_const;
 	priv->can.do_set_mode = ti_hecc_do_set_mode;
 	priv->can.do_get_state = ti_hecc_get_state;
+	priv->can.do_get_berr_counter = ti_hecc_get_berr_counter;
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
 	ndev->irq = irq->start;
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index e75f1a8..d195386 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -344,6 +344,9 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
 	if (skb == NULL)
 		return;
 
+	cf->data[6] = msg->msg.error.cc.regs.sja1000.txerr;
+	cf->data[7] = msg->msg.error.cc.regs.sja1000.rxerr;
+
 	if (msg->type == CPC_MSG_TYPE_CAN_STATE) {
 		u8 state = msg->msg.can_state;
 
@@ -361,8 +364,6 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
 		}
 	} else if (msg->type == CPC_MSG_TYPE_CAN_FRAME_ERROR) {
 		u8 ecc = msg->msg.error.cc.regs.sja1000.ecc;
-		u8 txerr = msg->msg.error.cc.regs.sja1000.txerr;
-		u8 rxerr = msg->msg.error.cc.regs.sja1000.rxerr;
 
 		/* bus error interrupt */
 		dev->can.can_stats.bus_error++;
@@ -392,7 +393,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
 
 		if (dev->can.state == CAN_STATE_ERROR_WARNING ||
 		    dev->can.state == CAN_STATE_ERROR_PASSIVE) {
-			cf->data[1] = (txerr > rxerr) ?
+			cf->data[1] = (cf->data[6] > cf->data[7]) ?
 			    CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE;
 		}
 	} else if (msg->type == CPC_MSG_TYPE_OVERRUN) {
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index dc53c83..4787274 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -294,10 +294,11 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
 					CAN_ERR_CRTL_TX_PASSIVE :
 					CAN_ERR_CRTL_RX_PASSIVE;
 			}
-			cf->data[6] = txerr;
-			cf->data[7] = rxerr;
 		}
 
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
+
 		netif_rx(skb);
 
 		priv->bec.txerr = txerr;
-- 
1.7.2.3

>From 51619f3b1e59b48f5ba97247df94d32aa68c9477 Mon Sep 17 00:00:00 2001
From: Wolfgang Grandegger <[email protected]>
Date: Wed, 23 Mar 2011 17:41:43 +0100
Subject: [PATCH 2/3] can: ti_hecc: fix 'data' is used uninitialized in ti_hecc_xmit()

Signed-off-by: Wolfgang Grandegger <[email protected]>
---
 drivers/net/can/ti_hecc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index d16dd00..871ad92 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -514,9 +514,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
 	spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
 	/* Prepare mailbox for transmission */
+	data = get_tx_head_prio(priv) << 8;
 	if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
 		data |= HECC_CANMCF_RTR;
-	data |= get_tx_head_prio(priv) << 8;
 	hecc_write_mbx(priv, mbxno, HECC_CANMCF, data);
 
 	if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
-- 
1.7.2.3

>From 7e2b48d9e870b71b80ba8626b4b52a2c41567b0c Mon Sep 17 00:00:00 2001
From: Wolfgang Grandegger <[email protected]>
Date: Wed, 23 Mar 2011 18:22:45 +0100
Subject: [PATCH 3/3] can: consolidate CAN error message handling

Signed-off-by: Wolfgang Grandegger <[email protected]>
---
 drivers/net/can/at91_can.c        |   19 +++++-------
 drivers/net/can/bfin_can.c        |   23 +++++++++++---
 drivers/net/can/c_can/c_can.c     |    7 +---
 drivers/net/can/flexcan.c         |   28 +++++++-----------
 drivers/net/can/janz-ican3.c      |   22 +++++++++++++-
 drivers/net/can/pch_can.c         |   57 ++++++++++++++++++-------------------
 drivers/net/can/sja1000/sja1000.c |   23 +++++++++++++--
 drivers/net/can/ti_hecc.c         |   11 ++++--
 include/linux/can/error.h         |    8 +++--
 9 files changed, 119 insertions(+), 79 deletions(-)

diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index f18cba7..67e1bf5 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -649,20 +649,19 @@ static void at91_poll_err_frame(struct net_device *dev,
 {
 	struct at91_priv *priv = netdev_priv(dev);
 
+	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
 	/* CRC error */
 	if (reg_sr & AT91_IRQ_CERR) {
 		netdev_dbg(dev, "CERR irq\n");
 		dev->stats.rx_errors++;
-		priv->can.can_stats.bus_error++;
-		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+		cf->data[2] |= CAN_ERR_PROT_CRC;
 	}
 
 	/* Stuffing Error */
 	if (reg_sr & AT91_IRQ_SERR) {
 		netdev_dbg(dev, "SERR irq\n");
 		dev->stats.rx_errors++;
-		priv->can.can_stats.bus_error++;
-		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 		cf->data[2] |= CAN_ERR_PROT_STUFF;
 	}
 
@@ -670,15 +669,13 @@ static void at91_poll_err_frame(struct net_device *dev,
 	if (reg_sr & AT91_IRQ_AERR) {
 		netdev_dbg(dev, "AERR irq\n");
 		dev->stats.tx_errors++;
-		cf->can_id |= CAN_ERR_ACK;
+		cf->data[2] |= CAN_ERR_PROT_ACK;
 	}
 
 	/* Form error */
 	if (reg_sr & AT91_IRQ_FERR) {
 		netdev_dbg(dev, "FERR irq\n");
 		dev->stats.rx_errors++;
-		priv->can.can_stats.bus_error++;
-		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 		cf->data[2] |= CAN_ERR_PROT_FORM;
 	}
 
@@ -686,10 +683,10 @@ static void at91_poll_err_frame(struct net_device *dev,
 	if (reg_sr & AT91_IRQ_BERR) {
 		netdev_dbg(dev, "BERR irq\n");
 		dev->stats.tx_errors++;
-		priv->can.can_stats.bus_error++;
-		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 		cf->data[2] |= CAN_ERR_PROT_BIT;
 	}
+
+	priv->can.can_stats.bus_error++;
 }
 
 static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr)
@@ -868,8 +865,8 @@ static void at91_irq_err_state(struct net_device *dev,
 		 * the "fallthrough"
 		 */
 		netdev_dbg(dev, "Error Active\n");
-		cf->can_id |= CAN_ERR_PROT;
-		cf->data[2] = CAN_ERR_PROT_ACTIVE;
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[1] = CAN_ERR_CRTL_ACTIVE;
 	case CAN_STATE_ERROR_WARNING:	/* fallthrough */
 		reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_BOFF;
 		reg_ier = AT91_IRQ_ERRP;
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 9c3e78e..f4ce17b 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -400,14 +400,27 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
 
 		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
-		if (status & BEF)
+		cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+		if (status & BEF) {
 			cf->data[2] |= CAN_ERR_PROT_BIT;
-		else if (status & FER)
+			stats->tx_errors++;
+		}
+		if (status & FER) {
 			cf->data[2] |= CAN_ERR_PROT_FORM;
-		else if (status & SER)
+			stats->rx_errors++;
+		}
+		if (status & SER) {
 			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		else
-			cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+			stats->rx_errors++;
+		}
+		if (status & ACKE) {
+			cf->data[2] |= CAN_ERR_PROT_ACK;
+			stats->tx_errors++;
+		}
+		if (status & CRCE) {
+			cf->data[2] |= CAN_ERR_PROT_CRC;
+			stats->rx_errors++;
+		}
 	}
 
 	priv->can.state = state;
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 1405078..119e352 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -906,7 +906,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
 	priv->can.can_stats.bus_error++;
 	stats->rx_errors++;
 	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
-	cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 
 	switch (lec_type) {
 	case LEC_STUFF_ERROR:
@@ -919,8 +918,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
 		break;
 	case LEC_ACK_ERROR:
 		netdev_dbg(dev, "ack error\n");
-		cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
-				CAN_ERR_PROT_LOC_ACK_DEL);
+		cf->data[2] |= CAN_ERR_PROT_ACK;
 		break;
 	case LEC_BIT1_ERROR:
 		netdev_dbg(dev, "bit1 error\n");
@@ -932,8 +930,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
 		break;
 	case LEC_CRC_ERROR:
 		netdev_dbg(dev, "CRC error\n");
-		cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-				CAN_ERR_PROT_LOC_CRC_DEL);
+		cf->data[2] |= CAN_ERR_PROT_CRC;
 		break;
 	default:
 		break;
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 731764f..1d67410 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -290,48 +290,42 @@ static void do_bus_err(struct net_device *dev,
 		       struct can_frame *cf, u32 reg_esr)
 {
 	struct flexcan_priv *priv = netdev_priv(dev);
-	int rx_errors = 0, tx_errors = 0;
 
 	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
+	cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 	if (reg_esr & FLEXCAN_ESR_BIT1_ERR) {
 		dev_dbg(dev->dev.parent, "BIT1_ERR irq\n");
 		cf->data[2] |= CAN_ERR_PROT_BIT1;
-		tx_errors = 1;
+		dev->stats.tx_errors++;
 	}
 	if (reg_esr & FLEXCAN_ESR_BIT0_ERR) {
 		dev_dbg(dev->dev.parent, "BIT0_ERR irq\n");
 		cf->data[2] |= CAN_ERR_PROT_BIT0;
-		tx_errors = 1;
+		dev->stats.tx_errors++;
 	}
 	if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
 		dev_dbg(dev->dev.parent, "ACK_ERR irq\n");
-		cf->can_id |= CAN_ERR_ACK;
-		cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
-		tx_errors = 1;
+		cf->data[2] |= CAN_ERR_PROT_ACK;
+		dev->stats.tx_errors++;
 	}
 	if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
 		dev_dbg(dev->dev.parent, "CRC_ERR irq\n");
-		cf->data[2] |= CAN_ERR_PROT_BIT;
-		cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
-		rx_errors = 1;
+		cf->data[2] |= CAN_ERR_PROT_CRC;
+		dev->stats.rx_errors++;
 	}
 	if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
 		dev_dbg(dev->dev.parent, "FRM_ERR irq\n");
 		cf->data[2] |= CAN_ERR_PROT_FORM;
-		rx_errors = 1;
+		dev->stats.rx_errors++;
 	}
 	if (reg_esr & FLEXCAN_ESR_STF_ERR) {
 		dev_dbg(dev->dev.parent, "STF_ERR irq\n");
 		cf->data[2] |= CAN_ERR_PROT_STUFF;
-		rx_errors = 1;
+		dev->stats.rx_errors++;
 	}
 
 	priv->can.can_stats.bus_error++;
-	if (rx_errors)
-		dev->stats.rx_errors++;
-	if (tx_errors)
-		dev->stats.tx_errors++;
 }
 
 static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
@@ -403,8 +397,8 @@ static void do_state(struct net_device *dev,
 	switch (new_state) {
 	case CAN_STATE_ERROR_ACTIVE:
 		dev_dbg(dev->dev.parent, "Error Active\n");
-		cf->can_id |= CAN_ERR_PROT;
-		cf->data[2] = CAN_ERR_PROT_ACTIVE;
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[2] = CAN_ERR_CRTL_ACTIVE;
 		break;
 	case CAN_STATE_BUS_OFF:
 		cf->can_id |= CAN_ERR_BUSOFF;
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 366f5cc..99a1bc8 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -983,7 +983,6 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
 		dev_dbg(mod->dev, "bus error interrupt\n");
 		mod->can.can_stats.bus_error++;
-		stats->rx_errors++;
 		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
 		switch (ecc & ECC_MASK) {
@@ -999,11 +998,30 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 		default:
 			cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 			cf->data[3] = ecc & ECC_SEG;
+			switch (cf->data[3]) {
+			case CAN_ERR_PROT_LOC_ACK:
+			case CAN_ERR_PROT_LOC_ACK_DEL:
+				cf->data[2] |= CAN_ERR_PROT_ACK;
+				break;
+			case CAN_ERR_PROT_LOC_CRC_SEQ:
+			case CAN_ERR_PROT_LOC_CRC_DEL:
+				cf->data[2] |= CAN_ERR_PROT_CRC;
+				break;
+			default:
+				cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+				break;
+			}
 			break;
 		}
 
-		if ((ecc & ECC_DIR) == 0)
+		/* Error occured during transmission? */
+		if ((ecc & ECC_DIR) == 0) {
 			cf->data[2] |= CAN_ERR_PROT_TX;
+			stats->tx_errors++;
+
+		} else {
+			stats->rx_errors++;
+		}
 
 		cf->data[6] = txerr;
 		cf->data[7] = rxerr;
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index 042ecff..bf4d74a 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -535,36 +535,35 @@ static void pch_can_error(struct net_device *ndev, u32 status)
 	}
 
 	lec = status & PCH_LEC_ALL;
-	switch (lec) {
-	case PCH_STUF_ERR:
-		cf->data[2] |= CAN_ERR_PROT_STUFF;
+	if (lec) {
 		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-		break;
-	case PCH_FORM_ERR:
-		cf->data[2] |= CAN_ERR_PROT_FORM;
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-		break;
-	case PCH_ACK_ERR:
-		cf->can_id |= CAN_ERR_ACK;
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-		break;
-	case PCH_BIT1_ERR:
-	case PCH_BIT0_ERR:
-		cf->data[2] |= CAN_ERR_PROT_BIT;
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-		break;
-	case PCH_CRC_ERR:
-		cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
-			       CAN_ERR_PROT_LOC_CRC_DEL;
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
-		break;
-	case PCH_LEC_ALL: /* Written by CPU. No error status */
-		break;
+		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+		switch (lec) {
+		case PCH_STUF_ERR:
+			cf->data[2] |= CAN_ERR_PROT_STUFF;
+			stats->rx_errors++;
+			break;
+		case PCH_FORM_ERR:
+			cf->data[2] |= CAN_ERR_PROT_FORM;
+			stats->rx_errors++;
+			break;
+		case PCH_ACK_ERR:
+			cf->data[2] |= CAN_ERR_PROT_ACK;
+			stats->tx_errors++;
+			break;
+		case PCH_BIT1_ERR:
+		case PCH_BIT0_ERR:
+			cf->data[2] |= CAN_ERR_PROT_BIT;
+			stats->rx_errors++;
+			break;
+		case PCH_CRC_ERR:
+			cf->data[2] |= CAN_ERR_PROT_CRC;
+			stats->rx_errors++;
+			break;
+		case PCH_LEC_ALL: /* Written by CPU. No error status */
+			break;
+		}
 	}
 
 	priv->can.state = state;
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 1e6b3dd..f171e2d 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -404,7 +404,6 @@ 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, REG_ECC);
 
@@ -421,13 +420,31 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
 			cf->data[2] |= CAN_ERR_PROT_STUFF;
 			break;
 		default:
-			cf->data[2] |= CAN_ERR_PROT_UNSPEC;
 			cf->data[3] = ecc & ECC_SEG;
+			switch (cf->data[3]) {
+			case CAN_ERR_PROT_LOC_ACK:
+			case CAN_ERR_PROT_LOC_ACK_DEL:
+				cf->data[2] |= CAN_ERR_PROT_ACK;
+				break;
+			case CAN_ERR_PROT_LOC_CRC_SEQ:
+			case CAN_ERR_PROT_LOC_CRC_DEL:
+				cf->data[2] |= CAN_ERR_PROT_CRC;
+				break;
+			default:
+				cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+				break;
+			}
 			break;
 		}
+
 		/* Error occured during transmission? */
-		if ((ecc & ECC_DIR) == 0)
+		if ((ecc & ECC_DIR) == 0) {
 			cf->data[2] |= CAN_ERR_PROT_TX;
+			stats->tx_errors++;
+
+		} else {
+			stats->rx_errors++;
+		}
 	}
 	if (isrc & IRQ_EPI) {
 		/* error passive interrupt */
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 871ad92..762ff7f 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -734,24 +734,27 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
 		if (err_status & HECC_CANES_FE) {
 			hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE);
 			cf->data[2] |= CAN_ERR_PROT_FORM;
+			stats->rx_errors++;
 		}
 		if (err_status & HECC_CANES_BE) {
 			hecc_set_bit(priv, HECC_CANES, HECC_CANES_BE);
 			cf->data[2] |= CAN_ERR_PROT_BIT;
+			stats->tx_errors++;
 		}
 		if (err_status & HECC_CANES_SE) {
 			hecc_set_bit(priv, HECC_CANES, HECC_CANES_SE);
 			cf->data[2] |= CAN_ERR_PROT_STUFF;
+			stats->rx_errors++;
 		}
 		if (err_status & HECC_CANES_CRCE) {
 			hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
-			cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL;
+			cf->data[2] |= CAN_ERR_PROT_CRC;
+			stats->rx_errors++;
 		}
 		if (err_status & HECC_CANES_ACKE) {
 			hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
-			cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
-					CAN_ERR_PROT_LOC_ACK_DEL;
+			cf->data[2] |= CAN_ERR_PROT_ACK;
+			stats->tx_errors++;
 		}
 	}
 
diff --git a/include/linux/can/error.h b/include/linux/can/error.h
index d4127fd..b74e85a 100644
--- a/include/linux/can/error.h
+++ b/include/linux/can/error.h
@@ -14,6 +14,8 @@
 #ifndef CAN_ERROR_H
 #define CAN_ERROR_H
 
+#define CAN_ERR_VERSION 1
+
 #define CAN_ERR_DLC 8 /* dlc for error frames */
 
 /* error class (mask) in can_id */
@@ -22,7 +24,6 @@
 #define CAN_ERR_CRTL         0x00000004U /* controller problems / data[1]    */
 #define CAN_ERR_PROT         0x00000008U /* protocol violations / data[2..3] */
 #define CAN_ERR_TRX          0x00000010U /* transceiver status  / data[4]    */
-#define CAN_ERR_ACK          0x00000020U /* received no ACK on transmission */
 #define CAN_ERR_BUSOFF       0x00000040U /* bus off */
 #define CAN_ERR_BUSERROR     0x00000080U /* bus error (may flood!) */
 #define CAN_ERR_RESTARTED    0x00000100U /* controller restarted */
@@ -41,6 +42,7 @@
 #define CAN_ERR_CRTL_TX_PASSIVE  0x20 /* reached error passive status TX */
 				      /* (at least one error counter exceeds */
 				      /* the protocol-defined level of 127)  */
+#define CAN_ERR_CRTL_ACTIVE      0x40 /* active error announcement */
 
 /* error in CAN protocol (type) / data[2] */
 #define CAN_ERR_PROT_UNSPEC      0x00 /* unspecified */
@@ -49,8 +51,8 @@
 #define CAN_ERR_PROT_STUFF       0x04 /* bit stuffing error */
 #define CAN_ERR_PROT_BIT0        0x08 /* unable to send dominant bit */
 #define CAN_ERR_PROT_BIT1        0x10 /* unable to send recessive bit */
-#define CAN_ERR_PROT_OVERLOAD    0x20 /* bus overload */
-#define CAN_ERR_PROT_ACTIVE      0x40 /* active error announcement */
+#define CAN_ERR_PROT_CRC         0x20 /* CRC error */
+#define CAN_ERR_PROT_ACK         0x40 /* received no ACK on transmission */
 #define CAN_ERR_PROT_TX          0x80 /* error occured on transmission */
 
 /* error in CAN protocol (location) / data[3] */
-- 
1.7.2.3

_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to