From: Sven Eckelmann Date: Tue, 7 Apr 2026 07:14:25 +0000 (+0200) Subject: realtek: dsa: postpone probe due to deferred PHYs X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F23075%2Fhead;p=thirdparty%2Fopenwrt.git realtek: dsa: postpone probe due to deferred PHYs 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 Co-authored-by: Markus Stockhausen Signed-off-by: Sven Eckelmann Link: https://github.com/openwrt/openwrt/pull/23075 Signed-off-by: Robert Marko --- diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c index e0d3a59e6c9..964d3d64eba 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c @@ -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;