提交 57c8a456 编写于 作者: O Oliver Hartkopp 提交者: David S. Miller

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: NOliver Hartkopp <socketcan@hartkopp.net>
Acked-by: NWolfgang Grandegger <wg@grandegger.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 b3bcb72e
...@@ -83,6 +83,20 @@ static struct can_bittiming_const sja1000_bittiming_const = { ...@@ -83,6 +83,20 @@ static struct can_bittiming_const sja1000_bittiming_const = {
.brp_inc = 1, .brp_inc = 1,
}; };
static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
{
unsigned long flags;
/*
* The command register needs some locking and time to settle
* the write_reg() operation - especially on SMP systems.
*/
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);
}
static int sja1000_probe_chip(struct net_device *dev) static int sja1000_probe_chip(struct net_device *dev)
{ {
struct sja1000_priv *priv = netdev_priv(dev); struct sja1000_priv *priv = netdev_priv(dev);
...@@ -294,7 +308,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, ...@@ -294,7 +308,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
can_put_echo_skb(skb, dev, 0); 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; return NETDEV_TX_OK;
} }
...@@ -343,7 +357,7 @@ static void sja1000_rx(struct net_device *dev) ...@@ -343,7 +357,7 @@ static void sja1000_rx(struct net_device *dev)
cf->can_id = id; cf->can_id = id;
/* release receive buffer */ /* release receive buffer */
priv->write_reg(priv, REG_CMR, CMD_RRB); sja1000_write_cmdreg(priv, CMD_RRB);
netif_rx(skb); netif_rx(skb);
...@@ -371,7 +385,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) ...@@ -371,7 +385,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++; stats->rx_over_errors++;
stats->rx_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) { if (isrc & IRQ_EI) {
......
...@@ -167,6 +167,7 @@ struct sja1000_priv { ...@@ -167,6 +167,7 @@ struct sja1000_priv {
void __iomem *reg_base; /* ioremap'ed address to registers */ void __iomem *reg_base; /* ioremap'ed address to registers */
unsigned long irq_flags; /* for request_irq() */ unsigned long irq_flags; /* for request_irq() */
spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
u16 flags; /* custom mode flags */ u16 flags; /* custom mode flags */
u8 ocr; /* output control register */ u8 ocr; /* output control register */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册