Skip to content

Commit

Permalink
net: dsa: microchip: Add shared regmap mutex
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marek Vasut authored and David S. Miller committed Oct 17, 2019
1 parent 7f238ca commit 013572a
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 9 deletions.
7 changes: 4 additions & 3 deletions drivers/net/dsa/microchip/ksz8795_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ KSZ_REGMAP_TABLE(ksz8795, 16, SPI_ADDR_SHIFT,

static int ksz8795_spi_probe(struct spi_device *spi)
{
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;

Expand All @@ -33,9 +34,9 @@ static int ksz8795_spi_probe(struct spi_device *spi)
return -ENOMEM;

for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
dev->regmap[i] = devm_regmap_init_spi(spi,
&ksz8795_regmap_config
[i]);
rc = ksz8795_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev,
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/dsa/microchip/ksz9477_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0);
static int ksz9477_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;

Expand All @@ -25,8 +26,9 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;

for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
dev->regmap[i] = devm_regmap_init_i2c(i2c,
&ksz9477_regmap_config[i]);
rc = ksz9477_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&i2c->dev,
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/dsa/microchip/ksz9477_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT,

static int ksz9477_spi_probe(struct spi_device *spi)
{
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;

Expand All @@ -32,8 +33,9 @@ static int ksz9477_spi_probe(struct spi_device *spi)
return -ENOMEM;

for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
dev->regmap[i] = devm_regmap_init_spi(spi,
&ksz9477_regmap_config[i]);
rc = ksz9477_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev,
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/microchip/ksz_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ int ksz_switch_register(struct ksz_device *dev,
}

mutex_init(&dev->dev_mutex);
mutex_init(&dev->stats_mutex);
mutex_init(&dev->regmap_mutex);
mutex_init(&dev->alu_mutex);
mutex_init(&dev->vlan_mutex);

Expand Down
16 changes: 15 additions & 1 deletion drivers/net/dsa/microchip/ksz_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct ksz_device {
const char *name;

struct mutex dev_mutex; /* device access */
struct mutex stats_mutex; /* status access */
struct mutex regmap_mutex; /* regmap access */
struct mutex alu_mutex; /* ALU access */
struct mutex vlan_mutex; /* vlan access */
const struct ksz_dev_ops *dev_ops;
Expand Down Expand Up @@ -290,6 +290,18 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset,
ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data);
}

static inline void ksz_regmap_lock(void *__mtx)
{
struct mutex *mtx = __mtx;
mutex_lock(mtx);
}

static inline void ksz_regmap_unlock(void *__mtx)
{
struct mutex *mtx = __mtx;
mutex_unlock(mtx);
}

/* Regmap tables generation */
#define KSZ_SPI_OP_RD 3
#define KSZ_SPI_OP_WR 2
Expand All @@ -314,6 +326,8 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset,
.write_flag_mask = \
KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp, \
regbits, regpad), \
.lock = ksz_regmap_lock, \
.unlock = ksz_regmap_unlock, \
.reg_format_endian = REGMAP_ENDIAN_BIG, \
.val_format_endian = REGMAP_ENDIAN_BIG \
}
Expand Down

0 comments on commit 013572a

Please sign in to comment.