Several bugs are fixed: utilization of just half of the RX buffers, useless wait for interrupt on open, more reliable reset sequence. The MERR interrupt is not used anymore: it overloads the CPU in bus-off state without any additional information. One shot mode for the MCP2515 is added.
Signed-off-by: Christian Pellegrin <[email protected]> --- Index: kernel/2.6/include/socketcan/can/platform/mcp251x.h =================================================================== --- kernel/2.6/include/socketcan/can/platform/mcp251x.h (revision 1120) +++ kernel/2.6/include/socketcan/can/platform/mcp251x.h (working copy) @@ -7,6 +7,8 @@ * */ +#include <linux/spi/spi.h> + /** * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data * @oscillator_frequency: - oscillator frequency in Hz Index: kernel/2.6/drivers/net/can/mcp251x.c =================================================================== --- kernel/2.6/drivers/net/can/mcp251x.c (revision 1120) +++ kernel/2.6/drivers/net/can/mcp251x.c (working copy) @@ -234,8 +234,7 @@ struct workqueue_struct *wq; struct work_struct tx_work; struct work_struct irq_work; - struct completion awake; - int wake; + int force_quit; int after_suspend; #define AFTER_SUSPEND_UP 1 @@ -363,8 +362,10 @@ 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); } } @@ -471,21 +472,6 @@ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); } -static void mcp251x_hw_wakeup(struct spi_device *spi) -{ - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - - priv->wake = 1; - - /* Can only wake up by generating a wake-up interrupt. */ - mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE); - mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF); - - /* Wait until the device is awake */ - if (!wait_for_completion_timeout(&priv->awake, HZ)) - 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 @@ -535,21 +521,24 @@ static void mcp251x_set_normal_mode(struct spi_device *spi) { + struct mcp251x_platform_data *pdata = spi->dev.platform_data; struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); unsigned long timeout; /* Enable interrupts */ mcp251x_write_reg(spi, CANINTE, CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE | - CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE | - CANINTF_MERRF); + CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE); if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { /* Put device into loopback mode */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK); } else { /* Put device into normal mode */ - mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); + mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL | + ((pdata->model == CAN_MCP251X_MCP2515 && + priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) ? + CANCTRL_OSM : 0)); /* Wait for the device to enter normal mode */ timeout = jiffies + HZ; @@ -594,12 +583,10 @@ mcp251x_do_set_bittiming(net); /* Enable RX0->RX1 buffer roll over and disable filters */ - mcp251x_write_bits(spi, RXBCTRL(0), - RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1, - RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1); - mcp251x_write_bits(spi, RXBCTRL(1), - RXBCTRL_RXM0 | RXBCTRL_RXM1, - RXBCTRL_RXM0 | RXBCTRL_RXM1); + mcp251x_write_reg(spi, RXBCTRL(0), + RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1); + mcp251x_write_reg(spi, RXBCTRL(1), + RXBCTRL_RXM0 | RXBCTRL_RXM1); return 0; } @@ -607,19 +594,30 @@ { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); int ret; + unsigned long timeout; mutex_lock(&priv->spi_lock); priv->spi_tx_buf[0] = INSTRUCTION_RESET; ret = spi_write(spi, priv->spi_tx_buf, 1); + if (ret) + dev_err(&spi->dev, "reset failed: ret = %d\n", ret); mutex_unlock(&priv->spi_lock); - if (ret) - dev_err(&spi->dev, "reset failed: ret = %d\n", ret); /* Wait for reset to finish */ + timeout = jiffies + HZ; mdelay(10); + while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) + != CANCTRL_REQOP_CONF) { + schedule(); + if (time_after(jiffies, timeout)) { + dev_err(&spi->dev, "MCP251x didn't" + " enter in conf mode after reset\n"); + break; + } + } } static int mcp251x_hw_probe(struct spi_device *spi) @@ -685,7 +683,6 @@ return ret; } - mcp251x_hw_wakeup(spi); mcp251x_hw_reset(spi); ret = mcp251x_setup(net, priv, spi); if (ret) { @@ -763,7 +760,6 @@ irq_work); struct spi_device *spi = priv->spi; struct net_device *net = priv->net; - u8 txbnctrl; u8 intf; enum can_state new_state; @@ -791,11 +787,9 @@ return; while (!priv->force_quit && !freezing(current)) { - u8 eflag = mcp251x_read_reg(spi, EFLG); + u8 eflag; int can_id = 0, data1 = 0; - mcp251x_write_reg(spi, EFLG, 0x00); - if (priv->restart_tx) { priv->restart_tx = 0; mcp251x_write_reg(spi, TXBCTRL(0), 0); @@ -805,15 +799,22 @@ can_id |= CAN_ERR_RESTARTED; } - if (priv->wake) { - /* Wait whilst the device wakes up */ - mdelay(10); - priv->wake = 0; - } - intf = mcp251x_read_reg(spi, CANINTF); + + if (intf & CANINTF_RX0IF) { + mcp251x_hw_rx(spi, 0); + /* Free one buffer ASAP */ + mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF, 0x00); + } + + if (intf & CANINTF_RX1IF) + mcp251x_hw_rx(spi, 1); + mcp251x_write_bits(spi, CANINTF, intf, 0x00); + eflag = mcp251x_read_reg(spi, EFLG); + mcp251x_write_reg(spi, EFLG, 0x00); + /* Update can state */ if (eflag & EFLG_TXBO) { new_state = CAN_STATE_BUS_OFF; @@ -894,19 +895,6 @@ 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)) { net->stats.tx_packets++; net->stats.tx_bytes += priv->tx_len - 1; @@ -916,12 +904,6 @@ } netif_wake_queue(net); } - - if (intf & CANINTF_RX0IF) - mcp251x_hw_rx(spi, 0); - - if (intf & CANINTF_RX1IF) - mcp251x_hw_rx(spi, 1); } } @@ -1022,8 +1004,6 @@ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler); - init_completion(&priv->awake); - /* Configure the SPI bus */ spi->mode = SPI_MODE_0; spi->bits_per_word = 8; _______________________________________________ Socketcan-core mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-core
