]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/drivers/net/can/mcp251x.c
To prevent the CAN drivers to operate on invalid socketbuffers the skbs are
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / mcp251x.c
index 1dcda35e0d7da375879695570b6d9abfc6b6832a..cda2b3f806ac74f5d7c07d43bbd7e13332312bd5 100644 (file)
@@ -1,10 +1,11 @@
 /*
- *
  * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
  *
  * MCP2510 support and bug fixes by Christian Pellegrin
  * <chripell@evolware.org>
  *
+ * Copyright 2009 Christian Pellegrin EVOL S.r.l.
+ *
  * Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.
  * Written under contract by:
  *   Chris Elston, Katalix Systems, Ltd.
  *
  * static struct spi_board_info spi_board_info[] = {
  *         {
- *                 .modalias      = "mcp251x",
+ *                 .modalias = "mcp251x",
  *                 .platform_data = &mcp251x_info,
- *                 .irq           = IRQ_EINT13,
- *                 .max_speed_hz  = 2*1000*1000,
- *                 .chip_select   = 2,
+ *                 .irq = IRQ_EINT13,
+ *                 .max_speed_hz = 2*1000*1000,
+ *                 .chip_select = 2,
  *         },
  * };
  *
  *
  */
 
+#include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
+#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
-#include <linux/can/dev.h>
-#include <linux/can/core.h>
-#include <linux/if_arp.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/freezer.h>
 #include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/can/platform/mcp251x.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/platform/mcp251x.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+#error This driver does not support Kernel versions < 2.6.22
+#endif
 
 /* SPI interface instruction set */
-#define INSTRUCTION_WRITE              0x02
-#define INSTRUCTION_READ               0x03
+#define INSTRUCTION_WRITE      0x02
+#define INSTRUCTION_READ       0x03
 #define INSTRUCTION_BIT_MODIFY 0x05
 #define INSTRUCTION_LOAD_TXB(n)        (0x40 + 2 * (n))
 #define INSTRUCTION_READ_RXB(n)        (((n) == 0) ? 0x90 : 0x94)
-#define INSTRUCTION_RESET              0xC0
+#define INSTRUCTION_RESET      0xC0
 
 /* MPC251x registers */
 #define CANSTAT              0x0e
 #define TEC          0x1c
 #define REC          0x1d
 #define CNF1         0x2a
+#  define CNF1_SJW_SHIFT   6
 #define CNF2         0x29
-#  define CNF2_BTLMODE 0x80
+#  define CNF2_BTLMODE    0x80
+#  define CNF2_SAM         0x40
+#  define CNF2_PS1_SHIFT   3
 #define CNF3         0x28
-#  define CNF3_SOF     0x08
-#  define CNF3_WAKFIL  0x04
+#  define CNF3_SOF        0x08
+#  define CNF3_WAKFIL     0x04
 #  define CNF3_PHSEG2_MASK 0x07
 #define CANINTE              0x2b
 #  define CANINTE_MERRE 0x80
 #  define EFLG_TXBO    0x20
 #  define EFLG_RX0OVR  0x40
 #  define EFLG_RX1OVR  0x80
-#define TXBCTRL(n)  ((n * 0x10) + 0x30)
+#define TXBCTRL(n)  (((n) * 0x10) + 0x30 + TXBCTRL_OFF)
 #  define TXBCTRL_ABTF 0x40
 #  define TXBCTRL_MLOA 0x20
 #  define TXBCTRL_TXERR 0x10
 #  define TXBCTRL_TXREQ 0x08
-#define RXBCTRL(n)  ((n * 0x10) + 0x60)
-#  define RXBCTRL_BUKT  0x04
-#  define RXBCTRL_RXM0  0x20
-#  define RXBCTRL_RXM1  0x40
+#define TXBSIDH(n)  (((n) * 0x10) + 0x30 + TXBSIDH_OFF)
+#  define SIDH_SHIFT    3
+#define TXBSIDL(n)  (((n) * 0x10) + 0x30 + TXBSIDL_OFF)
+#  define SIDL_SID_MASK    7
+#  define SIDL_SID_SHIFT   5
+#  define SIDL_EXIDE_SHIFT 3
+#  define SIDL_EID_SHIFT   16
+#  define SIDL_EID_MASK    3
+#define TXBEID8(n)  (((n) * 0x10) + 0x30 + TXBEID8_OFF)
+#define TXBEID0(n)  (((n) * 0x10) + 0x30 + TXBEID0_OFF)
+#define TXBDLC(n)   (((n) * 0x10) + 0x30 + TXBDLC_OFF)
+#  define DLC_RTR_SHIFT    6
+#define TXBCTRL_OFF 0
+#define TXBSIDH_OFF 1
+#define TXBSIDL_OFF 2
+#define TXBEID8_OFF 3
+#define TXBEID0_OFF 4
+#define TXBDLC_OFF  5
+#define TXBDAT_OFF  6
+#define RXBCTRL(n)  (((n) * 0x10) + 0x60 + RXBCTRL_OFF)
+#  define RXBCTRL_BUKT 0x04
+#  define RXBCTRL_RXM0 0x20
+#  define RXBCTRL_RXM1 0x40
+#define RXBSIDH(n)  (((n) * 0x10) + 0x60 + RXBSIDH_OFF)
+#  define RXBSIDH_SHIFT 3
+#define RXBSIDL(n)  (((n) * 0x10) + 0x60 + RXBSIDL_OFF)
+#  define RXBSIDL_IDE   0x08
+#  define RXBSIDL_EID   3
+#  define RXBSIDL_SHIFT 5
+#define RXBEID8(n)  (((n) * 0x10) + 0x60 + RXBEID8_OFF)
+#define RXBEID0(n)  (((n) * 0x10) + 0x60 + RXBEID0_OFF)
+#define RXBDLC(n)   (((n) * 0x10) + 0x60 + RXBDLC_OFF)
+#  define RXBDLC_LEN_MASK  0x0f
+#  define RXBDLC_RTR       0x40
+#define RXBCTRL_OFF 0
+#define RXBSIDH_OFF 1
+#define RXBSIDL_OFF 2
+#define RXBEID8_OFF 3
+#define RXBEID0_OFF 4
+#define RXBDLC_OFF  5
+#define RXBDAT_OFF  6
+
+#define GET_BYTE(val, byte)                    \
+       (((val) >> ((byte) * 8)) & 0xff)
+#define SET_BYTE(val, byte)                    \
+       (((val) & 0xff) << ((byte) * 8))
 
