Hi Wolfram,

Wolfgang Grandegger wrote:
> Wolfgang Grandegger wrote:
>> Wolfram Sang wrote:
>>>> Well, to save a test cycle, I'm awaiting for your patch first.
>>> That's probably a good idea, I don't even know if this patch applies without
>>> the rest of my branch.
>>>
>>> I just saw there is one FIXME left in the code. If you can comment on this,
>>> this would be much appreciated, as I don't know the napi-framework a bit and
>>> cannot judge if it should return 0 there or better -ENOSOMETHING in that 
>>> case.
> 
> I have attached my untested patch for SVN trunk fixing the bus-off
> recovery.
> 
>> Well, I tried to apply the patch to the SVN trunk, which failed :-).
>> Will fix and test now.
> 
> Failed again because you fixed the open issue with base_address :-).
> Please send your patch and I will check and test.

I'm doing some test now, but the beast does not behave like expected :-(:

restart-ms=0 works fine:

  short-circuiting wires
  can2   87  [4] 12 34 56 67
  can2  20000004  [8] 00 08 00 00 00 00 00 00   ERRORFRAME
  can2  20000040  [8] 00 00 00 00 00 00 00 00   ERRORFRAME
              ^ bus-off
  can2  20000100  [8] 00 00 00 00 00 00 00 00   ERRORFRAME
             ^ manual restart

restart>0 does not:

  short-circuiting wires
  can2   87  [4] 12 34 56 67
  can2  20000004  [8] 00 08 00 00 00 00 00 00   ERRORFRAME
  can2  20000040  [8] 00 00 00 00 00 00 00 00   ERRORFRAME
  removing short-circuit
  can2   87  [4] 12 34 56 67

As you can see, the message gets through after removing the
short-circuit but no state change interrupt is triggered. This is
confirmed by the dmesg lines below:

[ 4290.511451] mpc52xx_can f0000900.can: error interrupt (canrflg=0x44)
[ 4290.514611] mpc52xx_can f0000900.can: error interrupt (canrflg=0x7c)
[ 4290.514671] mpc52xx_can f0000900.can: bus-off
[ 4292.142115] mpc52xx_can f0000900.can: TX done (canrflg=0x8)

Either we capture the TX done after BUS-OFF and check the state (which
is non-trivial) or we do not allow automatic recovery at all. Attached
is my revised patch for this test. I'm also not happy that we call
mscan_stop() from the interrupt context.

Wolfgang.



---
 kernel/2.6/drivers/net/can/mscan/mscan.c |   61 +++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 14 deletions(-)

Index: trunk/kernel/2.6/drivers/net/can/mscan/mscan.c
===================================================================
--- trunk.orig/kernel/2.6/drivers/net/can/mscan/mscan.c
+++ trunk/kernel/2.6/drivers/net/can/mscan/mscan.c
@@ -237,6 +237,15 @@ static int mscan_start(struct net_device
 	return 0;
 }
 
+static void mscan_stop(struct net_device *dev)
+{
+	struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
+
+	out_8(&regs->cantier, 0);
+	out_8(&regs->canrier, 0);
+	mscan_set_mode(dev, MSCAN_INIT_MODE);
+}
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
 static int mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 #else
@@ -326,21 +335,20 @@ static netdev_tx_t mscan_start_xmit(stru
 	return NETDEV_TX_OK;
 }
 
-static inline int check_set_state(struct net_device *dev, u8 canrflg)
+/* This function returns the old state to see where we came from */
+static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
 {
 	struct mscan_priv *priv = netdev_priv(dev);
-	enum can_state state;
-	int ret = 0;
+	enum can_state state, old_state = priv->can.state;
 
-	if (!(canrflg & MSCAN_CSCIF) || priv->can.state > CAN_STATE_BUS_OFF)
-		return 0;
+	if (!(canrflg & MSCAN_CSCIF) || old_state > CAN_STATE_BUS_OFF)
+		return old_state;
 
 	state = state_map[max(MSCAN_STATE_RX(canrflg),
 			      MSCAN_STATE_TX(canrflg))];
-	if (priv->can.state < state)
-		ret = 1;
+
 	priv->can.state = state;
-	return ret;
+	return old_state;
 }
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
@@ -365,6 +373,7 @@ static int mscan_rx_poll(struct net_devi
 #else
 	struct net_device_stats *stats = &dev->stats;
 #endif
+	enum can_state old_state;
 	int npackets = 0;
 	int ret = 1;
 	struct sk_buff *skb;
@@ -431,7 +440,16 @@ static int mscan_rx_poll(struct net_devi
 			} else
 				frame->data[1] = 0;
 
-			if (check_set_state(dev, canrflg)) {
+			old_state = check_set_state(dev, canrflg);
+			/* State out of BUS_OFF (automatic recovery) */
+			if (old_state == CAN_STATE_BUS_OFF
+			    && priv->can.state < old_state) {
+				frame->can_id |= CAN_ERR_RESTARTED;
+				priv->can.can_stats.restarts++;
+				netif_carrier_on(dev);
+			}
+			/* State got worse */
+			if (old_state < priv->can.state) {
 				switch (priv->can.state) {
 				case CAN_STATE_ERROR_WARNING:
 					frame->can_id |= CAN_ERR_CRTL;
@@ -456,7 +474,22 @@ static int mscan_rx_poll(struct net_devi
 					break;
 				case CAN_STATE_BUS_OFF:
 					frame->can_id |= CAN_ERR_BUSOFF;
-					can_bus_off(dev);
+					/*
+					 * The MSCAN on the MPC5200 does recover
+					 * from bus-off automatically. Therefore
+					 * we stop the chip if the user wants
+					 * to restart the chip.
+					 */
+					if (priv->can.restart_ms) {
+						netif_carrier_off(dev);
+						dev_dbg(ND2D(dev), "bus-off");
+						priv->can.can_stats.bus_off++;
+					} else {
+						mscan_stop(dev);
+						priv->can.state =
+							CAN_STATE_BUS_OFF;
+						can_bus_off(dev);
+					}
 					break;
 				default:
 					break;
@@ -516,6 +549,9 @@ static irqreturn_t mscan_isr(int irq, vo
 
 		struct list_head *tmp, *pos;
 
+		dev_dbg(ND2D(dev), "TX done (canrflg=%#x)\n",
+			in_8(&regs->canrflg));
+
 		list_for_each_safe(pos, tmp, &priv->tx_head) {
 			struct tx_queue_entry *entry =
 			    list_entry(pos, struct tx_queue_entry, list);
@@ -661,7 +697,6 @@ static int mscan_open(struct net_device 
 
 static int mscan_close(struct net_device *dev)
 {
-	struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
 	struct mscan_priv *priv = netdev_priv(dev);
 
 	netif_stop_queue(dev);
@@ -669,9 +704,7 @@ static int mscan_close(struct net_device
 	napi_disable(&priv->napi);
 #endif
 
-	out_8(&regs->cantier, 0);
-	out_8(&regs->canrier, 0);
-	mscan_set_mode(dev, MSCAN_INIT_MODE);
+	mscan_stop(dev);
 	close_candev(dev);
 	free_irq(dev->irq, dev);
 	priv->open_time = 0;
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to