From 0c427ca3c10ee393978e87fb191bab55512480c4 Mon Sep 17 00:00:00 2001 From: hartkopp Date: Mon, 17 May 2010 10:22:59 +0000 Subject: [PATCH] Fix writes to the SJA1000 command register on SMP systems. git-svn-id: svn://svn.berlios.de//socketcan/trunk@1180 030b6a49-0b11-0410-94ab-b0dab22257f2 --- kernel/2.6/drivers/net/can/sja1000/sja1000.c | 27 +++++++++++++++++--- kernel/2.6/drivers/net/can/sja1000/sja1000.h | 4 +++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/kernel/2.6/drivers/net/can/sja1000/sja1000.c b/kernel/2.6/drivers/net/can/sja1000/sja1000.c index c868829..5ba308d 100644 --- a/kernel/2.6/drivers/net/can/sja1000/sja1000.c +++ b/kernel/2.6/drivers/net/can/sja1000/sja1000.c @@ -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) { diff --git a/kernel/2.6/drivers/net/can/sja1000/sja1000.h b/kernel/2.6/drivers/net/can/sja1000/sja1000.h index 02aeb18..6720b37 100644 --- a/kernel/2.6/drivers/net/can/sja1000/sja1000.h +++ b/kernel/2.6/drivers/net/can/sja1000/sja1000.h @@ -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 */ -- 2.39.2