This patch clears the MCP251x SPI driver in trunk for mainline submission. CAN bus transitions should be correctly handled now.
Signed-off-by: Christian Pellegrin <[email protected]> --- Index: drivers/net/can/mcp251x.c =================================================================== --- drivers/net/can/mcp251x.c (revision 1070) +++ drivers/net/can/mcp251x.c (working copy) @@ -101,8 +101,11 @@ #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 @@ -139,15 +142,59 @@ # define TXBCTRL_MLOA 0x20 # define TXBCTRL_TXERR 0x10 # define TXBCTRL_TXREQ 0x08 +#define TXBSIDH(n) ((n * 0x10) + 0x31) +# define SIDH_SHIFT 3 +#define TXBSIDL(n) ((n * 0x10) + 0x32) +# 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) + 0x33) +#define TXBEID0(n) ((n * 0x10) + 0x34) +#define TXBDLC(n) ((n * 0x10) + 0x35) +# 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) # define RXBCTRL_BUKT 0x04 # define RXBCTRL_RXM0 0x20 # define RXBCTRL_RXM1 0x40 +#define RXBSIDH(n) ((n * 0x10) + 0x61) +# define RXBSIDH_SHIFT 3 +#define RXBSIDL(n) ((n * 0x10) + 0x62) +# define RXBSIDL_IDE 0x08 +# define RXBSIDL_EID 3 +# define RXBSIDL_SHIFT 5 +#define RXBEID8(n) ((n * 0x10) + 0x63) +#define RXBEID0(n) ((n * 0x10) + 0x64) +#define RXBDLC(n) ((n * 0x10) + 0x65) +# 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 -/* Buffer size required for the largest SPI transfer (i.e., reading a - * frame). */ +#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) + */ #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 @@ -159,6 +206,7 @@ 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, @@ -192,11 +240,15 @@ #define AFTER_SUSPEND_UP 1 #define AFTER_SUSPEND_DOWN 2 #define AFTER_SUSPEND_POWER 4 +#define AFTER_SUSPEND_RESTART 8 int restart_tx; }; -static void mcp251x_clean(struct mcp251x_priv *priv) +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) @@ -206,17 +258,17 @@ } /* - 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). + * 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) { @@ -242,7 +294,7 @@ ret = spi_sync(spi, &m); if (ret < 0) - dev_err(&spi->dev, "%s: failed: ret = %d\n", __func__, ret); + dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret); return ret; } @@ -296,12 +348,31 @@ mutex_unlock(&priv->spi_lock); } +static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *data, + int len, int tx_buf_idx) +{ + struct mcp251x_platform_data *pdata = spi->dev.platform_data; + struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + + if (pdata->model == CAN_MCP251X_MCP2510) { + int i; + + for (i = 1; i < TXBDAT_OFF + len; i++) + mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i, + data[i]); + } else { + mutex_lock(&priv->spi_lock); + memcpy(priv->spi_tx_buf, data, TXBDAT_OFF + len); + mcp251x_spi_trans(spi, TXBDAT_OFF + len); + mutex_unlock(&priv->spi_lock); + } +} + 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; + u8 buf[SPI_TRANSFER_BUF_LEN]; exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */ if (exide) @@ -311,150 +382,93 @@ eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */ rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */ + 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); +} + +static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *data, + int buf_idx) +{ + struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_platform_data *pdata = spi->dev.platform_data; + if (pdata->model == CAN_MCP251X_MCP2510) { - int i; + int i, len; - 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]); - } + for (i = 1; i < RXBDAT_OFF; i++) + data[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i); + len = data[RXBDLC_OFF] & RXBDLC_LEN_MASK; + if (len > 8) + len = 8; + for (; i < (RXBDAT_OFF + len); i++) + data[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i); } else { - u8 *tx_buf = priv->spi_tx_buf; - mutex_lock(&priv->spi_lock); - 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; + priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx); + mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN); + memcpy(data, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN); - memcpy(tx_buf + 6, frame->data, frame->can_dlc); - - mcp251x_spi_trans(spi, 6 + CAN_FRAME_MAX_DATA_LEN); - mutex_unlock(&priv->spi_lock); } - mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ); } 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]; skb = alloc_can_skb(priv->net, &frame); if (!skb) { - dev_err(&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; } - 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) { + 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); + if (buf[RXBDLC_OFF] & RXBDLC_RTR) { /* 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); - return; - } - - for (i = 0; i < frame->can_dlc; i++) { - frame->data[i] = mcp251x_read_reg(spi, - RXBCTRL(buf_idx) + - 6 + i); - } - } else { - u8 *tx_buf = priv->spi_tx_buf; - u8 *rx_buf = priv->spi_rx_buf; - int ret; - - mutex_lock(&priv->spi_lock); - - tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx); - - ret = mcp251x_spi_trans(spi, 14); - if (ret < 0) { - 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); + } else + /* Standard ID format */ + frame->can_id = + (buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) | + (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT); + /* Data length */ + frame->can_dlc = buf[RXBDLC_OFF] & RXBDLC_LEN_MASK; + if (frame->can_dlc > 8) { + dev_warn(&spi->dev, "invalid frame recevied\n"); + priv->net->stats.rx_errors++; + dev_kfree_skb(skb); + return; } + memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc); priv->net->stats.rx_packets++; priv->net->stats.rx_bytes += frame->can_dlc; - netif_rx(skb); } @@ -482,7 +496,7 @@ 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) + struct net_device *net) #endif { struct mcp251x_priv *priv = netdev_priv(net); @@ -515,8 +529,11 @@ switch (mode) { case CAN_MODE_START: - /* we have to delay work since SPI I/O may sleep */ + /* 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: @@ -533,19 +550,20 @@ /* 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) { + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) /* Put device into loopback mode */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK); - } else { + else { /* Put device into normal mode */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); /* Wait for the device to enter normal mode */ timeout = jiffies + HZ; - while (mcp251x_read_reg(spi, CANSTAT) & 0xE0) { + while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) { schedule(); if (time_after(jiffies, timeout)) { dev_err(&spi->dev, "MCP251x didn't" @@ -564,24 +582,24 @@ 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)); - + 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)); /* Restore original state */ mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state); @@ -589,12 +607,10 @@ } static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, - struct spi_device *spi) + struct spi_device *spi) { int ret; - /* Set initial baudrate. Make sure that registers are updated - always by explicitly calling mcp251x_do_set_bittiming */ ret = open_candev(net); if (ret) { dev_err(&spi->dev, "unable to set initial baudrate!\n"); @@ -625,8 +641,8 @@ mutex_unlock(&priv->spi_lock); if (ret < 0) - dev_err(&spi->dev, "%s: failed: ret = %d\n", __func__, ret); - /* wait for reset to finish */ + dev_err(&spi->dev, "reset failed: ret = %d\n", ret); + /* Wait for reset to finish */ mdelay(10); } @@ -636,16 +652,33 @@ 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); @@ -659,7 +692,14 @@ priv->force_quit = 0; priv->tx_skb = NULL; priv->tx_len = 0; - enable_irq(spi->irq); + + ret = request_irq(spi->irq, mcp251x_can_isr, + IRQF_TRIGGER_FALLING, DEVICE_NAME, net); + if (ret < 0) { + dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); + return ret; + } + mcp251x_hw_wakeup(spi); mcp251x_hw_reset(spi); ret = mcp251x_setup(net, priv, spi); @@ -688,13 +728,13 @@ flush_workqueue(priv->wq); mcp251x_write_reg(spi, TXBCTRL(0), 0); - if (priv->tx_skb || priv->tx_len) { - net->stats.tx_errors++; - mcp251x_clean(priv); - } + if (priv->tx_skb || priv->tx_len) + mcp251x_clean(net); mcp251x_hw_sleep(spi); + free_irq(spi->irq, net); + if (pdata->transceiver_enable) pdata->transceiver_enable(0); @@ -712,10 +752,14 @@ struct net_device *net = priv->net; struct can_frame *frame; - WARN_ON(!priv->tx_skb); - WARN_ON(priv->tx_len); 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); @@ -731,42 +775,49 @@ irq_work); struct spi_device *spi = priv->spi; struct net_device *net = priv->net; + u8 txbnctrl; u8 intf; - u8 txbnctrl; enum can_state new_state; if (priv->after_suspend) { - /* Wait whilst the device wakes up WARN_ON */ 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 */ + /* Clean since we lost tx buffer */ if (priv->tx_skb || priv->tx_len) { - net->stats.tx_errors++; - mcp251x_clean(priv); + mcp251x_clean(net); netif_wake_queue(net); } mcp251x_set_normal_mode(spi); } else mcp251x_hw_sleep(spi); priv->after_suspend = 0; + } + + if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF) { + while (!priv->force_quit && !freezing(current) && + (intf = mcp251x_read_reg(spi, CANINTF))) + mcp251x_write_bits(spi, CANINTF, intf, 0x00); 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_dbg(&spi->dev, - "timeout in txing a packet, restarting\n"); mcp251x_write_reg(spi, TXBCTRL(0), 0); - if (priv->tx_skb || priv->tx_len) { - net->stats.tx_errors++; - mcp251x_clean(priv); - } - priv->can.can_stats.restarts++; + if (priv->tx_skb || priv->tx_len) + mcp251x_clean(net); netif_wake_queue(net); + can_id |= CAN_ERR_RESTARTED; } if (priv->wake) { @@ -776,122 +827,106 @@ } intf = mcp251x_read_reg(spi, CANINTF); - if (intf == 0x00) - break; mcp251x_write_bits(spi, CANINTF, intf, 0x00); - 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 pending Tx buffers, restart queue */ - txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0)); - if (!(txbnctrl & TXBCTRL_TXREQ)) { - WARN_ON(priv->tx_skb); - WARN_ON(!priv->tx_len); - if (priv->tx_skb || priv->tx_len) { - net->stats.tx_errors++; - mcp251x_clean(priv); - } - 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); + struct can_frame *frame; - /* create error frame */ + /* Create error frame */ skb = alloc_can_err_skb(net, &frame); if (skb) { /* 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_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_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_ERR_CRTL; - frame->data[1] |= - CAN_ERR_CRTL_RX_WARNING; + CAN_ERR_CRTL_RX_OVERFLOW; } - } - /* update net stats */ - 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; - } - } + netif_rx(skb); + } else + dev_info(&spi->dev, + "cannot allocate error skb\n"); + } - /* update can state */ - if (eflag & EFLG_TXBO) { - new_state = CAN_STATE_BUS_OFF; + if (priv->can.state == CAN_STATE_BUS_OFF) { + if (priv->can.restart_ms == 0) { can_bus_off(net); - } else if (eflag & EFLG_TXEP) - new_state = CAN_STATE_ERROR_PASSIVE; - else if (eflag & EFLG_RXEP) - new_state = CAN_STATE_ERROR_PASSIVE; - else if (eflag & EFLG_TXWAR) - new_state = CAN_STATE_ERROR_WARNING; - else if (eflag & EFLG_RXWAR) - new_state = CAN_STATE_ERROR_WARNING; - else - new_state = CAN_STATE_ERROR_ACTIVE; + mcp251x_hw_sleep(spi); + return; + } + } - mcp251x_write_reg(spi, EFLG, 0x00); + if (intf == 0) + break; - if (skb) - netif_rx(skb); - } else - new_state = CAN_STATE_ERROR_ACTIVE; + if (intf & CANINTF_WAKIF) + complete(&priv->awake); - /* 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; - case CAN_STATE_BUS_OFF: - if (new_state <= CAN_STATE_ERROR_PASSIVE) - netif_carrier_on(net); - break; - default: - break; + 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); + } } - priv->can.state = new_state; if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) { net->stats.tx_packets++; net->stats.tx_bytes += priv->tx_len - 1; - WARN_ON(priv->tx_skb); - WARN_ON(!priv->tx_len); if (priv->tx_len) { can_get_echo_skb(net, 0); priv->tx_len = 0; } - mcp251x_clean(priv); netif_wake_queue(net); } @@ -900,24 +935,9 @@ if (intf & CANINTF_RX1IF) mcp251x_hw_rx(spi, 1); - } - - mcp251x_read_reg(spi, CANSTAT); } -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; -} - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) static const struct net_device_ops mcp251x_netdev_ops = { .ndo_open = mcp251x_open, @@ -926,8 +946,9 @@ }; #endif -static struct net_device *alloc_mcp251x_netdev(int sizeof_priv, - struct mcp251x_platform_data *pdata) +static struct net_device +*alloc_mcp251x_netdev(int sizeof_priv, + struct mcp251x_platform_data *pdata) { struct net_device *net; struct mcp251x_priv *priv; @@ -964,10 +985,9 @@ 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), pdata); @@ -984,22 +1004,25 @@ /* 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)); - } else { + (PAGE_SIZE / 2)); + } else /* Fall back to non-DMA */ mcp251x_enable_dma = 0; - } } /* Allocate non-DMA buffers */ @@ -1037,14 +1060,6 @@ 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; @@ -1060,8 +1075,6 @@ return ret; } error_probe: - free_irq(spi->irq, net); -error_irq: if (!mcp251x_enable_dma) kfree(priv->spi_rx_buf); error_rx_buf: @@ -1069,10 +1082,9 @@ 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: dev_err(&spi->dev, "probe failed\n"); error_out: @@ -1088,15 +1100,14 @@ 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) { + if (mcp251x_enable_dma) dma_free_coherent(&spi->dev, PAGE_SIZE, - priv->spi_tx_buf, priv->spi_tx_dma); - } else { + priv->spi_tx_buf, priv->spi_tx_dma); + else { kfree(priv->spi_tx_buf); kfree(priv->spi_rx_buf); } _______________________________________________ Socketcan-core mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-core
