summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2014-04-22 13:31:51 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2014-04-22 13:31:51 +0200
commit0ee9e84781aa368c96544e6e96a4696a5a7ba00a (patch)
tree6c02e2123d8a9b0ffdcb9c6bf6792d6737a95885
parent98eb9572b7dc548d0013baac9240f25a644ab277 (diff)
can: mcp251x: fix locking in BERR counter functionality
Symptoms: The interface stops receiving CAN frames when reception of CAN frame and call to the introduced get_berr_counter function coincide. Reproduction: Ip requests, among others, the berr field for the can interfaces. NOTE that it does so even if called as 'ip link show lo', as interface-based filtering is only done after the system calls to receive interface information. Run candump on a MCP-based can interface that has a lot of traffic (via 'cangen -g1' on another can node). On the system with the MCP chip, run while /bin/true; do ip link > /dev/null ; done; Reception of CAN-frames (as shown by candump) will cease within seconds. This issue got introduced by commit 1b59090a47101b4bf379d2c35986ad3f0bcb2aa1 as access to the SPI registers of the MCP251x were not locked. Issue report and patch courtesy David R. Piegdon of Indurad GmbH.
-rw-r--r--drivers/net/can/mcp251x.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 535e4032da2b..899b152ee8ae 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -593,15 +593,22 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
return 0;
}
-static int mcp251x_get_berr_counter(const struct net_device *dev, struct can_berr_counter *bec)
+static int mcp251x_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
{
struct mcp251x_priv *priv = netdev_priv(dev);
struct spi_device *spi = priv->spi;
uint8_t tec,rec;
+ mutex_lock(&priv->mcp_lock);
+
mcp251x_read_2regs(spi, TEC, &tec, &rec);
+
+ mutex_unlock(&priv->mcp_lock);
+
bec->txerr = tec;
bec->rxerr = rec;
+
return 0;
}