On Thu, Nov 12, 2009 at 02:17:21PM +0100, Wolfgang Grandegger wrote:

> Fine for me. But how do we select the clocks for the MSCAN on the
> MPC5200? Currently it's implemented as shown below:
> 
>        if (of_get_property(np, "clock-ipb", NULL))
>                 clock_src = MSCAN_CLKSRC_BUS;
>         else
>                 clock_src = MSCAN_CLKSRC_XTAL;
> 
> But we should have something compatible with the MPC512x, e.g.:
> 
>        fsl,mscan-clock-source = "clk-ipb".

Hmmm, will try to come up with something tomorrow.

> Marc has implemented it for the AT91 CAN. Search for "restart_ms" and
> "RESTARTED" in "at_can.c" to understand what I'm speaking about.

Okay, I talked with him and had a try. Could you say if it at least looks not
totally wrong? If it is at least somewhat the right direction? Then, just the
clocking-property is left for tomorrow and I will post the final patch and my
branch.

Regards (and thanks!),

   Wolfram

Subject: [PATCH] [RFC] net/can/mscan: add proper BUS_OFF handling

As hardware recovery can't be switched off, copy the mechanism from at91_can.

Signed-off-by: Wolfram Sang <[email protected]>
---
 drivers/net/can/mscan/mscan.c |   54 +++++++++++++++++++++++++++++-----------
 1 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 71e4233..d734d8b 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -202,6 +202,16 @@ static int mscan_start(struct net_device *dev)
        return 0;
 }
 
+static void mscan_stop(struct net_device *dev)
+{
+       struct mscan_priv *priv = netdev_priv(dev);
+       struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+       out_8(&regs->cantier, 0);
+       out_8(&regs->canrier, 0);
+       mscan_set_mode(dev, MSCAN_INIT_MODE);
+}
+
 static int mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct can_frame *frame = (struct can_frame *)skb->data;
@@ -289,21 +299,20 @@ static int mscan_start_xmit(struct sk_buff *skb, struct 
net_device *dev)
        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;
 }
 
 static int mscan_rx_poll(struct napi_struct *napi, int quota)
@@ -312,6 +321,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int 
quota)
        struct net_device *dev = napi->dev;
        struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
        struct net_device_stats *stats = &dev->stats;
+       enum can_state old_state;
        int npackets = 0;
        int ret = 1;
        struct sk_buff *skb;
@@ -376,7 +386,17 @@ static int mscan_rx_poll(struct napi_struct *napi, int 
quota)
                        } else
                                frame->data[1] = 0;
 
-                       if (check_set_state(dev, canrflg)) {
+                       old_state = check_set_state(dev, canrflg);
+                       /* State out of BUS_OFF */
+                       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);
+                               netif_wake_queue(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;
@@ -401,7 +421,15 @@ static int mscan_rx_poll(struct napi_struct *napi, int 
quota)
                                        break;
                                case CAN_STATE_BUS_OFF:
                                        frame->can_id |= CAN_ERR_BUSOFF;
-                                       can_bus_off(dev);
+                                       netif_carrier_off(dev);
+                                       priv->can.can_stats.bus_off++;
+
+                                       /* turn off chip, if restart is 
disabled */
+                                       if (!priv->can.restart_ms) {
+                                               mscan_stop(dev);
+                                               priv->can.state = 
CAN_STATE_BUS_OFF;
+                                               return 0;       // FIXME: What 
to return here?
+                                       }
                                        break;
                                default:
                                        break;
@@ -578,14 +606,10 @@ static int mscan_open(struct net_device *dev)
 static int mscan_close(struct net_device *dev)
 {
        struct mscan_priv *priv = netdev_priv(dev);
-       struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
 
        netif_stop_queue(dev);
        napi_disable(&priv->napi);
-
-       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;

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

Attachment: signature.asc
Description: Digital signature

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

Reply via email to