-/* Buffer size required for the largest SPI transfer (i.e., reading a
- * frame). */
+/*
+ * Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame)
+ */
 #define CAN_FRAME_MAX_DATA_LEN 8
-#define SPI_TRANSFER_BUF_LEN   (2*(6 + CAN_FRAME_MAX_DATA_LEN))
+#define SPI_TRANSFER_BUF_LEN   (6 + CAN_FRAME_MAX_DATA_LEN)
 #define CAN_FRAME_MAX_BITS     128
 
+#define TX_ECHO_SKB_MAX        1
+
 #define DEVICE_NAME "mcp251x"
 
 static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
@@ -154,6 +207,7 @@ module_param(mcp251x_enable_dma, int, S_IRUGO);
 MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
 
 static struct can_bittiming_const mcp251x_bittiming_const = {
+       .name = DEVICE_NAME,
        .tseg1_min = 3,
        .tseg1_max = 16,
        .tseg2_min = 2,
@@ -176,6 +230,7 @@ struct mcp251x_priv {
        dma_addr_t spi_rx_dma;
 
        struct sk_buff *tx_skb;
+       int tx_len;
        struct workqueue_struct *wq;
        struct work_struct tx_work;
        struct work_struct irq_work;
@@ -186,27 +241,48 @@ struct mcp251x_priv {
 #define AFTER_SUSPEND_UP 1
 #define AFTER_SUSPEND_DOWN 2
 #define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
        int restart_tx;
 };
 
-static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+static void mcp251x_clean(struct net_device *net)
+{
+       struct mcp251x_priv *priv = netdev_priv(net);
+
+       net->stats.tx_errors++;
+       if (priv->tx_skb)
+               dev_kfree_skb(priv->tx_skb);
+       if (priv->tx_len)
+               can_free_echo_skb(priv->net, 0);
+       priv->tx_skb = NULL;
+       priv->tx_len = 0;
+}
+
+/*
+ * Note about handling of error return of mcp251x_spi_trans: accessing
+ * registers via SPI is not really different conceptually than using
+ * normal I/O assembler instructions, although it's much more
+ * complicated from a practical POV. So it's not advisable to always
+ * check the return value of this function. Imagine that every
+ * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+ * error();", it would be a great mess (well there are some situation
+ * when exception handling C++ like could be useful after all). So we
+ * just check that transfers are OK at the beginning of our
+ * conversation with the chip and to avoid doing really nasty things
+ * (like injecting bogus packets in the network stack).
+ */
+static int mcp251x_spi_trans(struct spi_device *spi, int len)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        struct spi_transfer t = {
                .tx_buf = priv->spi_tx_buf,
                .rx_buf = priv->spi_rx_buf,
-               .len = 3,
+               .len = len,
                .cs_change = 0,
        };
        struct spi_message m;
-       u8 val = 0;
        int ret;
 
-       mutex_lock(&priv->spi_lock);
-
-       priv->spi_tx_buf[0] = INSTRUCTION_READ;
-       priv->spi_tx_buf[1] = reg;
-
        spi_message_init(&m);
 
        if (mcp251x_enable_dma) {
@@ -218,28 +294,32 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
        spi_message_add_tail(&t, &m);
 
        ret = spi_sync(spi, &m);
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
-       else
-               val = priv->spi_rx_buf[2];
+       if (ret)
+               dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
+       return ret;
+}
+
+static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+       u8 val = 0;
+
+       mutex_lock(&priv->spi_lock);
+
+       priv->spi_tx_buf[0] = INSTRUCTION_READ;
+       priv->spi_tx_buf[1] = reg;
+
+       mcp251x_spi_trans(spi, 3);
+       val = priv->spi_rx_buf[2];
 
        mutex_unlock(&priv->spi_lock);
 
-       dev_dbg(&spi->dev, "%s: read %02x = %02x\n", __func__, reg, val);
        return val;
 }
 
 static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-       struct spi_transfer t = {
-               .tx_buf = priv->spi_tx_buf,
-               .rx_buf = priv->spi_rx_buf,
-               .len = 3,
-               .cs_change = 0,
-       };
-       struct spi_message m;
-       int ret;
 
        mutex_lock(&priv->spi_lock);
 
@@ -247,36 +327,15 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
        priv->spi_tx_buf[1] = reg;
        priv->spi_tx_buf[2] = val;
 
-       spi_message_init(&m);
-
-       if (mcp251x_enable_dma) {
-               t.tx_dma = priv->spi_tx_dma;
-               t.rx_dma = priv->spi_rx_dma;
-               m.is_dma_mapped = 1;
-       }
-
-       spi_message_add_tail(&t, &m);
-
-       ret = spi_sync(spi, &m);
+       mcp251x_spi_trans(spi, 3);
 
        mutex_unlock(&priv->spi_lock);
-
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed\n", __func__);
 }
 
 static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
                               u8 mask, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-       struct spi_transfer t = {
-               .tx_buf = priv->spi_tx_buf,
-               .rx_buf = priv->spi_rx_buf,
-               .len = 4,
-               .cs_change = 0,
-       };
-       struct spi_message m;
-       int ret;
 
        mutex_lock(&priv->spi_lock);
 
@@ -285,32 +344,36 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
        priv->spi_tx_buf[2] = mask;
        priv->spi_tx_buf[3] = val;
 
-       spi_message_init(&m);
-
-       if (mcp251x_enable_dma) {
-               t.tx_dma = priv->spi_tx_dma;
-               t.rx_dma = priv->spi_rx_dma;
-               m.is_dma_mapped = 1;
-       }
+       mcp251x_spi_trans(spi, 4);
 
-       spi_message_add_tail(&t, &m);
+       mutex_unlock(&priv->spi_lock);
+}
 
