The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH net-next] net: phy: mdio-i2c: defer RollBall bridge probe to PHY discovery
@ 2026-06-04 18:12 Petr Wozniak
  2026-06-04 21:15 ` Maxime Chevallier
  2026-06-05  5:30 ` [PATCH v2 " Petr Wozniak
  0 siblings, 2 replies; 4+ messages in thread
From: Petr Wozniak @ 2026-06-04 18:12 UTC (permalink / raw)
  To: netdev
  Cc: kuba, andrew, hkallweit1, linux, davem, edumazet, pabeni,
	linux-phy, linux-kernel, maxime.chevallier, bjorn, olek2,
	Petr Wozniak

commit 8fe125892f40 ("net: phy: sfp: probe for RollBall I2C-to-MDIO
bridge in mdio-i2c") introduced a regression: for SFP modules inserted
before system boot, the RollBall I2C-to-MDIO bridge is not yet ready to
respond to CMD_READ/CMD_DONE cycles when sfp_sm_add_mdio_bus() runs.
The 200 ms probe times out, i2c_mii_probe_rollball() returns -ENODEV,
and sfp_sm_add_mdio_bus() sets mdio_protocol = MDIO_I2C_NONE.  By the
time sfp_sm_probe_for_phy() runs (up to ~17 s later on affected
hardware), the bridge is fully initialized — but PHY probing is skipped
because the protocol has already been changed to NONE.

Move the probe from i2c_mii_init_rollball() — called at bus-creation
time — to sfp_sm_probe_for_phy() in sfp.c, where it runs after the SFP
state machine's module initialization delays.  Export the probe function
as mdio_i2c_probe_rollball() so sfp.c can call it.

For RTL8261BE-based modules: the probe correctly returns -ENODEV at PHY
discovery time, causing sfp_sm_probe_for_phy() to destroy the MDIO bus
and set MDIO_I2C_NONE — eliminating the 5+ minute PHY probe retry loop.

For genuine RollBall modules inserted before boot (e.g. FLYPRO
SFP-10GT-CS-30M with Aquantia AQR113C): the probe now runs after
initialization is complete and correctly returns 0 — PHY detection
proceeds normally.

Reported-by: Aleksander Bajkowski <olek2@wp.pl>
Fixes: 8fe125892f40 ("net: phy: sfp: probe for RollBall I2C-to-MDIO bridge in mdio-i2c")
Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com>
---
 drivers/net/mdio/mdio-i2c.c   | 18 ++++--------------
 drivers/net/phy/sfp.c         | 18 ++++++++++++------
 include/linux/mdio/mdio-i2c.h |  1 +
 3 files changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c
--- a/drivers/net/mdio/mdio-i2c.c
+++ b/drivers/net/mdio/mdio-i2c.c
@@ -352,7 +352,7 @@
 	return 0;
 }

-static int i2c_mii_probe_rollball(struct i2c_adapter *i2c)
+int mdio_i2c_probe_rollball(struct i2c_adapter *i2c)
 {
 	u8 data_buf[] = { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 };
 	u8 cmd_buf[]  = { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ };
@@ -397,9 +397,11 @@

 	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(mdio_i2c_probe_rollball);

 static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
 {
+	/* Send the RollBall unlock password; bridge presence is verified
+	 * later, in sfp_sm_probe_for_phy(), after module initialization. */
 	struct i2c_msg msg;
 	u8 pw[5];
 	int ret;
@@ -419,7 +421,7 @@
 	if (ret != 1)
 		return -EIO;

-	return i2c_mii_probe_rollball(i2c);
+	return 0;
 }

 struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
@@ -444,12 +446,8 @@
 	case MDIO_I2C_ROLLBALL:
 		ret = i2c_mii_init_rollball(i2c);
 		if (ret < 0) {
-			if (ret != -ENODEV)
-				dev_err(parent,
-					"Cannot initialize RollBall MDIO I2C protocol: %d\n",
-					ret);
-			/* -ENODEV propagates to caller: no bridge present,
-			 * PHY probing should be skipped for this module. */
+			dev_err(parent,
+				"Cannot initialize RollBall MDIO I2C protocol: %d\n",
+				ret);
 			mdiobus_free(mii);
 			return ERR_PTR(ret);
 		}
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2028,17 +2028,8 @@ static int sfp_sm_add_mdio_bus(struct sfp *sfp)
 	dev_info(sfp->dev, "probing phy device through the [%s] protocol\n",
 		 mdio_i2c_proto_type(sfp->mdio_protocol));

-	int ret;
-
 	if (sfp->mdio_protocol == MDIO_I2C_NONE)
 		return 0;

-	ret = sfp_i2c_mdiobus_create(sfp);
-	if (ret == -ENODEV) {
-		/* Probe confirmed no bridge present; skip PHY discovery. */
-		sfp->mdio_protocol = MDIO_I2C_NONE;
-		return 0;
-	}
-	return ret;
+	return sfp_i2c_mdiobus_create(sfp);
 }

 /* Probe a SFP for a PHY device if the module supports copper - the PHY
@@ -2058,8 +2049,23 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)

 	case MDIO_I2C_ROLLBALL:
-		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true);
+		/* Probe here, after module initialization delays, so that
+		 * genuine RollBall bridges have had time to start up.
+		 * Modules without a bridge (e.g. RTL8261BE) return -ENODEV. */
+		err = mdio_i2c_probe_rollball(sfp->i2c);
+		if (err == -ENODEV) {
+			sfp_i2c_mdiobus_destroy(sfp);
+			sfp->mdio_protocol = MDIO_I2C_NONE;
+			break;
+		}
+		if (!err)
+			err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true);
 		break;
 	}
diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h
--- a/include/linux/mdio/mdio-i2c.h
+++ b/include/linux/mdio/mdio-i2c.h
@@ -33,5 +33,6 @@

 struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
 			       enum mdio_i2c_proto protocol);
+int mdio_i2c_probe_rollball(struct i2c_adapter *i2c);

 #endif
--
2.51.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-09  2:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-04 18:12 [PATCH net-next] net: phy: mdio-i2c: defer RollBall bridge probe to PHY discovery Petr Wozniak
2026-06-04 21:15 ` Maxime Chevallier
2026-06-05  5:30 ` [PATCH v2 " Petr Wozniak
2026-06-09  2:28   ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox