[openwrt/openwrt] realtek: fix mdio parent/child locking issues

LEDE Commits lede-commits at lists.infradead.org
Sun Jun 8 12:21:40 PDT 2025


hauke pushed a commit to openwrt/openwrt.git, branch openwrt-24.10:
https://git.openwrt.org/0f9ebe2da714f58c25185cfd32845249e61feaf2

commit 0f9ebe2da714f58c25185cfd32845249e61feaf2
Author: Markus Stockhausen <markus.stockhausen at gmx.de>
AuthorDate: Sat May 17 02:22:09 2025 -0400

    realtek: fix mdio parent/child locking issues
    
    Since the early beginning of the Realtek DSA driver there is an uncovered
    locking issue between the standard (parent) mdio bus and the DSA (child)
    mdio bus. This comes from the fact that the DSA bus simply links to the
    parent read and write functions and calls them directly. This leads to
    the following lock issue.
    
    - Child bus calls phy_read/write functions and uses its internal lock
    - Parent bus calls phy_read/write functions and uses its internal lock
    
    It becomes clear that critical section can be accessed twice without
    knowing that a operation from the other bus is currently active. This
    can lead to critical malfunctions because the mdio driver needs a lot of
    internal magic to get page selection done right. Effects are:
    
    - The original page is lost after a phy_write/read_paged() call
    - dmesg like "Realtek RTL8218B (external) rtl838x slave mii-0:00:
      Expected external RTL8218B, found PHY-ID 6b23"
    
    Other DSA drivers simply use the read/write functions from the parent bus
    and thus avoid locking issues. Do it the same way.
    
    Fixes: 2b88563ee5aafd9 ("realtek: update the tree to the latest refactored version")
    Signed-off-by: Markus Stockhausen <markus.stockhausen at gmx.de>
    Link: https://github.com/openwrt/openwrt/pull/18824
    Signed-off-by: Robert Marko <robimarko at gmail.com>
    (cherry picked from commit 461fc06f9d72d032b2acc86fbb7662511e07dd3c)
    Link: https://github.com/openwrt/openwrt/pull/18755
    Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
 .../files-6.6/drivers/net/dsa/rtl83xx/common.c     | 30 ++++++++++++++--------
 .../files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h    |  2 +-
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
index fe0980a1be..805ed182c2 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
@@ -271,6 +271,20 @@ int write_phy(u32 port, u32 page, u32 reg, u32 val)
 	return -1;
 }
 
+static int rtldsa_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+	struct rtl838x_switch_priv *priv = bus->priv;
+
+	return mdiobus_read_nested(priv->parent_bus, addr, regnum);
+}
+
+static int rtldsa_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+	struct rtl838x_switch_priv *priv = bus->priv;
+
+	return mdiobus_write_nested(priv->parent_bus, addr, regnum, val);
+}
+
 static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
 {
 	struct device *dev = priv->dev;
@@ -288,8 +302,8 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
 		return -ENODEV;
 	}
 
-	priv->mii_bus = of_mdio_find_bus(mii_np);
-	if (!priv->mii_bus) {
+	priv->parent_bus = of_mdio_find_bus(mii_np);
+	if (!priv->parent_bus) {
 		pr_debug("Deferring probe of mdio bus\n");
 		return -EPROBE_DEFER;
 	}
@@ -300,18 +314,14 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
 	if (!bus)
 		return -ENOMEM;
 
-	bus->name = "rtl838x slave mii";
-
-	/* Since the NIC driver is loaded first, we can use the mdio rw functions
-	 * assigned there.
-	 */
-	bus->read = priv->mii_bus->read;
-	bus->write = priv->mii_bus->write;
+	bus->name = "rtldsa_mdio";
+	bus->read = rtldsa_mdio_read;
+	bus->write = rtldsa_mdio_write;
 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", bus->name, dev->id);
 
 	bus->parent = dev;
 	priv->ds->slave_mii_bus = bus;
-	priv->ds->slave_mii_bus->priv = priv->mii_bus->priv;
+	priv->ds->slave_mii_bus->priv = priv;
 
 	ret = mdiobus_register(priv->ds->slave_mii_bus);
 	if (ret && mii_np) {
diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
index 16c6098378..c721b4d070 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
@@ -1081,7 +1081,7 @@ struct rtl838x_switch_priv {
 	struct mutex pie_mutex;		/* Mutex for Packet Inspection Engine */
 	int link_state_irq;
 	int mirror_group_ports[4];
-	struct mii_bus *mii_bus;
+	struct mii_bus *parent_bus;
 	const struct rtl838x_reg *r;
 	u8 cpu_port;
 	u8 port_mask;




More information about the lede-commits mailing list