-       ret = spi_sync(spi, &m);
+static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
+                               int len, int tx_buf_idx)
+{
+       struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
 
-       mutex_unlock(&priv->spi_lock);
+       if (pdata->model == CAN_MCP251X_MCP2510) {
+               int i;
 
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed\n", __func__);
+               for (i = 1; i < TXBDAT_OFF + len; i++)
+                       mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
+                                         buf[i]);
+       } else {
+               mutex_lock(&priv->spi_lock);
+               memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
+               mcp251x_spi_trans(spi, TXBDAT_OFF + len);
+               mutex_unlock(&priv->spi_lock);
+       }
 }
 
-static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
                          int tx_buf_idx)
 {
-       struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        u32 sid, eid, exide, rtr;
-
-       dev_dbg(&spi->dev, "%s\n", __func__);
+       u8 buf[SPI_TRANSFER_BUF_LEN];
 
        exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
        if (exide)
@@ -320,202 +383,86 @@ static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
        eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
        rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
 
-       if (pdata->model == CAN_MCP251X_MCP2510) {
-               int i;
-
-               mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 1, sid >> 3);
-               mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 2,
-                                 ((sid & 7) << 5) | (exide << 3) |
-                                 ((eid >> 16) & 3));
-               mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 3,
-                                 (eid >> 8) & 0xff);
-               mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 4, eid & 0xff);
-               mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 5,
-                                 (rtr << 6) | frame->can_dlc);
-
-               for (i = 0; i < frame->can_dlc ; i++) {
-                       mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 6 + i,
-                                         frame->data[i]);
-               }
-       } else {
-               struct spi_transfer t = {
-                       .tx_buf = priv->spi_tx_buf,
-                       .rx_buf = priv->spi_rx_buf,
-                       .cs_change = 0,
-                       .len = 6 + CAN_FRAME_MAX_DATA_LEN,
-               };
-               struct spi_message m;
-               int ret;
-               u8 *tx_buf = priv->spi_tx_buf;
-
-               mutex_lock(&priv->spi_lock);
+       buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
+       buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT;
+       buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) |
+               (exide << SIDL_EXIDE_SHIFT) |
+               ((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);
+       buf[TXBEID8_OFF] = GET_BYTE(eid, 1);
+       buf[TXBEID0_OFF] = GET_BYTE(eid, 0);
+       buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;
+       memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);
+       mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
+       mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+}
 
-               tx_buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
-               tx_buf[1] = sid >> 3;
-               tx_buf[2] = ((sid & 7) << 5) | (exide << 3) |
-                 ((eid >> 16) & 3);
-               tx_buf[3] = (eid >> 8) & 0xff;
-               tx_buf[4] = eid & 0xff;
-               tx_buf[5] = (rtr << 6) | frame->can_dlc;
+static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
+                               int buf_idx)
+{
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+       struct mcp251x_platform_data *pdata = spi->dev.platform_data;
 
-               memcpy(tx_buf + 6, frame->data, frame->can_dlc);
+       if (pdata->model == CAN_MCP251X_MCP2510) {
+               int i, len;
 
-               spi_message_init(&m);
+               for (i = 1; i < RXBDAT_OFF; i++)
+                       buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
 
-               if (mcp251x_enable_dma) {
-                       t.tx_dma = priv->spi_tx_dma;
-                       t.rx_dma = priv->spi_rx_dma;
-                       m.is_dma_mapped = 1;
-               }
-
-               spi_message_add_tail(&t, &m);
+               len = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
+               for (; i < (RXBDAT_OFF + len); i++)
+                       buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+       } else {
+               mutex_lock(&priv->spi_lock);
 
-               ret = spi_sync(spi, &m);
+               priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
+               mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
+               memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
 
                mutex_unlock(&priv->spi_lock);
-
-               if (ret < 0) {
-                       dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__,
-                               ret);
-                       return -1;
-               }
        }
-       mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
-       return 0;
 }
 
 static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-       struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        struct sk_buff *skb;
        struct can_frame *frame;
+       u8 buf[SPI_TRANSFER_BUF_LEN];
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
-       skb = dev_alloc_skb(sizeof(struct can_frame));
+       skb = alloc_can_skb(priv->net, &frame);
        if (!skb) {
-               dev_dbg(&spi->dev, "%s: out of memory for Rx'd frame\n",
-                       __func__);
+               dev_err(&spi->dev, "cannot allocate RX skb\n");
                priv->net->stats.rx_dropped++;
                return;
        }
-       skb->dev = priv->net;
-       frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
-
-       if (pdata->model == CAN_MCP251X_MCP2510) {
-               int i;
-               u8 rx_buf[6];
-
-               rx_buf[1] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 1);
-               rx_buf[2] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 2);
-               rx_buf[3] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 3);
-               rx_buf[4] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 4);
-               rx_buf[5] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 5);
-
-               if ((rx_buf[2] >> 3) & 0x1) {
-                       /* Extended ID format */
-                       frame->can_id = CAN_EFF_FLAG;
-                       frame->can_id |= ((rx_buf[2] & 3) << 16) |
-                         (rx_buf[3] << 8) | rx_buf[4] |
-                         (((rx_buf[1] << 3) | (rx_buf[2] >> 5)) << 18);
-               } else {
-                       /* Standard ID format */
-                       frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
-               }
 
