From 57d3c7b09bd797b8db974557a71df8675a22601b Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 4 Oct 2010 10:50:51 +0200 Subject: can: mcp251x: fix NOHZ local_softirq_pending 08 warning This patch replaces netif_rx() with netif_rx_ni() which has to be used from the threaded interrupt i.e. process context context. Thanks to Christian Pellegrin for pointing at the right fix: 481a8199142c050b72bff8a1956a49fd0a75bbe0 by Oliver Hartkopp. Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index b11a0cb5ed81..c06e02382eca 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -451,7 +451,7 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) priv->net->stats.rx_packets++; priv->net->stats.rx_bytes += frame->can_dlc; - netif_rx(skb); + netif_rx_ni(skb); } static void mcp251x_hw_sleep(struct spi_device *spi) @@ -676,7 +676,7 @@ static void mcp251x_error_skb(struct net_device *net, int can_id, int data1) if (skb) { frame->can_id = can_id; frame->data[1] = data1; - netif_rx(skb); + netif_rx_ni(skb); } else { dev_err(&net->dev, "cannot allocate error skb\n"); -- cgit v1.2.3 From 711e4d6eccd72c57938228b8e0c29cb205527032 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 30 Sep 2010 09:46:00 +0200 Subject: can: mcp251x: increase rx_errors on overflow, not only rx_over_errors Signed-off-by: Sascha Hauer Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index c06e02382eca..fdea752f398f 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -816,10 +816,14 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) if (intf & CANINTF_ERRIF) { /* Handle overflow counters */ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) { - if (eflag & EFLG_RX0OVR) + if (eflag & EFLG_RX0OVR) { net->stats.rx_over_errors++; - if (eflag & EFLG_RX1OVR) + net->stats.rx_errors++; + } + if (eflag & EFLG_RX1OVR) { net->stats.rx_over_errors++; + net->stats.rx_errors++; + } can_id |= CAN_ERR_CRTL; data1 |= CAN_ERR_CRTL_RX_OVERFLOW; } -- cgit v1.2.3 From f3a3ed3115d39463dc6672454bfbeaff46811a37 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Sep 2010 09:53:35 +0200 Subject: can: mcp251x: allow to read two registers in one spi transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch bases on work done earlier by David Jander. Signed-off-by: Sascha Hauer Acked-by: David Jander Signed-off-by: Uwe Kleine-König Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index fdea752f398f..9b3466aed06d 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -319,6 +319,20 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg) return val; } +static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg, + uint8_t *v1, uint8_t *v2) +{ + struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + + priv->spi_tx_buf[0] = INSTRUCTION_READ; + priv->spi_tx_buf[1] = reg; + + mcp251x_spi_trans(spi, 4); + + *v1 = priv->spi_rx_buf[2]; + *v2 = priv->spi_rx_buf[3]; +} + static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val) { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); @@ -754,10 +768,11 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) mutex_lock(&priv->mcp_lock); while (!priv->force_quit) { enum can_state new_state; - u8 intf = mcp251x_read_reg(spi, CANINTF); - u8 eflag; + u8 intf, eflag; int can_id = 0, data1 = 0; + mcp251x_read_2regs(spi, CANINTF, &intf, &eflag); + if (intf & CANINTF_RX0IF) { mcp251x_hw_rx(spi, 0); /* Free one buffer ASAP */ @@ -770,7 +785,6 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) mcp251x_write_bits(spi, CANINTF, intf, 0x00); - eflag = mcp251x_read_reg(spi, EFLG); mcp251x_write_reg(spi, EFLG, 0x00); /* Update can state */ -- cgit v1.2.3 From 7e15de3a73899903f33975b1ce57cf59c616d1d9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Sep 2010 10:00:47 +0200 Subject: can: mcp251x: read-modify-write eflag only when needed Use read-modify-write instead of a simple write to change the register contents, to close existing the race window between the original manual read and write. Signed-off-by: Sascha Hauer Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 9b3466aed06d..7e2f951002a5 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -785,7 +785,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) mcp251x_write_bits(spi, CANINTF, intf, 0x00); - mcp251x_write_reg(spi, EFLG, 0x00); + if (eflag) + mcp251x_write_bits(spi, EFLG, eflag, 0x00); /* Update can state */ if (eflag & EFLG_TXBO) { -- cgit v1.2.3 From d3cd15657516141adce387810be8cb377baf020e Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 28 Sep 2010 10:18:34 +0200 Subject: can: mcp251x: write intf only when needed This patch introduces a variable "clear_intf" that hold the bits that should be cleared. Only read-modify-write register if "clear_intf" is set. Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7e2f951002a5..f5e2edd09ce4 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -125,6 +125,8 @@ # define CANINTF_TX0IF 0x04 # define CANINTF_RX1IF 0x02 # define CANINTF_RX0IF 0x01 +# define CANINTF_ERR_TX \ + (CANINTF_ERRIF | CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF) #define EFLG 0x2d # define EFLG_EWARN 0x01 # define EFLG_RXWAR 0x02 @@ -769,10 +771,12 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) while (!priv->force_quit) { enum can_state new_state; u8 intf, eflag; + u8 clear_intf = 0; int can_id = 0, data1 = 0; mcp251x_read_2regs(spi, CANINTF, &intf, &eflag); + /* receive buffer 0 */ if (intf & CANINTF_RX0IF) { mcp251x_hw_rx(spi, 0); /* Free one buffer ASAP */ @@ -780,10 +784,17 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) 0x00); } - if (intf & CANINTF_RX1IF) + /* receive buffer 1 */ + if (intf & CANINTF_RX1IF) { mcp251x_hw_rx(spi, 1); + clear_intf |= CANINTF_RX1IF; + } - mcp251x_write_bits(spi, CANINTF, intf, 0x00); + /* any error or tx interrupt we need to clear? */ + if (intf & CANINTF_ERR_TX) + clear_intf |= intf & CANINTF_ERR_TX; + if (clear_intf) + mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00); if (eflag) mcp251x_write_bits(spi, EFLG, eflag, 0x00); -- cgit v1.2.3 From f1f8c6cbe6f08f93ac2a4ca19625891d8a82b7f8 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 18 Oct 2010 15:00:18 +0200 Subject: can: mcp251x: Don't use pdata->model for chip selection anymore Since commit e446630c960946b5c1762e4eadb618becef599e7, i.e. v2.6.35-rc1, the mcp251x chip model can be selected via the modalias member in the struct spi_board_info. The driver stores the actual model in the struct mcp251x_platform_data. From the driver point of view the platform_data should be read only. Since all in-tree users of the mcp251x have already been converted to the modalias method, this patch moves the "model" member from the struct mcp251x_platform_data to the driver's private data structure. Signed-off-by: Marc Kleine-Budde Cc: Christian Pellegrin Cc: Marc Zyngier --- drivers/net/can/mcp251x.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index f5e2edd09ce4..0386bed43551 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -38,14 +38,14 @@ * static struct mcp251x_platform_data mcp251x_info = { * .oscillator_frequency = 8000000, * .board_specific_setup = &mcp251x_setup, - * .model = CAN_MCP251X_MCP2510, * .power_enable = mcp251x_power_enable, * .transceiver_enable = NULL, * }; * * static struct spi_board_info spi_board_info[] = { * { - * .modalias = "mcp251x", + * .modalias = "mcp2510", + * // or "mcp2515" depending on your controller * .platform_data = &mcp251x_info, * .irq = IRQ_EINT13, * .max_speed_hz = 2*1000*1000, @@ -224,10 +224,16 @@ static struct can_bittiming_const mcp251x_bittiming_const = { .brp_inc = 1, }; +enum mcp251x_model { + CAN_MCP251X_MCP2510 = 0x2510, + CAN_MCP251X_MCP2515 = 0x2515, +}; + struct mcp251x_priv { struct can_priv can; struct net_device *net; struct spi_device *spi; + enum mcp251x_model model; struct mutex mcp_lock; /* SPI device lock */ @@ -362,10 +368,9 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg, 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); - if (pdata->model == CAN_MCP251X_MCP2510) { + if (priv->model == CAN_MCP251X_MCP2510) { int i; for (i = 1; i < TXBDAT_OFF + len; i++) @@ -408,9 +413,8 @@ 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; - if (pdata->model == CAN_MCP251X_MCP2510) { + if (priv->model == CAN_MCP251X_MCP2510) { int i, len; for (i = 1; i < RXBDAT_OFF; i++) @@ -951,16 +955,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) struct net_device *net; struct mcp251x_priv *priv; struct mcp251x_platform_data *pdata = spi->dev.platform_data; - int model = spi_get_device_id(spi)->driver_data; int ret = -ENODEV; if (!pdata) /* Platform data is required for osc freq */ goto error_out; - if (model) - pdata->model = model; - /* Allocate can/net device */ net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX); if (!net) { @@ -977,6 +977,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) priv->can.clock.freq = pdata->oscillator_frequency / 2; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; + priv->model = spi_get_device_id(spi)->driver_data; priv->net = net; dev_set_drvdata(&spi->dev, priv); @@ -1150,8 +1151,7 @@ static int mcp251x_can_resume(struct spi_device *spi) #define mcp251x_can_resume NULL #endif -static struct spi_device_id mcp251x_id_table[] = { - { "mcp251x", 0 /* Use pdata.model */ }, +static const struct spi_device_id mcp251x_id_table[] = { { "mcp2510", CAN_MCP251X_MCP2510 }, { "mcp2515", CAN_MCP251X_MCP2515 }, { }, -- cgit v1.2.3 From beab675cb45f28a4a76780e43fd03e33bc773555 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 23 Sep 2010 21:34:28 +0200 Subject: can: mcp251x: define helper functions mcp251x_is_2510, mcp251x_is_2515 Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 0386bed43551..7f8aa4ce02c5 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -258,6 +258,16 @@ struct mcp251x_priv { int restart_tx; }; +#define MCP251X_IS(_model) \ +static inline int mcp251x_is_##_model(struct spi_device *spi) \ +{ \ + struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \ + return priv->model == CAN_MCP251X_MCP##_model; \ +} + +MCP251X_IS(2510); +MCP251X_IS(2515); + static void mcp251x_clean(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); @@ -370,7 +380,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - if (priv->model == CAN_MCP251X_MCP2510) { + if (mcp251x_is_2510(spi)) { int i; for (i = 1; i < TXBDAT_OFF + len; i++) @@ -414,7 +424,7 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - if (priv->model == CAN_MCP251X_MCP2510) { + if (mcp251x_is_2510(spi)) { int i, len; for (i = 1; i < RXBDAT_OFF; i++) -- cgit v1.2.3 From 9c473fc33915ddb14b71a4929c838c22b20a24ce Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 4 Oct 2010 12:09:31 +0200 Subject: can: mcp251x: optimize 2515, rx int gets cleared automatically Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger --- drivers/net/can/mcp251x.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7f8aa4ce02c5..c664be261e98 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -793,15 +793,20 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) /* receive buffer 0 */ if (intf & CANINTF_RX0IF) { mcp251x_hw_rx(spi, 0); - /* Free one buffer ASAP */ - mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF, - 0x00); + /* + * Free one buffer ASAP + * (The MCP2515 does this automatically.) + */ + if (mcp251x_is_2510(spi)) + mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00); } /* receive buffer 1 */ if (intf & CANINTF_RX1IF) { mcp251x_hw_rx(spi, 1); - clear_intf |= CANINTF_RX1IF; + /* the MCP2515 does this automatically */ + if (mcp251x_is_2510(spi)) + clear_intf |= CANINTF_RX1IF; } /* any error or tx interrupt we need to clear? */ -- cgit v1.2.3