Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: microchip: Add shared regmap mutex

The KSZ driver uses one regmap per register width (8/16/32), each with
it's own lock, but accessing the same set of registers. In theory, it
is possible to create a race condition between these regmaps, although
the underlying bus (SPI or I2C) locking should assure nothing bad will
really happen and the accesses would be correct.

To make the driver do the right thing, add one single shared mutex for
all the regmaps used by the driver instead. This assures that even if
some future hardware is on a bus which does not serialize the accesses
the same way SPI or I2C does, nothing bad will happen.

Note that the status_mutex was unused and only initied, hence it was
renamed and repurposed as the regmap mutex.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: David S. Miller <davem@davemloft.net>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: George McCollister <george.mccollister@gmail.com>
Cc: Tristram Ha <Tristram.Ha@microchip.com>
Cc: Woojung Huh <woojung.huh@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Marek Vasut and committed by
David S. Miller
013572a2 7f238ca9

+28 -9
+4 -3
drivers/net/dsa/microchip/ksz8795_spi.c
··· 25 25 26 26 static int ksz8795_spi_probe(struct spi_device *spi) 27 27 { 28 + struct regmap_config rc; 28 29 struct ksz_device *dev; 29 30 int i, ret; 30 31 ··· 34 33 return -ENOMEM; 35 34 36 35 for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { 37 - dev->regmap[i] = devm_regmap_init_spi(spi, 38 - &ksz8795_regmap_config 39 - [i]); 36 + rc = ksz8795_regmap_config[i]; 37 + rc.lock_arg = &dev->regmap_mutex; 38 + dev->regmap[i] = devm_regmap_init_spi(spi, &rc); 40 39 if (IS_ERR(dev->regmap[i])) { 41 40 ret = PTR_ERR(dev->regmap[i]); 42 41 dev_err(&spi->dev,
+4 -2
drivers/net/dsa/microchip/ksz9477_i2c.c
··· 17 17 static int ksz9477_i2c_probe(struct i2c_client *i2c, 18 18 const struct i2c_device_id *i2c_id) 19 19 { 20 + struct regmap_config rc; 20 21 struct ksz_device *dev; 21 22 int i, ret; 22 23 ··· 26 25 return -ENOMEM; 27 26 28 27 for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) { 29 - dev->regmap[i] = devm_regmap_init_i2c(i2c, 30 - &ksz9477_regmap_config[i]); 28 + rc = ksz9477_regmap_config[i]; 29 + rc.lock_arg = &dev->regmap_mutex; 30 + dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); 31 31 if (IS_ERR(dev->regmap[i])) { 32 32 ret = PTR_ERR(dev->regmap[i]); 33 33 dev_err(&i2c->dev,
+4 -2
drivers/net/dsa/microchip/ksz9477_spi.c
··· 24 24 25 25 static int ksz9477_spi_probe(struct spi_device *spi) 26 26 { 27 + struct regmap_config rc; 27 28 struct ksz_device *dev; 28 29 int i, ret; 29 30 ··· 33 32 return -ENOMEM; 34 33 35 34 for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) { 36 - dev->regmap[i] = devm_regmap_init_spi(spi, 37 - &ksz9477_regmap_config[i]); 35 + rc = ksz9477_regmap_config[i]; 36 + rc.lock_arg = &dev->regmap_mutex; 37 + dev->regmap[i] = devm_regmap_init_spi(spi, &rc); 38 38 if (IS_ERR(dev->regmap[i])) { 39 39 ret = PTR_ERR(dev->regmap[i]); 40 40 dev_err(&spi->dev,
+1 -1
drivers/net/dsa/microchip/ksz_common.c
··· 436 436 } 437 437 438 438 mutex_init(&dev->dev_mutex); 439 - mutex_init(&dev->stats_mutex); 439 + mutex_init(&dev->regmap_mutex); 440 440 mutex_init(&dev->alu_mutex); 441 441 mutex_init(&dev->vlan_mutex); 442 442
+15 -1
drivers/net/dsa/microchip/ksz_common.h
··· 47 47 const char *name; 48 48 49 49 struct mutex dev_mutex; /* device access */ 50 - struct mutex stats_mutex; /* status access */ 50 + struct mutex regmap_mutex; /* regmap access */ 51 51 struct mutex alu_mutex; /* ALU access */ 52 52 struct mutex vlan_mutex; /* vlan access */ 53 53 const struct ksz_dev_ops *dev_ops; ··· 290 290 ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); 291 291 } 292 292 293 + static inline void ksz_regmap_lock(void *__mtx) 294 + { 295 + struct mutex *mtx = __mtx; 296 + mutex_lock(mtx); 297 + } 298 + 299 + static inline void ksz_regmap_unlock(void *__mtx) 300 + { 301 + struct mutex *mtx = __mtx; 302 + mutex_unlock(mtx); 303 + } 304 + 293 305 /* Regmap tables generation */ 294 306 #define KSZ_SPI_OP_RD 3 295 307 #define KSZ_SPI_OP_WR 2 ··· 326 314 .write_flag_mask = \ 327 315 KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp, \ 328 316 regbits, regpad), \ 317 + .lock = ksz_regmap_lock, \ 318 + .unlock = ksz_regmap_unlock, \ 329 319 .reg_format_endian = REGMAP_ENDIAN_BIG, \ 330 320 .val_format_endian = REGMAP_ENDIAN_BIG \ 331 321 }