-               if ((rx_buf[5] >> 6) & 0x1) {
-                       /* Remote transmission request */
+       mcp251x_hw_rx_frame(spi, buf, buf_idx);
+       if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {
+               /* Extended ID format */
+               frame->can_id = CAN_EFF_FLAG;
+               frame->can_id |=
+                       /* Extended ID part */
+                       SET_BYTE(buf[RXBSIDL_OFF] & RXBSIDL_EID, 2) |
+                       SET_BYTE(buf[RXBEID8_OFF], 1) |
+                       SET_BYTE(buf[RXBEID0_OFF], 0) |
+                       /* Standard ID part */
+                       (((buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+                         (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT)) << 18);
+               /* Remote transmission request */
+               if (buf[RXBDLC_OFF] & RXBDLC_RTR)
                        frame->can_id |= CAN_RTR_FLAG;
-               }
-
-               /* Data length */
-               frame->can_dlc = rx_buf[5] & 0x0f;
-               if (frame->can_dlc > 8) {
-                       dev_warn(&spi->dev, "invalid frame recevied\n");
-                       priv->net->stats.rx_errors++;
-                       dev_kfree_skb(skb);
-                       return;
-               }
-
-               for (i = 0; i < frame->can_dlc; i++) {
-                       frame->data[i] = mcp251x_read_reg(spi,
-                                                         RXBCTRL(buf_idx) +
-                                                         6 + i);
-               }
        } else {
-               struct spi_transfer t = {
-                       .tx_buf = priv->spi_tx_buf,
-                       .rx_buf = priv->spi_rx_buf,
-                       .cs_change = 0,
-                       .len = 14, /* RX buffer: RXBnCTRL to RXBnD7 */
-               };
-               struct spi_message m;
-               int ret;
-               u8 *tx_buf = priv->spi_tx_buf;
-               u8 *rx_buf = priv->spi_rx_buf;
-
-               mutex_lock(&priv->spi_lock);
-
-               tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
-
-               spi_message_init(&m);
-
-               if (mcp251x_enable_dma) {
-                       t.tx_dma = priv->spi_tx_dma;
-                       t.rx_dma = priv->spi_rx_dma;
-                       m.is_dma_mapped = 1;
-               }
-
-               spi_message_add_tail(&t, &m);
-
-               ret = spi_sync(spi, &m);
-
-               if (ret < 0) {
-                       dev_dbg(&spi->dev, "%s: failed: ret = %d\n",
-                               __func__, ret);
-                       priv->net->stats.rx_errors++;
-                       mutex_unlock(&priv->spi_lock);
-                       return;
-               }
-
-               if ((rx_buf[2] >> 3) & 0x1) {
-                       /* Extended ID format */
-                       frame->can_id = CAN_EFF_FLAG;
-                       frame->can_id |= ((rx_buf[2] & 3) << 16) |
-                         (rx_buf[3] << 8) | rx_buf[4] |
-                         (((rx_buf[1] << 3) | (rx_buf[2] >> 5)) << 18);
-               } else {
-                       /* Standard ID format */
-                       frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
-               }
-
-               if ((rx_buf[5] >> 6) & 0x1) {
-                       /* Remote transmission request */
-                       frame->can_id |= CAN_RTR_FLAG;
-               }
-
-               /* Data length */
-               frame->can_dlc = rx_buf[5] & 0x0f;
-               if (frame->can_dlc > 8) {
-                       dev_warn(&spi->dev, "invalid frame recevied\n");
-                       priv->net->stats.rx_errors++;
-                       dev_kfree_skb(skb);
-                       mutex_unlock(&priv->spi_lock);
-                       return;
-               }
-
-               memcpy(frame->data, rx_buf + 6, CAN_FRAME_MAX_DATA_LEN);
-
-               mutex_unlock(&priv->spi_lock);
+               /* Standard ID format */
+               frame->can_id =
+                       (buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+                       (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);
        }
+       /* Data length */
+       frame->can_dlc = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
+       memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc);
 
        priv->net->stats.rx_packets++;
        priv->net->stats.rx_bytes += frame->can_dlc;
-
-       skb->protocol = __constant_htons(ETH_P_CAN);
-       skb->pkt_type = PACKET_BROADCAST;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
        netif_rx(skb);
 }
 
@@ -539,24 +486,24 @@ static void mcp251x_hw_wakeup(struct spi_device *spi)
                dev_err(&spi->dev, "MCP251x didn't wake-up\n");
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
 static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
+#else
+static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
+                                          struct net_device *net)
+#endif
 {
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
-       if (priv->tx_skb) {
-               dev_warn(&spi->dev, "hard_xmit called with not null tx_skb\n");
+       if (priv->tx_skb || priv->tx_len) {
+               dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+               netif_stop_queue(net);
                return NETDEV_TX_BUSY;
        }
 
-       if (skb->len != sizeof(struct can_frame)) {
-               dev_dbg(&spi->dev, "dropping packet - bad length\n");
-               dev_kfree_skb(skb);
-               net->stats.tx_dropped++;
-               return 0;
-       }
+       if (can_dropped_invalid_skb(net, skb))
+               return NETDEV_TX_OK;
 
        netif_stop_queue(net);
        priv->tx_skb = skb;
@@ -569,11 +516,16 @@ static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
 static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
-       struct spi_device *spi = priv->spi;
-
-       dev_dbg(&spi->dev, "%s (unimplemented)\n", __func__);
 
        switch (mode) {
+       case CAN_MODE_START:
+               /* We have to delay work since SPI I/O may sleep */
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               priv->restart_tx = 1;
+               if (priv->can.restart_ms == 0)
+                       priv->after_suspend = AFTER_SUSPEND_RESTART;
+               queue_work(priv->wq, &priv->irq_work);
+               break;
        default:
                return -EOPNOTSUPP;
        }
@@ -588,8 +540,9 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
 
        /* Enable interrupts */
        mcp251x_write_reg(spi, CANINTE,
-               CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
-               CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE);
+                         CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
+                         CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
+                         CANINTF_MERRF);
 
        if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
                /* Put device into loopback mode */
@@ -600,15 +553,16 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
 
                /* Wait for the device to enter normal mode */
                timeout = jiffies + HZ;
-               while (mcp251x_read_reg(spi, CANSTAT) & 0xE0) {
-                       udelay(10);
+               while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) {
+                       schedule();
                        if (time_after(jiffies, timeout)) {
                                dev_err(&spi->dev, "MCP251x didn't"
                                        " enter in normal mode\n");
-                               break;
+                               return;
                        }
                }
        }
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
 }
 
 static int mcp251x_do_set_bittiming(struct net_device *net)
@@ -616,44 +570,28 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
        struct mcp251x_priv *priv = netdev_priv(net);
        struct can_bittiming *bt = &priv->can.bittiming;
        struct spi_device *spi = priv->spi;
-       u8 state;
 
-       dev_dbg(&spi->dev, "%s: BRP = %d, PropSeg = %d, PS1 = %d,"
-               " PS2 = %d, SJW = %d\n", __func__, bt->brp,
-               bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
-               bt->sjw);
-
-       /* Store original mode and set mode to config */
-       state = mcp251x_read_reg(spi, CANCTRL);
-       state = mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK;
-       mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK,
-                          CANCTRL_REQOP_CONF);
-
-       mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << 6) | (bt->brp - 1));
+       mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << CNF1_SJW_SHIFT) |
+                         (bt->brp - 1));
        mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE |
