aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2010-05-18 17:03:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-18 17:03:10 -0400
commit57c8a456640fa3ca777652f11f2db4179a3e66b6 (patch)
treea290a904176384e1a9c80edc291f08286e23f3f3
parentb3bcb72edb29c52fb0a065d5b1c7cf40ed9287f4 (diff)
can: Fix SJA1000 command register writes on SMP systems
The SJA1000 command register is concurrently written in the rx-path to free the receive buffer _and_ in the tx-path to start the transmission. The SJA1000 data sheet, 6.4.4 COMMAND REGISTER (CMR) states: "Between two commands at least one internal clock cycle is needed in order to proceed. The internal clock is half of the external oscillator frequency." On SMP systems the current implementation leads to a write stall in the tx-path, which can be solved by adding some general locking and some time to settle the write_reg() operation for the command register. Thanks to Klaus Hitschler for the original fix and detailed problem description. This patch applies on net-2.6 and (with some offsets) on net-next-2.6 . Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Acked-by: Wolfgang Grandegger <wg@grandegger.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/can/sja1000/sja1000.c20
-rw-r--r--drivers/net/can/sja1000/sja1000.h1
2 files changed, 18 insertions, 3 deletions
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 24b58619f7c1..85f7cbfe8e5f 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -83,6 +83,20 @@ static struct can_bittiming_const sja1000_bittiming_const = {
83 .brp_inc = 1, 83 .brp_inc = 1,
84}; 84};
85 85
86static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
87{
88 unsigned long flags;
89
90 /*
91 * The command register needs some locking and time to settle
92 * the write_reg() operation - especially on SMP systems.
93 */
94 spin_lock_irqsave(&priv->cmdreg_lock, flags);
95 priv->write_reg(priv, REG_CMR, val);
96 priv->read_reg(priv, REG_SR);
97 spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
98}
99
86static int sja1000_probe_chip(struct net_device *dev) 100static int sja1000_probe_chip(struct net_device *dev)
87{ 101{
88 struct sja1000_priv *priv = netdev_priv(dev); 102 struct sja1000_priv *priv = netdev_priv(dev);
@@ -294,7 +308,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
294 308
295 can_put_echo_skb(skb, dev, 0); 309 can_put_echo_skb(skb, dev, 0);
296 310
297 priv->write_reg(priv, REG_CMR, CMD_TR); 311 sja1000_write_cmdreg(priv, CMD_TR);
298 312
299 return NETDEV_TX_OK; 313 return NETDEV_TX_OK;
300} 314}
@@ -343,7 +357,7 @@ static void sja1000_rx(struct net_device *dev)
343 cf->can_id = id; 357 cf->can_id = id;
344 358
345 /* release receive buffer */ 359 /* release receive buffer */
346 priv->write_reg(priv, REG_CMR, CMD_RRB); 360 sja1000_write_cmdreg(priv, CMD_RRB);
347 361
348 netif_rx(skb); 362 netif_rx(skb);
349 363
@@ -371,7 +385,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
371 cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 385 cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
372 stats->rx_over_errors++; 386 stats->rx_over_errors++;
373 stats->rx_errors++; 387 stats->rx_errors++;
374 priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ 388 sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */
375 } 389 }
376 390
377 if (isrc & IRQ_EI) { 391 if (isrc & IRQ_EI) {
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index 97a622b9302f..de8e778f6832 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -167,6 +167,7 @@ struct sja1000_priv {
167 167
168 void __iomem *reg_base; /* ioremap'ed address to registers */ 168 void __iomem *reg_base; /* ioremap'ed address to registers */
169 unsigned long irq_flags; /* for request_irq() */ 169 unsigned long irq_flags; /* for request_irq() */
170 spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
170 171
171 u16 flags; /* custom mode flags */ 172 u16 flags; /* custom mode flags */
172 u8 ocr; /* output control register */ 173 u8 ocr; /* output control register */