[net-next RFC PATCH v2 1/3] net: phy: permit PHYs to register a second time

Christian Marangi
2025-03-26T00:24:43Z

Some PHY might needs to register AGAIN after a firmware is loaded to
correctly provide the real PHY ID.

It was found that some PHY expose on the BUS with a PHY ID that change
as soon as the PHY firmware is loaded and started.

To better handle this case and provide to the system correct info on
what PHY is actually present on the BUS, introduce a new option for PHY
device, needs_reregister, that register the PHY device 2 times.

With needs_reregister enabled, in phy_device_register() the PHY is first
registered with the driver detected for the PHY ID. The PHY driver is
then released and the PHY ID for the PHY address is rescanned.
The phy_id and c45_ids entry are updated for the PHY device and finally
the PHY is registered again with the more specific PHY driver. (matching
the new PHY ID)

It's assumed that loading the firmware doesn't cause the PHY ID to change
to different vendor or PHY of different family (provided by different
drivers)

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/phy/phy_device.c | 27 +++++++++++++++++++++++++++
include/linux/phy.h | 5 +++++
2 files changed, 32 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 46713d27412b..d5938aacc0fe 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -987,6 +987,33 @@ int phy_device_register(struct phy_device *phydev)
goto out;
}

+ /* Some PHY might needs to register AGAIN after a firmware
+ * is loaded to correctly provide the real PHY ID.
+ * For PHY that needs this, release the PHY driver, rescan
+ * the MDIO bus for the PHY address and attach a driver
+ * again.
+ * This second time, the real PHY is provided and the
+ * more specific PHY driver OPs are used.
+ */
+ if (phydev->needs_reregister) {
+ device_release_driver(&phydev->mdio.dev);
+
+ if (phydev->is_c45)
+ get_phy_c45_ids(phydev->mdio.bus,
+ phydev->mdio.addr,
+ &phydev->c45_ids);
+ else
+ get_phy_c22_id(phydev->mdio.bus,
+ phydev->mdio.addr,
+ &phydev->phy_id);
+
+ err = device_attach(&phydev->mdio.dev);
+ if (err <= 0) {
+ phydev_err(phydev, "failed to reattach\n");
+ goto out;
+ }
+ }
+
return 0;

out:
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 19f076a71f94..00ddfbe7033b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -578,6 +578,10 @@ struct macsec_ops;
* @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY
* @wol_enabled: Set to true if the PHY or the attached MAC have Wake-on-LAN
* enabled.
+ * @needs_reregister: Set to true if the PHY needs to register AGAIN after
+ * first registration. This is to handle special case where the
+ * PHY needs to load a firmware to correctly communicate the
+ * specific PHY ID.
* @state: State of the PHY for management purposes
* @dev_flags: Device-specific flags used by the PHY driver.
*
@@ -681,6 +685,7 @@ struct phy_device {
unsigned is_on_sfp_module:1;
unsigned mac_managed_pm:1;
unsigned wol_enabled:1;
+ unsigned needs_reregister;

unsigned autoneg:1;
/* The most recently read link state */
--
2.48.1