-                         ((bt->phase_seg1 - 1) << 3) |
+                         (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?
+                          CNF2_SAM : 0) |
+                         ((bt->phase_seg1 - 1) << CNF2_PS1_SHIFT) |
                          (bt->prop_seg - 1));
        mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
                           (bt->phase_seg2 - 1));
-
-       /* Restore original state */
-       mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state);
+       dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+                mcp251x_read_reg(spi, CNF1),
+                mcp251x_read_reg(spi, CNF2),
+                mcp251x_read_reg(spi, CNF3));
 
        return 0;
 }
 
-static void mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
-                         struct spi_device *spi)
+static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
+                        struct spi_device *spi)
 {
-       int ret;
-
-       /* Set initial baudrate. Make sure that registers are updated
-          always by explicitly calling mcp251x_do_set_bittiming */
-       ret = can_set_bittiming(net);
-       if (ret)
-               dev_err(&spi->dev, "unable to set initial baudrate!\n");
-       else
-               mcp251x_do_set_bittiming(net);
+       mcp251x_do_set_bittiming(net);
 
        /* Enable RX0->RX1 buffer roll over and disable filters */
        mcp251x_write_bits(spi, RXBCTRL(0),
@@ -662,10 +600,7 @@ static void mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
        mcp251x_write_bits(spi, RXBCTRL(1),
                           RXBCTRL_RXM0 | RXBCTRL_RXM1,
                           RXBCTRL_RXM0 | RXBCTRL_RXM1);
-
-       dev_dbg(&spi->dev, "%s RXBCTL 0 and 1: %02x %02x\n", __func__,
-               mcp251x_read_reg(spi, RXBCTRL(0)),
-               mcp251x_read_reg(spi, RXBCTRL(1)));
+       return 0;
 }
 
 static void mcp251x_hw_reset(struct spi_device *spi)
@@ -681,9 +616,9 @@ static void mcp251x_hw_reset(struct spi_device *spi)
 
        mutex_unlock(&priv->spi_lock);
 
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
-       /* wait for reset to finish */
+       if (ret)
+               dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+       /* Wait for reset to finish */
        mdelay(10);
 }
 
@@ -693,33 +628,74 @@ static int mcp251x_hw_probe(struct spi_device *spi)
 
        mcp251x_hw_reset(spi);
 
+       /*
+        * Please note that these are "magic values" based on after
+        * reset defaults taken from data sheet which allows us to see
+        * if we really have a chip on the bus (we avoid common all
+        * zeroes or all ones situations)
+        */
        st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
        st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
 
-       dev_dbg(&spi->dev, "%s: 0x%02x - 0x%02x\n", __func__,
-               st1, st2);
+       dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
 
-       /* check for power up default values */
+       /* Check for power up default values */
        return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
 }
 
+static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+{
+       struct net_device *net = (struct net_device *)dev_id;
+       struct mcp251x_priv *priv = netdev_priv(net);
+
+       /* Schedule bottom half */
+       if (!work_pending(&priv->irq_work))
+               queue_work(priv->wq, &priv->irq_work);
+
+       return IRQ_HANDLED;
+}
+
 static int mcp251x_open(struct net_device *net)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+       int ret;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
+       ret = open_candev(net);
+       if (ret) {
+               dev_err(&spi->dev, "unable to set initial baudrate!\n");
+               return ret;
+       }
 
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(1);
 
        priv->force_quit = 0;
        priv->tx_skb = NULL;
-       enable_irq(spi->irq);
+       priv->tx_len = 0;
+
+       ret = request_irq(spi->irq, mcp251x_can_isr,
+                         IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
+       if (ret) {
+               dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+               if (pdata->transceiver_enable)
+                       pdata->transceiver_enable(0);
+               close_candev(net);
+               return ret;
+       }
+
        mcp251x_hw_wakeup(spi);
        mcp251x_hw_reset(spi);
-       mcp251x_setup(net, priv, spi);
+       ret = mcp251x_setup(net, priv, spi);
+       if (ret) {
+               free_irq(spi->irq, net);
+               mcp251x_hw_sleep(spi);
+               if (pdata->transceiver_enable)
+                       pdata->transceiver_enable(0);
+               close_candev(net);
+               return ret;
+       }
        mcp251x_set_normal_mode(spi);
        netif_wake_queue(net);
 
@@ -732,47 +708,26 @@ static int mcp251x_stop(struct net_device *net)
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
+       close_candev(net);
 
        /* Disable and clear pending interrupts */
        mcp251x_write_reg(spi, CANINTE, 0x00);
        mcp251x_write_reg(spi, CANINTF, 0x00);
 
        priv->force_quit = 1;
-       disable_irq(spi->irq);
+       free_irq(spi->irq, net);
        flush_workqueue(priv->wq);
 
        mcp251x_write_reg(spi, TXBCTRL(0), 0);
-       if (priv->tx_skb) {
-               net->stats.tx_errors++;
-               dev_kfree_skb(priv->tx_skb);
-               priv->tx_skb = NULL;
-       }
+       if (priv->tx_skb || priv->tx_len)
+               mcp251x_clean(net);
 
        mcp251x_hw_sleep(spi);
 
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(0);
 
-       return 0;
-}
-
-static int mcp251x_do_get_state(struct net_device *net, enum can_state *state)
-{
-       struct mcp251x_priv *priv = netdev_priv(net);
-       struct spi_device *spi = priv->spi;
-       u8 eflag;
-
-       eflag = mcp251x_read_reg(spi, EFLG);
-
-       if (eflag & EFLG_TXBO)
-               *state = CAN_STATE_BUS_OFF;
-       else if (eflag & (EFLG_RXEP | EFLG_TXEP))
-               *state = CAN_STATE_BUS_PASSIVE;
-       else if (eflag & EFLG_EWARN)
-               *state = CAN_STATE_BUS_WARNING;
-       else
-               *state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_STOPPED;
 
        return 0;
 }
@@ -782,15 +737,23 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
        struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
                                                 tx_work);
        struct spi_device *spi = priv->spi;
