[RFC PATCH net-next v2 06/10] net: phy: air: skip the download when the MD32 is already running

From: Aleksei Sviridkin

Date: Fri Sep 04 2026 - 15:21:43 EST


The download is unconditional, so a chip whose firmware was loaded by
something else - a bootloader, an earlier bind of the PHY driver, or
an MDIO device serving the chip - is reprogrammed at 144KB per probe.

Read the status register the loader already polls for readiness and
skip the download when it reports ready, only picking up the running
firmware's version. Adopting is reported back distinctly from loading,
because nothing on that path touches FW_CTRL_1: the PHY driver must
leave the MCU restart to .config_init() rather than assume probe
already did it.

The image in RAM now wins over the files on disk. Where the PHY node
carries no reset-gpios nothing clears that RAM on unbind, so writing
new firmware files and rebinding keeps the old image running and
reports its version as the current one. A power cycle, or a reset line
on the PHY node for phy_detach() to assert, brings the reload back.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@xxxxxx>
---
drivers/net/phy/air_en8811h.c | 4 ++--
drivers/net/phy/air_phy_lib.c | 17 +++++++++++++++++
drivers/net/phy/air_phy_lib.h | 2 ++
3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index 2f6ed30ba24d..51ff90e60c25 100644
--- a/drivers/net/phy/air_en8811h.c
+++ b/drivers/net/phy/air_en8811h.c
@@ -1019,8 +1019,8 @@ static int en8811h_probe(struct phy_device *phydev)
if (ret < 0)
return ret;

- /* mcu has just restarted after firmware load */
- priv->mcu_needs_restart = false;
+ /* Adopted firmware was never restarted here. */
+ priv->mcu_needs_restart = (ret == 1);

/* MDIO_DEVS1/2 empty, so set mmds_present bits here */
phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c
index 2f3e5b71abac..fc596942eb65 100644
--- a/drivers/net/phy/air_phy_lib.c
+++ b/drivers/net/phy/air_phy_lib.c
@@ -368,6 +368,12 @@ static int air_mmd_status_read(struct mdio_device *mdiodev)
return ret;
}

+bool air_en8811h_mcu_running(struct mdio_device *mdiodev)
+{
+ return air_mmd_status_read(mdiodev) == EN8811H_PHY_READY;
+}
+EXPORT_SYMBOL_GPL(air_en8811h_mcu_running);
+
int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev)
{
int ret, reg_value;
@@ -402,6 +408,17 @@ int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version)
struct device *dev = &mdiodev->dev;
int ret;

+ if (air_en8811h_mcu_running(mdiodev)) {
+ ret = air_mdio_buckpbus_reg_read(mdiodev, EN8811H_FW_VERSION,
+ fw_version);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "MD32 already running, firmware %08x\n",
+ *fw_version);
+ return 1;
+ }
+
ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev);
if (ret < 0)
return ret;
diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h
index 2a4c156d6396..6823812c8fd5 100644
--- a/drivers/net/phy/air_phy_lib.h
+++ b/drivers/net/phy/air_phy_lib.h
@@ -59,7 +59,9 @@ struct firmware;

int air_fw_write_buf(struct mdio_device *mdiodev, u32 address,
const struct firmware *fw);
+bool air_en8811h_mcu_running(struct mdio_device *mdiodev);
int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev);
+/* Returns 1 when it adopted firmware that was already running. */
int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version);

#endif /* __AIR_PHY_LIB_H */
--
2.53.0