]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/drivers/net/can/sja1000/sja1000.c
Fix writes to the SJA1000 command register on SMP systems.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / sja1000 / sja1000.c
index c868829e47f1becf0fa7bbbd1ed360c29c6ea5b5..5ba308d18f0a07c00f3ee4f9d1297311447d9870 100644 (file)
@@ -88,6 +88,27 @@ static struct can_bittiming_const sja1000_bittiming_const = {
        .brp_inc = 1,
 };
 
+static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
+{
+       /* the command register needs some locking on SMP systems */
+
+#ifdef CONFIG_SMP
+
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->cmdreg_lock, flags);
+       priv->write_reg(priv, REG_CMR, val);
+       priv->read_reg(priv, REG_SR);
+       spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
+
+#else
+
+       /* write to the command register without locking */
+       priv->write_reg(priv, REG_CMR, val);
+
+#endif
+}
+
 static int sja1000_probe_chip(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
@@ -305,7 +326,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
 
        can_put_echo_skb(skb, dev, 0);
 
-       priv->write_reg(priv, REG_CMR, CMD_TR);
+       sja1000_write_cmdreg(priv, CMD_TR);
 
        return NETDEV_TX_OK;
 }
@@ -358,7 +379,7 @@ static void sja1000_rx(struct net_device *dev)
        cf->can_id = id;
 
        /* release receive buffer */
-       priv->write_reg(priv, REG_CMR, CMD_RRB);
+       sja1000_write_cmdreg(priv, CMD_RRB);
 
        netif_rx(skb);
 
@@ -393,7 +414,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                stats->rx_over_errors++;
                stats->rx_errors++;
-               priv->write_reg(priv, REG_CMR, CMD_CDO);        /* clear bit */
+               sja1000_write_cmdreg(priv, CMD_CDO);    /* clear bit */
        }
 
        if (isrc & IRQ_EI) {