+       struct net_device *net = priv->net;
        struct can_frame *frame;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        if (priv->tx_skb) {
                frame = (struct can_frame *)priv->tx_skb->data;
+
+               if (priv->can.state == CAN_STATE_BUS_OFF) {
+                       mcp251x_clean(net);
+                       netif_wake_queue(net);
+                       return;
+               }
                if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
                        frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
                mcp251x_hw_tx(spi, frame, 0);
+               priv->tx_len = 1 + frame->can_dlc;
+               can_put_echo_skb(priv->tx_skb, net, 0);
+               priv->tx_skb = NULL;
        }
 }
 
@@ -800,42 +763,46 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                                                 irq_work);
        struct spi_device *spi = priv->spi;
        struct net_device *net = priv->net;
-       u8 intf;
        u8 txbnctrl;
+       u8 intf;
+       enum can_state new_state;
 
        if (priv->after_suspend) {
-               /* Wait whilst the device wakes up */
                mdelay(10);
                mcp251x_hw_reset(spi);
                mcp251x_setup(net, priv, spi);
-               if (priv->after_suspend & AFTER_SUSPEND_UP) {
+               if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
+                       mcp251x_set_normal_mode(spi);
+               } else if (priv->after_suspend & AFTER_SUSPEND_UP) {
                        netif_device_attach(net);
-                       /* clear since we lost tx buffer */
-                       if (priv->tx_skb) {
-                               net->stats.tx_errors++;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
+                       /* Clean since we lost tx buffer */
+                       if (priv->tx_skb || priv->tx_len) {
+                               mcp251x_clean(net);
                                netif_wake_queue(net);
                        }
                        mcp251x_set_normal_mode(spi);
-               } else
+               } else {
                        mcp251x_hw_sleep(spi);
+               }
                priv->after_suspend = 0;
-               return;
        }
 
+       if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF)
+               return;
+
        while (!priv->force_quit && !freezing(current)) {
+               u8 eflag = mcp251x_read_reg(spi, EFLG);
+               int can_id = 0, data1 = 0;
+
+               mcp251x_write_reg(spi, EFLG, 0x00);
+
                if (priv->restart_tx) {
                        priv->restart_tx = 0;
-                       dev_warn(&spi->dev,
-                                "timeout in txing a packet, restarting\n");
                        mcp251x_write_reg(spi, TXBCTRL(0), 0);
-                       if (priv->tx_skb) {
-                               net->stats.tx_errors++;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
-                       }
+                       if (priv->tx_skb || priv->tx_len)
+                               mcp251x_clean(net);
                        netif_wake_queue(net);
+                       can_id |= CAN_ERR_RESTARTED;
                }
 
                if (priv->wake) {
@@ -845,104 +812,107 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                }
 
                intf = mcp251x_read_reg(spi, CANINTF);
-               if (intf == 0x00)
-                       break;
                mcp251x_write_bits(spi, CANINTF, intf, 0x00);
 
-               dev_dbg(&spi->dev, "interrupt:%s%s%s%s%s%s%s%s\n",
-                       (intf & CANINTF_MERRF) ? " MERR" : "",
-                       (intf & CANINTF_WAKIF) ? " WAK" : "",
-                       (intf & CANINTF_ERRIF) ? " ERR" : "",
-                       (intf & CANINTF_TX2IF) ? " TX2" : "",
-                       (intf & CANINTF_TX1IF) ? " TX1" : "",
-                       (intf & CANINTF_TX0IF) ? " TX0" : "",
-                       (intf & CANINTF_RX1IF) ? " RX1" : "",
-                       (intf & CANINTF_RX0IF) ? " RX0" : "");
-
-               if (intf & CANINTF_WAKIF)
-                       complete(&priv->awake);
+               /* Update can state */
+               if (eflag & EFLG_TXBO) {
+                       new_state = CAN_STATE_BUS_OFF;
+                       can_id |= CAN_ERR_BUSOFF;
+               } else if (eflag & EFLG_TXEP) {
+                       new_state = CAN_STATE_ERROR_PASSIVE;
+                       can_id |= CAN_ERR_CRTL;
+                       data1 |= CAN_ERR_CRTL_TX_PASSIVE;
+               } else if (eflag & EFLG_RXEP) {
+                       new_state = CAN_STATE_ERROR_PASSIVE;
+                       can_id |= CAN_ERR_CRTL;
+                       data1 |= CAN_ERR_CRTL_RX_PASSIVE;
+               } else if (eflag & EFLG_TXWAR) {
+                       new_state = CAN_STATE_ERROR_WARNING;
+                       can_id |= CAN_ERR_CRTL;
+                       data1 |= CAN_ERR_CRTL_TX_WARNING;
+               } else if (eflag & EFLG_RXWAR) {
+                       new_state = CAN_STATE_ERROR_WARNING;
+                       can_id |= CAN_ERR_CRTL;
+                       data1 |= CAN_ERR_CRTL_RX_WARNING;
+               } else {
+                       new_state = CAN_STATE_ERROR_ACTIVE;
+               }
 
-               if (intf & CANINTF_MERRF) {
-                       /* if there are no pending Tx buffers, restart queue */
-                       txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
-                       if (!(txbnctrl & TXBCTRL_TXREQ)) {
-                               if (priv->tx_skb) {
-                                       net->stats.tx_errors++;
-                                       dev_kfree_skb(priv->tx_skb);
-                                       priv->tx_skb = NULL;
-                               }
-                               netif_wake_queue(net);
-                       }
+               /* Update can state statistics */
+               switch (priv->can.state) {
+               case CAN_STATE_ERROR_ACTIVE:
+                       if (new_state >= CAN_STATE_ERROR_WARNING &&
+                           new_state <= CAN_STATE_BUS_OFF)
+                               priv->can.can_stats.error_warning++;
+               case CAN_STATE_ERROR_WARNING:   /* fallthrough */
+                       if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+                           new_state <= CAN_STATE_BUS_OFF)
+                               priv->can.can_stats.error_passive++;
+                       break;
+               default:
+                       break;
                }
+               priv->can.state = new_state;
 
-               if (intf & CANINTF_ERRIF) {
+               if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
                        struct sk_buff *skb;
-                       struct can_frame *frame = NULL;
-                       u8 eflag = mcp251x_read_reg(spi, EFLG);
-
-                       dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflag);
+                       struct can_frame *frame;
 
                        /* Create error frame */
-                       skb = dev_alloc_skb(sizeof(struct can_frame));
+                       skb = alloc_can_err_skb(net, &frame);
                        if (skb) {
-                               frame = (struct can_frame *)
-                                       skb_put(skb, sizeof(struct can_frame));
-                               *(unsigned long long *)&frame->data = 0ULL;
-                               frame->can_id = CAN_ERR_FLAG;
-                               frame->can_dlc = CAN_ERR_DLC;
-
-                               skb->dev = net;
-                               skb->protocol = __constant_htons(ETH_P_CAN);
-                               skb->pkt_type = PACKET_BROADCAST;
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
                                /* Set error frame flags based on bus state */
-                               if (eflag & EFLG_TXBO) {
-                                       frame->can_id |= CAN_ERR_BUSOFF;
-                               } else if (eflag & EFLG_TXEP) {
-                                       frame->can_id |= CAN_ERR_CRTL;
-                                       frame->data[1] |=
-                                         CAN_ERR_CRTL_TX_PASSIVE;
-                               } else if (eflag & EFLG_RXEP) {
-                                       frame->can_id |= CAN_ERR_CRTL;
-                                       frame->data[1] |=
-                                         CAN_ERR_CRTL_RX_PASSIVE;
-                               } else if (eflag & EFLG_TXWAR) {
-                                       frame->can_id |= CAN_ERR_CRTL;
-                                       frame->data[1] |=
-                                         CAN_ERR_CRTL_TX_WARNING;
-                               } else if (eflag & EFLG_RXWAR) {
+                               frame->can_id = can_id;
+                               frame->data[1] = data1;
+
+                               /* Update net stats for overflows */
+                               if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+                                       if (eflag & EFLG_RX0OVR)
+                                               net->stats.rx_over_errors++;
+                                       if (eflag & EFLG_RX1OVR)
+                                               net->stats.rx_over_errors++;
                                        frame->can_id |= CAN_ERR_CRTL;
                                        frame->data[1] |=
-                                         CAN_ERR_CRTL_RX_WARNING;
+                                               CAN_ERR_CRTL_RX_OVERFLOW;
                                }
+
+                               netif_rx(skb);
+                       } else {
+                               dev_info(&spi->dev,
+                                        "cannot allocate error skb\n");
                        }
+               }
 
