aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips
diff options
context:
space:
mode:
authorDENG Qingfang <dqfext@gmail.com>2021-04-03 22:59:15 +0800
committerChuanhong Guo <gch981213@gmail.com>2021-04-15 00:00:54 +0800
commitf99c9cd9c4d4c49a676d678327546fd41690fe2a (patch)
tree6976653d304444fb5ef5c4a45ecc7f167038da98 /target/linux/ramips
parent679c557e9121f3609346a9f9926130a4e99f18de (diff)
downloadupstream-f99c9cd9c4d4c49a676d678327546fd41690fe2a.tar.gz
upstream-f99c9cd9c4d4c49a676d678327546fd41690fe2a.tar.bz2
upstream-f99c9cd9c4d4c49a676d678327546fd41690fe2a.zip
ramips: mt7530 swconfig: fix race condition in register access
The mt7530_{r,w}32 operation over MDIO uses 3 mdiobus operations and does not hold a lock, which causes a race condition when multiple threads try to access a register, they may get unexpected results. To avoid this, handle the MDIO lock manually, and use the unlocked __mdiobus_{read,write} in the critical section. This fixes the "Ghost VLAN" artifact[1] in MT7530/7621 when the VLAN operation and the swconfig LED link status poll race between each other. [1] https://forum.openwrt.org/t/mysterious-vlan-ids-on-mt7621-device/64495 Signed-off-by: DENG Qingfang <dqfext@gmail.com>
Diffstat (limited to 'target/linux/ramips')
-rw-r--r--target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c
index be1b8a6d8e..b4632d3990 100644
--- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c
+++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c
@@ -290,9 +290,11 @@ mt7530_r32(struct mt7530_priv *priv, u32 reg)
if (priv->bus) {
u16 high, low;
- mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
- low = mdiobus_read(priv->bus, 0x1f, (reg >> 2) & 0xf);
- high = mdiobus_read(priv->bus, 0x1f, 0x10);
+ mutex_lock(&priv->bus->mdio_lock);
+ __mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ low = __mdiobus_read(priv->bus, 0x1f, (reg >> 2) & 0xf);
+ high = __mdiobus_read(priv->bus, 0x1f, 0x10);
+ mutex_unlock(&priv->bus->mdio_lock);
return (high << 16) | (low & 0xffff);
}
@@ -307,9 +309,11 @@ static void
mt7530_w32(struct mt7530_priv *priv, u32 reg, u32 val)
{
if (priv->bus) {
- mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
- mdiobus_write(priv->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
- mdiobus_write(priv->bus, 0x1f, 0x10, val >> 16);
+ mutex_lock(&priv->bus->mdio_lock);
+ __mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ __mdiobus_write(priv->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
+ __mdiobus_write(priv->bus, 0x1f, 0x10, val >> 16);
+ mutex_unlock(&priv->bus->mdio_lock);
return;
}