Skip to content

Commit a9edcde

Browse files
hartkoppmarckleinebudde
authored andcommitted
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 3e66d01 ("can: populate netdev::dev_id for udev discrimination"). Reported-by: Marc Kleine-Budde <[email protected]> Signed-off-by: Oliver Hartkopp <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 78c181b commit a9edcde

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

drivers/net/can/sja1000/sja1000_isa.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ static int clk[MAXDEV];
4646
static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
4747
static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
4848
static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
49+
static spinlock_t indirect_lock[MAXDEV]; /* lock for indirect access mode */
4950

5051
module_param_array(port, ulong, NULL, S_IRUGO);
5152
MODULE_PARM_DESC(port, "I/O port number");
@@ -101,19 +102,26 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
101102
static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
102103
int reg)
103104
{
104-
unsigned long base = (unsigned long)priv->reg_base;
105+
unsigned long flags, base = (unsigned long)priv->reg_base;
106+
u8 readval;
105107

108+
spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
106109
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;
108114
}
109115

110116
static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
111117
int reg, u8 val)
112118
{
113-
unsigned long base = (unsigned long)priv->reg_base;
119+
unsigned long flags, base = (unsigned long)priv->reg_base;
114120

121+
spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
115122
outb(reg, base);
116123
outb(val, base + 1);
124+
spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
117125
}
118126

119127
static int sja1000_isa_probe(struct platform_device *pdev)
@@ -169,6 +177,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
169177
if (iosize == SJA1000_IOSIZE_INDIRECT) {
170178
priv->read_reg = sja1000_isa_port_read_reg_indirect;
171179
priv->write_reg = sja1000_isa_port_write_reg_indirect;
180+
spin_lock_init(&indirect_lock[idx]);
172181
} else {
173182
priv->read_reg = sja1000_isa_port_read_reg;
174183
priv->write_reg = sja1000_isa_port_write_reg;
@@ -198,6 +207,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
198207

199208
platform_set_drvdata(pdev, dev);
200209
SET_NETDEV_DEV(dev, &pdev->dev);
210+
dev->dev_id = idx;
201211

202212
err = register_sja1000dev(dev);
203213
if (err) {

0 commit comments

Comments
 (0)