-                       if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
-                               if (eflag & EFLG_RX0OVR)
-                                       net->stats.rx_over_errors++;
-                               if (eflag & EFLG_RX1OVR)
-                                       net->stats.rx_over_errors++;
-                               if (frame) {
-                                       frame->can_id |= CAN_ERR_CRTL;
-                                       frame->data[1] =
-                                         CAN_ERR_CRTL_RX_OVERFLOW;
-                               }
+               if (priv->can.state == CAN_STATE_BUS_OFF) {
+                       if (priv->can.restart_ms == 0) {
+                               can_bus_off(net);
+                               mcp251x_hw_sleep(spi);
+                               return;
                        }
-                       mcp251x_write_reg(spi, EFLG, 0x00);
+               }
 
-                       if (skb)
-                               netif_rx(skb);
+               if (intf == 0)
+                       break;
+
+               if (intf & CANINTF_WAKIF)
+                       complete(&priv->awake);
+
+               if (intf & CANINTF_MERRF) {
+                       /* If there are pending Tx buffers, restart queue */
+                       txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
+                       if (!(txbnctrl & TXBCTRL_TXREQ)) {
+                               if (priv->tx_skb || priv->tx_len)
+                                       mcp251x_clean(net);
+                               netif_wake_queue(net);
+                       }
                }
 
                if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
-                       if (priv->tx_skb) {
-                               net->stats.tx_packets++;
-                               net->stats.tx_bytes +=
-                                       ((struct can_frame *)
-                                        (priv->tx_skb->data))->can_dlc;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
+                       net->stats.tx_packets++;
+                       net->stats.tx_bytes += priv->tx_len - 1;
+                       if (priv->tx_len) {
+                               can_get_echo_skb(net, 0);
+                               priv->tx_len = 0;
                        }
                        netif_wake_queue(net);
                }
@@ -952,60 +922,16 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
 
                if (intf & CANINTF_RX1IF)
                        mcp251x_hw_rx(spi, 1);
-
        }
-
-       mcp251x_read_reg(spi, CANSTAT);
-
-       dev_dbg(&spi->dev, "interrupt ended\n");
-}
-
-static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
-{
-       struct net_device *net = (struct net_device *)dev_id;
-       struct mcp251x_priv *priv = netdev_priv(net);
-
-       dev_dbg(&priv->spi->dev, "%s: irq\n", __func__);
-       /* Schedule bottom half */
-       if (!work_pending(&priv->irq_work))
-               queue_work(priv->wq, &priv->irq_work);
-
-       return IRQ_HANDLED;
-}
-
-static void mcp251x_tx_timeout(struct net_device *net)
-{
-       struct mcp251x_priv *priv = netdev_priv(net);
-
-       priv->restart_tx = 1;
-       queue_work(priv->wq, &priv->irq_work);
 }
 
-static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
-{
-       struct net_device *net;
-       struct mcp251x_priv *priv;
-
-       net = alloc_candev(sizeof_priv);
-       if (!net)
-               return NULL;
-
-       priv = netdev_priv(net);
-
-       net->open               = mcp251x_open;
-       net->stop               = mcp251x_stop;
-       net->hard_start_xmit    = mcp251x_hard_start_xmit;
-       net->tx_timeout         = mcp251x_tx_timeout;
-       net->watchdog_timeo     = HZ;
-
-       priv->can.bittiming_const = &mcp251x_bittiming_const;
-       priv->can.do_get_state    = mcp251x_do_get_state;
-       priv->can.do_set_mode     = mcp251x_do_set_mode;
-
-       priv->net = net;
-
-       return net;
-}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops mcp251x_netdev_ops = {
+       .ndo_open = mcp251x_open,
+       .ndo_stop = mcp251x_stop,
+       .ndo_start_xmit = mcp251x_hard_start_xmit,
+};
+#endif
 
 static int __devinit mcp251x_can_probe(struct spi_device *spi)
 {
@@ -1014,40 +940,54 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        int ret = -ENODEV;
 
-       if (!pdata) {
+       if (!pdata)
                /* Platform data is required for osc freq */
                goto error_out;
-       }
 
        /* Allocate can/net device */
-       net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv));
+       net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
        if (!net) {
                ret = -ENOMEM;
                goto error_alloc;
        }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       net->netdev_ops = &mcp251x_netdev_ops;
