aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-04-11 04:13:17 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-04-24 16:09:00 -0400
commitd61d09de023320b95a536eb4d31941e67002a93c (patch)
tree80b68aa639fd6ac670e933ac85e3b3fc94390167
parent2b9aecdce227e099349b73e3a074936d3c51f2a9 (diff)
can: c_can: Work around C_CAN RX wreckage
Alexander reported that the new optimized handling of the RX fifo causes random packet loss on Intel PCH C_CAN hardware. After a few fruitless debugging sessions I got hold of a PCH (eg20t) afflicted system. That machine does not have the CAN interface wired up, but it was possible to reproduce the issue with the HW loopback mode. As Alexander observed correctly, clearing the NewDat flag along with reading out the message buffer causes that issue on C_CAN, while D_CAN handles that correctly. Instead of restoring the original message buffer handling horror the following workaround solves the issue: transfer buffer to IF without clearing the NewDat handle the message clear NewDat bit That's similar to the original code but conditional for C_CAN. I really wonder why all user manuals (C_CAN, Intel PCH and some more) recommend to clear the NewDat bit right away. The knows it all Oracle operated by Gurgle does not unearth any useful information either. I simply cannot believe that we are the first to uncover that HW issue. Reported-and-tested-by: Alexander Stein <alexander.stein@systec-electronic.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/c_can/c_can.c13
-rw-r--r--drivers/net/can/c_can/c_can.h1
2 files changed, 11 insertions, 3 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index c1a8684ed1c8..5d43c5a0e2d9 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -647,6 +647,10 @@ static int c_can_start(struct net_device *dev)
647 if (err) 647 if (err)
648 return err; 648 return err;
649 649
650 /* Setup the command for new messages */
651 priv->comm_rcv_high = priv->type != BOSCH_D_CAN ?
652 IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
653
650 priv->can.state = CAN_STATE_ERROR_ACTIVE; 654 priv->can.state = CAN_STATE_ERROR_ACTIVE;
651 655
652 /* reset tx helper pointers and the rx mask */ 656 /* reset tx helper pointers and the rx mask */
@@ -791,14 +795,15 @@ static u32 c_can_adjust_pending(u32 pend)
791 return pend & ~((1 << lasts) - 1); 795 return pend & ~((1 << lasts) - 1);
792} 796}
793 797
794static inline void c_can_rx_object_get(struct net_device *dev, u32 obj) 798static inline void c_can_rx_object_get(struct net_device *dev,
799 struct c_can_priv *priv, u32 obj)
795{ 800{
796#ifdef CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING 801#ifdef CONFIG_CAN_C_CAN_STRICT_FRAME_ORDERING
797 if (obj < C_CAN_MSG_RX_LOW_LAST) 802 if (obj < C_CAN_MSG_RX_LOW_LAST)
798 c_can_object_get(dev, IF_RX, obj, IF_COMM_RCV_LOW); 803 c_can_object_get(dev, IF_RX, obj, IF_COMM_RCV_LOW);
799 else 804 else
800#endif 805#endif
801 c_can_object_get(dev, IF_RX, obj, IF_COMM_RCV_HIGH); 806 c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high);
802} 807}
803 808
804static inline void c_can_rx_finalize(struct net_device *dev, 809static inline void c_can_rx_finalize(struct net_device *dev,
@@ -813,6 +818,8 @@ static inline void c_can_rx_finalize(struct net_device *dev,
813 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX); 818 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX);
814 } 819 }
815#endif 820#endif
821 if (priv->type != BOSCH_D_CAN)
822 c_can_object_get(dev, IF_RX, obj, IF_COMM_CLR_NEWDAT);
816} 823}
817 824
818static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, 825static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
@@ -823,7 +830,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
823 while ((obj = ffs(pend)) && quota > 0) { 830 while ((obj = ffs(pend)) && quota > 0) {
824 pend &= ~BIT(obj - 1); 831 pend &= ~BIT(obj - 1);
825 832
826 c_can_rx_object_get(dev, obj); 833 c_can_rx_object_get(dev, priv, obj);
827 ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX)); 834 ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
828 835
829 if (ctrl & IF_MCONT_MSGLST) { 836 if (ctrl & IF_MCONT_MSGLST) {
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index cd91960ce92c..792944c74b94 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -198,6 +198,7 @@ struct c_can_priv {
198 u32 __iomem *raminit_ctrlreg; 198 u32 __iomem *raminit_ctrlreg;
199 unsigned int instance; 199 unsigned int instance;
200 void (*raminit) (const struct c_can_priv *priv, bool enable); 200 void (*raminit) (const struct c_can_priv *priv, bool enable);
201 u32 comm_rcv_high;
201 u32 rxmasked; 202 u32 rxmasked;
202 u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; 203 u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
203}; 204};