diff options
author | Andrew Lunn <andrew@lunn.ch> | 2016-04-11 15:40:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-11 21:15:48 -0400 |
commit | 9a6f2b0113c8fce815db7c9d23754bdea4b428a0 (patch) | |
tree | 05e5b4205fb6aebdcf105fa8866cfeceeec93ff9 | |
parent | 7c3da7d0d4f3506ef70d9cf148a22400477854d0 (diff) |
net: mdio: Fix lockdep falls positive splat
MDIO devices can be stacked upon each other. The current code supports
two levels, which until recently has been enough for a DSA mdio bus on
top of another bus. Now we have hardware which has an MDIO mux in the
middle.
Define an MDIO MUTEX class with three levels.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/mdio-mux.c | 10 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 4 | ||||
-rw-r--r-- | include/linux/mdio.h | 11 |
3 files changed, 15 insertions, 10 deletions
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 308ade0eb1b6..5c81d6faf304 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c | |||
@@ -45,13 +45,7 @@ static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum) | |||
45 | struct mdio_mux_parent_bus *pb = cb->parent; | 45 | struct mdio_mux_parent_bus *pb = cb->parent; |
46 | int r; | 46 | int r; |
47 | 47 | ||
48 | /* In theory multiple mdio_mux could be stacked, thus creating | 48 | mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); |
49 | * more than a single level of nesting. But in practice, | ||
50 | * SINGLE_DEPTH_NESTING will cover the vast majority of use | ||
51 | * cases. We use it, instead of trying to handle the general | ||
52 | * case. | ||
53 | */ | ||
54 | mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); | ||
55 | r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); | 49 | r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); |
56 | if (r) | 50 | if (r) |
57 | goto out; | 51 | goto out; |
@@ -76,7 +70,7 @@ static int mdio_mux_write(struct mii_bus *bus, int phy_id, | |||
76 | 70 | ||
77 | int r; | 71 | int r; |
78 | 72 | ||
79 | mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); | 73 | mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); |
80 | r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); | 74 | r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); |
81 | if (r) | 75 | if (r) |
82 | goto out; | 76 | goto out; |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 0cba64f1ecf4..751202a285a6 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -457,7 +457,7 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum) | |||
457 | 457 | ||
458 | BUG_ON(in_interrupt()); | 458 | BUG_ON(in_interrupt()); |
459 | 459 | ||
460 | mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); | 460 | mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); |
461 | retval = bus->read(bus, addr, regnum); | 461 | retval = bus->read(bus, addr, regnum); |
462 | mutex_unlock(&bus->mdio_lock); | 462 | mutex_unlock(&bus->mdio_lock); |
463 | 463 | ||
@@ -509,7 +509,7 @@ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val) | |||
509 | 509 | ||
510 | BUG_ON(in_interrupt()); | 510 | BUG_ON(in_interrupt()); |
511 | 511 | ||
512 | mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); | 512 | mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); |
513 | err = bus->write(bus, addr, regnum, val); | 513 | err = bus->write(bus, addr, regnum, val); |
514 | mutex_unlock(&bus->mdio_lock); | 514 | mutex_unlock(&bus->mdio_lock); |
515 | 515 | ||
diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 5bfd99d1a40a..bf9d1d750693 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h | |||
@@ -13,6 +13,17 @@ | |||
13 | 13 | ||
14 | struct mii_bus; | 14 | struct mii_bus; |
15 | 15 | ||
16 | /* Multiple levels of nesting are possible. However typically this is | ||
17 | * limited to nested DSA like layer, a MUX layer, and the normal | ||
18 | * user. Instead of trying to handle the general case, just define | ||
19 | * these cases. | ||
20 | */ | ||
21 | enum mdio_mutex_lock_class { | ||
22 | MDIO_MUTEX_NORMAL, | ||
23 | MDIO_MUTEX_MUX, | ||
24 | MDIO_MUTEX_NESTED, | ||
25 | }; | ||
26 | |||
16 | struct mdio_device { | 27 | struct mdio_device { |
17 | struct device dev; | 28 | struct device dev; |
18 | 29 | ||