+#else
+       net->open = mcp251x_open;
+       net->stop = mcp251x_stop;
+       net->hard_start_xmit = mcp251x_hard_start_xmit;
+#endif
+       net->flags |= IFF_ECHO;
+
        priv = netdev_priv(net);
+       priv->can.bittiming_const = &mcp251x_bittiming_const;
+       priv->can.do_set_mode = mcp251x_do_set_mode;
+       priv->can.clock.freq = pdata->oscillator_frequency / 2;
+       priv->net = net;
        dev_set_drvdata(&spi->dev, priv);
 
        priv->spi = spi;
        mutex_init(&priv->spi_lock);
 
-       priv->can.bittiming.clock = pdata->oscillator_frequency / 2;
-
        /* If requested, allocate DMA buffers */
        if (mcp251x_enable_dma) {
-               spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
+               spi->dev.coherent_dma_mask = ~0;
 
-               /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
-                  that much and share it between Tx and Rx DMA buffers. */
+               /*
+                * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+                * that much and share it between Tx and Rx DMA buffers.
+                */
                priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
-                       PAGE_SIZE, &priv->spi_tx_dma, GFP_DMA);
+                                                     PAGE_SIZE,
+                                                     &priv->spi_tx_dma,
+                                                     GFP_DMA);
 
                if (priv->spi_tx_buf) {
                        priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
-                               (PAGE_SIZE / 2));
+                                                 (PAGE_SIZE / 2));
                        priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
-                               (PAGE_SIZE / 2));
+                                                       (PAGE_SIZE / 2));
                } else {
                        /* Fall back to non-DMA */
                        mcp251x_enable_dma = 0;
@@ -1062,7 +1002,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
                        goto error_tx_buf;
                }
                priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
-               if (!priv->spi_tx_buf) {
+               if (!priv->spi_rx_buf) {
                        ret = -ENOMEM;
                        goto error_rx_buf;
                }
@@ -1089,14 +1029,6 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        spi->bits_per_word = 8;
        spi_setup(spi);
 
-       /* Register IRQ */
-       if (request_irq(spi->irq, mcp251x_can_isr,
-                       IRQF_TRIGGER_FALLING, DEVICE_NAME, net) < 0) {
-               dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
-               goto error_irq;
-       }
-       disable_irq(spi->irq);
-
        if (!mcp251x_hw_probe(spi)) {
                dev_info(&spi->dev, "Probe failed\n");
                goto error_probe;
@@ -1107,13 +1039,11 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
                pdata->transceiver_enable(0);
 
        ret = register_candev(net);
-       if (ret >= 0) {
+       if (!ret) {
                dev_info(&spi->dev, "probed\n");
                return ret;
        }
 error_probe:
-       free_irq(spi->irq, net);
-error_irq:
        if (!mcp251x_enable_dma)
                kfree(priv->spi_rx_buf);
 error_rx_buf:
@@ -1121,11 +1051,12 @@ error_rx_buf:
                kfree(priv->spi_tx_buf);
 error_tx_buf:
        free_candev(net);
-       if (mcp251x_enable_dma) {
+       if (mcp251x_enable_dma)
                dma_free_coherent(&spi->dev, PAGE_SIZE,
-                       priv->spi_tx_buf, priv->spi_tx_dma);
-       }
+                                 priv->spi_tx_buf, priv->spi_tx_dma);
 error_alloc:
+       if (pdata->power_enable)
+               pdata->power_enable(0);
        dev_err(&spi->dev, "probe failed\n");
 error_out:
        return ret;
@@ -1140,14 +1071,13 @@ static int __devexit mcp251x_can_remove(struct spi_device *spi)
        unregister_candev(net);
        free_candev(net);
 
-       free_irq(spi->irq, net);
        priv->force_quit = 1;
        flush_workqueue(priv->wq);
        destroy_workqueue(priv->wq);
 
        if (mcp251x_enable_dma) {
                dma_free_coherent(&spi->dev, PAGE_SIZE,
-                       priv->spi_tx_buf, priv->spi_tx_dma);
+                                 priv->spi_tx_buf, priv->spi_tx_dma);
        } else {
                kfree(priv->spi_tx_buf);
                kfree(priv->spi_rx_buf);
@@ -1173,8 +1103,9 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
                if (pdata->transceiver_enable)
                        pdata->transceiver_enable(0);
                priv->after_suspend = AFTER_SUSPEND_UP;
-       } else
+       } else {
                priv->after_suspend = AFTER_SUSPEND_DOWN;
+       }
 
        if (pdata->power_enable) {
                pdata->power_enable(0);
@@ -1197,8 +1128,9 @@ static int mcp251x_can_resume(struct spi_device *spi)
                        if (pdata->transceiver_enable)
                                pdata->transceiver_enable(1);
                        queue_work(priv->wq, &priv->irq_work);
-               } else
+               } else {
                        priv->after_suspend = 0;
+               }
        }
        return 0;
 }
@@ -1209,15 +1141,15 @@ static int mcp251x_can_resume(struct spi_device *spi)
 
 static struct spi_driver mcp251x_can_driver = {
        .driver = {
-               .name           = DEVICE_NAME,
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
+               .name = DEVICE_NAME,
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
        },
 
-       .probe          = mcp251x_can_probe,
-       .remove         = __devexit_p(mcp251x_can_remove),
-       .suspend        = mcp251x_can_suspend,
-       .resume         = mcp251x_can_resume,
+       .probe = mcp251x_can_probe,
+       .remove = __devexit_p(mcp251x_can_remove),
+       .suspend = mcp251x_can_suspend,
+       .resume = mcp251x_can_resume,
 };
 
 static int __init mcp251x_can_init(void)