diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2014-04-15 13:30:00 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-04-24 16:22:53 -0400 |
commit | a9edcdedbd3d8f3ffcd7bdcab5812707a25e554e (patch) | |
tree | 5eff58f9133f3e21f8b2134867cefc1c2ec4b817 | |
parent | 78c181bc8a75d3f0624eaf24aa8265d441990c8c (diff) |
can: sja1000_isa: add locking for indirect register access mode
When accessing the SJA1000 controller registers in the indirect access mode,
writing the register number and reading/writing the data has to be an atomic
attempt.
As the sja1000_isa driver is an old style driver with a fixed number of
instances the locking variable depends on the same index like all the other
configuration elements given on the module command line.
As a positive side effect dev->dev_id is populated by the instance index,
which was missing in 3e66d0138c05d9 ("can: populate netdev::dev_id for udev
discrimination").
Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r-- | drivers/net/can/sja1000/sja1000_isa.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c index df136a2516c4..014695d7e6a3 100644 --- a/drivers/net/can/sja1000/sja1000_isa.c +++ b/drivers/net/can/sja1000/sja1000_isa.c | |||
@@ -46,6 +46,7 @@ static int clk[MAXDEV]; | |||
46 | static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; | 46 | static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; |
47 | static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; | 47 | static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; |
48 | static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; | 48 | static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; |
49 | static spinlock_t indirect_lock[MAXDEV]; /* lock for indirect access mode */ | ||
49 | 50 | ||
50 | module_param_array(port, ulong, NULL, S_IRUGO); | 51 | module_param_array(port, ulong, NULL, S_IRUGO); |
51 | MODULE_PARM_DESC(port, "I/O port number"); | 52 | MODULE_PARM_DESC(port, "I/O port number"); |
@@ -101,19 +102,26 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv, | |||
101 | static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv, | 102 | static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv, |
102 | int reg) | 103 | int reg) |
103 | { | 104 | { |
104 | unsigned long base = (unsigned long)priv->reg_base; | 105 | unsigned long flags, base = (unsigned long)priv->reg_base; |
106 | u8 readval; | ||
105 | 107 | ||
108 | spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags); | ||
106 | outb(reg, base); | 109 | outb(reg, base); |
107 | return inb(base + 1); | 110 | readval = inb(base + 1); |
111 | spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags); | ||
112 | |||
113 | return readval; | ||
108 | } | 114 | } |
109 | 115 | ||
110 | static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv, | 116 | static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv, |
111 | int reg, u8 val) | 117 | int reg, u8 val) |
112 | { | 118 | { |
113 | unsigned long base = (unsigned long)priv->reg_base; | 119 | unsigned long flags, base = (unsigned long)priv->reg_base; |
114 | 120 | ||
121 | spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags); | ||
115 | outb(reg, base); | 122 | outb(reg, base); |
116 | outb(val, base + 1); | 123 | outb(val, base + 1); |
124 | spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags); | ||
117 | } | 125 | } |
118 | 126 | ||
119 | static int sja1000_isa_probe(struct platform_device *pdev) | 127 | static int sja1000_isa_probe(struct platform_device *pdev) |
@@ -169,6 +177,7 @@ static int sja1000_isa_probe(struct platform_device *pdev) | |||
169 | if (iosize == SJA1000_IOSIZE_INDIRECT) { | 177 | if (iosize == SJA1000_IOSIZE_INDIRECT) { |
170 | priv->read_reg = sja1000_isa_port_read_reg_indirect; | 178 | priv->read_reg = sja1000_isa_port_read_reg_indirect; |
171 | priv->write_reg = sja1000_isa_port_write_reg_indirect; | 179 | priv->write_reg = sja1000_isa_port_write_reg_indirect; |
180 | spin_lock_init(&indirect_lock[idx]); | ||
172 | } else { | 181 | } else { |
173 | priv->read_reg = sja1000_isa_port_read_reg; | 182 | priv->read_reg = sja1000_isa_port_read_reg; |
174 | priv->write_reg = sja1000_isa_port_write_reg; | 183 | priv->write_reg = sja1000_isa_port_write_reg; |
@@ -198,6 +207,7 @@ static int sja1000_isa_probe(struct platform_device *pdev) | |||
198 | 207 | ||
199 | platform_set_drvdata(pdev, dev); | 208 | platform_set_drvdata(pdev, dev); |
200 | SET_NETDEV_DEV(dev, &pdev->dev); | 209 | SET_NETDEV_DEV(dev, &pdev->dev); |
210 | dev->dev_id = idx; | ||
201 | 211 | ||
202 | err = register_sja1000dev(dev); | 212 | err = register_sja1000dev(dev); |
203 | if (err) { | 213 | if (err) { |