[PATCH net] net: dsa: skip user_mii_bus fallback if phy-handle is set

Daniel Golle
2026-03-06T03:16:54Z

When phylink_of_phy_connect() returns -ENODEV, dsa_user_phy_setup()
falls back to connecting the port to the PHY at dp->index on the
switch's internal MDIO bus. This fallback was introduced to handle
switches where no explicit phy-handle is given in DT. However, if a
phy-handle property is present but the referenced PHY device is not
yet available at registration time, phylink_of_phy_connect() also
returns -ENODEV, causing the fallback to potentially attach the wrong
PHY device instead of propagating the error.

This becomes a very weird bug on switches on which the PHY address
isn't equal to the corresponding DSA port's index, as failure to
attach the PHY with -ENOENT then just attaches another PHY, typically
rendering two ports unusable instead of just one (and until you read
and understand the code it looks like an alarming memory corruption
rather than just PHY not being ready on time).

Fix this by calling fwnode_get_phy_node() before falling back:
If a phy-handle fwnode exists, skip the internal bus fallback and let
the -ENODEV propagate to the caller. The fallback is only taken when
no phy-handle is present in DT, which was the original intent.

Fixes: aab9c4067d238 ("net: dsa: Plug in PHYLINK support")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
net/dsa/user.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/net/dsa/user.c b/net/dsa/user.c
index c4bd6fe90b455..90e540f490bb3 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -2656,6 +2656,7 @@ static int dsa_user_phy_setup(struct net_device *user_dev)
{
struct dsa_port *dp = dsa_user_to_port(user_dev);
struct device_node *port_dn = dp->dn;
+ struct fwnode_handle *phy_fwnode;
struct dsa_switch *ds = dp->ds;
u32 phy_flags = 0;
int ret;
@@ -2682,9 +2683,18 @@ static int dsa_user_phy_setup(struct net_device *user_dev)
ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags);
if (ret == -ENODEV && ds->user_mii_bus) {
/* We could not connect to a designated PHY or SFP, so try to
- * use the switch internal MDIO bus instead
+ * use the switch internal MDIO bus instead. Only fall back if
+ * no phy-handle was specified in DT. If a phy-handle exists
+ * but the PHY device is missing (e.g. not yet ready at
+ * registration time), connecting to a PHY at dp->index would
+ * attach the wrong PHY device.
*/
- ret = dsa_user_phy_connect(user_dev, dp->index, phy_flags);
+ phy_fwnode = fwnode_get_phy_node(of_fwnode_handle(port_dn));
+ if (IS_ERR(phy_fwnode))
+ ret = dsa_user_phy_connect(user_dev, dp->index,
+ phy_flags);
+ else
+ fwnode_handle_put(phy_fwnode);
}
if (ret) {
netdev_err(user_dev, "failed to connect to PHY: %pe\n",
--
2.53.0