can: Unify droping of invalid tx skbs and netdev stats
[pandora-kernel.git] / drivers / net / can / mscan / mscan.c
index bb06dfb..40827c1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>,
  *                         Varma Electronics Oy
  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- * Copytight (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
+ * Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
@@ -152,6 +152,12 @@ static int mscan_start(struct net_device *dev)
        priv->shadow_canrier = 0;
        priv->flags = 0;
 
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               /* Clear pending bus-off condition */
+               if (in_8(&regs->canmisc) & MSCAN_BOHOLD)
+                       out_8(&regs->canmisc, MSCAN_BOHOLD);
+       }
+
        err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
        if (err)
                return err;
@@ -163,8 +169,29 @@ static int mscan_start(struct net_device *dev)
        out_8(&regs->cantier, 0);
 
        /* Enable receive interrupts. */
-       out_8(&regs->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
-             MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
+       out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+
+       return 0;
+}
+
+static int mscan_restart(struct net_device *dev)
+{
+       struct mscan_priv *priv = netdev_priv(dev);
+
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
+                    "bus-off state expected");
+               out_8(&regs->canmisc, MSCAN_BOHOLD);
+               /* Re-enable receive interrupts. */
+               out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+       } else {
+               if (priv->can.state <= CAN_STATE_BUS_OFF)
+                       mscan_set_mode(dev, MSCAN_INIT_MODE);
+               return mscan_start(dev);
+       }
 
        return 0;
 }
@@ -177,8 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rtr, buf_id;
        u32 can_id;
 
-       if (frame->can_dlc > 8)
-               return -EINVAL;
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
 
        out_8(&regs->cantier, 0);
 
@@ -297,7 +324,8 @@ static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
        frame->can_id |= can_id >> 1;
        if (can_id & 1)
                frame->can_id |= CAN_RTR_FLAG;
-       frame->can_dlc = in_8(&regs->rx.dlr) & 0xf;
+
+       frame->can_dlc = get_can_dlc(in_8(&regs->rx.dlr) & 0xf);
 
        if (!(frame->can_id & CAN_RTR_FLAG)) {
                void __iomem *data = &regs->rx.dsr1_0;
@@ -358,9 +386,12 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
                         * automatically. To avoid that we stop the chip doing
                         * a light-weight stop (we are in irq-context).
                         */
-                       out_8(&regs->cantier, 0);
-                       out_8(&regs->canrier, 0);
-                       setbits8(&regs->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
+                       if (priv->type != MSCAN_TYPE_MPC5121) {
+                               out_8(&regs->cantier, 0);
+                               out_8(&regs->canrier, 0);
+                               setbits8(&regs->canctl0,
+                                        MSCAN_SLPRQ | MSCAN_INITRQ);
+                       }
                        can_bus_off(dev);
                        break;
                default:
@@ -490,9 +521,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
 
        switch (mode) {
        case CAN_MODE_START:
-               if (priv->can.state <= CAN_STATE_BUS_OFF)
-                       mscan_set_mode(dev, MSCAN_INIT_MODE);
-               ret = mscan_start(dev);
+               ret = mscan_restart(dev);
                if (ret)
                        break;
                if (netif_queue_stopped(dev))
@@ -591,18 +620,21 @@ static const struct net_device_ops mscan_netdev_ops = {
        .ndo_start_xmit         = mscan_start_xmit,
 };
 
-int register_mscandev(struct net_device *dev, int clock_src)
+int register_mscandev(struct net_device *dev, int mscan_clksrc)
 {
        struct mscan_priv *priv = netdev_priv(dev);
        struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
        u8 ctl1;
 
        ctl1 = in_8(&regs->canctl1);
-       if (clock_src)
+       if (mscan_clksrc)
                ctl1 |= MSCAN_CLKSRC;
        else
                ctl1 &= ~MSCAN_CLKSRC;
 
+       if (priv->type == MSCAN_TYPE_MPC5121)
+               ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */
+
        ctl1 |= MSCAN_CANE;
        out_8(&regs->canctl1, ctl1);
        udelay(100);