]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: dsa: postpone probe due to deferred PHYs 23075/head
authorSven Eckelmann <sven@narfation.org>
Tue, 7 Apr 2026 07:14:25 +0000 (09:14 +0200)
committerRobert Marko <robimarko@gmail.com>
Mon, 27 Apr 2026 08:36:23 +0000 (10:36 +0200)
PHY drivers might need access to NVMEM or the filesystem to load
calibration/initialization data. The driver will then return -EPROBE_DEFER
to signal to the device core that the probe should be retried multiple
times again in the 10s driver_deferred_probe_timeout.

But when the switch driver calls dsa_register_switch(), it needs to connect
the PHYs directly. As result, all PHYs without an driver will automatically
get the default driver (either `genphy_c45_driver` or `genphy_driver`)
assigned and initialized. But for PHYs with the additional initialization
data from NVMEM/fs, this will usually result in not working PHYs.

Since there are Realtek based boards with RTL826x PHYs and the new driver
loads the initialization/patch values from rootfs, it is necessary to check
in the beginning of the probe function whether the PHYs are ready and the
probing can continue.

If some driver is still without driver after the deferred probe period
ended, the loading will just continue and the generic PHY drivers will
still be used.

Closes: #22811
Co-authored-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Co-authored-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Link: https://github.com/openwrt/openwrt/pull/23075
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c

index e0d3a59e6c98bc3ed37a3a53493f4d27e269755c..964d3d64eba56d0473e0fc7d7b8d06448e23d2e1 100644 (file)
@@ -211,6 +211,48 @@ u64 rtl839x_get_port_reg_le(int reg)
        return v;
 }
 
+static bool rtldsa_phy_load_deferred(struct phy_device *phydev)
+{
+       struct device *d = &phydev->mdio.dev;
+
+       if (d->driver)
+               return false;
+
+       return driver_deferred_probe_check_state(d) == -EPROBE_DEFER;
+}
+
+static bool rtldsa_phys_load_deferred(void)
+{
+       struct device_node *phy_node;
+       struct phy_device *phydev;
+       struct device_node *dn;
+       bool deferred;
+
+       for_each_node_by_name(dn, "port") {
+               if (!of_device_is_available(dn))
+                       continue;
+
+               phy_node = of_parse_phandle(dn, "phy-handle", 0);
+               if (!phy_node)
+                       continue;
+
+               phydev = of_phy_find_device(phy_node);
+               of_node_put(phy_node);
+               if (!phydev)
+                       continue;
+
+               deferred = rtldsa_phy_load_deferred(phydev);
+               put_device(&phydev->mdio.dev);
+
+               if (deferred) {
+                       of_node_put(dn);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
 {
        struct device_node *dn, *phy_node, *pcs_node, *led_node;
@@ -1528,6 +1570,9 @@ static int rtl83xx_sw_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       if (rtldsa_phys_load_deferred())
+               return -EPROBE_DEFER;
+
        err = rtldsa_ethernet_loaded(pdev);
        if (err)
                return err;