]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
Fix writes to the SJA1000 command register on SMP systems.
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 17 May 2010 10:22:59 +0000 (10:22 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 17 May 2010 10:22:59 +0000 (10:22 +0000)
git-svn-id: svn://svn.berlios.de//socketcan/trunk@1180 030b6a49-0b11-0410-94ab-b0dab22257f2

kernel/2.6/drivers/net/can/sja1000/sja1000.c
kernel/2.6/drivers/net/can/sja1000/sja1000.h

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) {
index 02aeb1811c6dd26b2fe7e800ebd61c0cdebfa807..6720b371d83a2b3704bc7ae4bc5196a4f51faeba 100644 (file)
@@ -168,6 +168,10 @@ struct sja1000_priv {
        void __iomem *reg_base;  /* ioremap'ed address to registers */
        unsigned long irq_flags; /* for request_irq() */
 
+#ifdef CONFIG_SMP
+       spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
+#endif
+
        u16 flags;              /* custom mode flags */
        u8 ocr;                 /* output control register */
        u8 cdr;                 /* clock divider register */