[PATCH net-next v19 04/10] net: phy: Create SFP phy_port before registering upstream
From: Maxime Chevallier
Date: Fri Oct 16 2026 - 09:34:45 EST
When dealing with PHY-driven SFP, we create a phy_port representing the
SFP bus when we know we have such a bus.
We can move the port creation before registering the sfp upstream ops,
as long as we know the SFP bus is there. This will allow passing the
phy_port along with the upstream information to the SFP bus.
Reviewed-by: Andrew Lunn <andrew@xxxxxxx>
Tested-by: Aleksei Sviridkin <f@xxxxxx>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@xxxxxxxxxx>
Tested-by: Christophe Leroy (CS GROUP) <chleroy@xxxxxxxxxx>
Signed-off-by: Maxime Chevallier <maxime.chevallier@xxxxxxxxxxx>
---
drivers/net/phy/phy_device.c | 62 ++++++++++++++++++++++++------------
1 file changed, 42 insertions(+), 20 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ab1aa8981c00..7713418a6734 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1586,13 +1586,13 @@ static void phy_del_port(struct phy_device *phydev, struct phy_port *port)
phydev->n_ports--;
}
-static int phy_setup_sfp_port(struct phy_device *phydev)
+static struct phy_port *phy_setup_sfp_port(struct phy_device *phydev)
{
struct phy_port *port = phy_port_alloc();
int ret;
if (!port)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
port->parent_type = PHY_PORT_PHY;
port->phy = phydev;
@@ -1607,10 +1607,12 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
* when attaching the port to the phydev.
*/
ret = phy_add_port(phydev, port);
- if (ret)
+ if (ret) {
phy_port_destroy(port);
+ return ERR_PTR(ret);
+ }
- return ret;
+ return port;
}
/**
@@ -1619,32 +1621,48 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
*/
static int phy_sfp_probe(struct phy_device *phydev)
{
+ struct phy_port *port;
struct sfp_bus *bus;
- int ret = 0;
- if (phydev->mdio.dev.fwnode) {
- bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
- if (IS_ERR(bus))
- return PTR_ERR(bus);
+ if (!phydev->mdio.dev.fwnode)
+ return 0;
- phydev->sfp_bus = bus;
+ bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
+ if (IS_ERR(bus))
+ return PTR_ERR(bus);
- ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
- sfp_bus_put(bus);
+ phydev->sfp_bus = bus;
- if (ret)
+ if (bus) {
+ port = phy_setup_sfp_port(phydev);
+ if (IS_ERR(port)) {
+ sfp_bus_put(bus);
phydev->sfp_bus = NULL;
+ return PTR_ERR(port);
+ }
}
- if (!ret && phydev->sfp_bus) {
- ret = phy_setup_sfp_port(phydev);
- if (ret) {
- sfp_bus_del_upstream(phydev->sfp_bus);
- phydev->sfp_bus = NULL;
- }
+ return 0;
+}
+
+static int phy_sfp_add_upstream(struct phy_device *phydev)
+{
+ struct sfp_bus *bus = phydev->sfp_bus;
+ int ret;
+
+ ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
+ if (ret) {
+ sfp_bus_put(bus);
+ phydev->sfp_bus = NULL;
+ return ret;
}
- return ret;
+ /* sfp_bus_add_upstream() grabs a ref to the sfp bus on success, it's
+ * safe to release it now.
+ */
+ sfp_bus_put(bus);
+
+ return 0;
}
/**
@@ -3551,6 +3569,10 @@ static int phy_setup_ports(struct phy_device *phydev)
break;
}
+ ret = phy_sfp_add_upstream(phydev);
+ if (ret)
+ goto err_sfp;
+
return 0;
err_sfp:
--
2.56.0