[RFC PATCH net-next 0/9] net: survive a PHY whose firmware arrives after the MAC probes
From: Aleksei Sviridkin <hidden>
Date: 2026-08-29 05:25:55
Also in:
linux-devicetree, lkml
The Airoha EN8811H answers its PHY ID from power-on, but it is an MD32 microcontroller until the host loads firmware into its volatile RAM, and on systems that keep the firmware files in a filesystem those files become readable long after the MDIO bus was scanned. Today the DSA port that names such a PHY is dropped at switch probe and stays dead for the whole uptime. This follows the direction Andrew sketched in [1]: describe the chip as an MDIO device that owns the download and the reset line, publish the PHY on a child bus only once the firmware runs, and teach phylink to wait for a PHY that is expected to probe late. Patches 1-2 add the bindings. Patches 3-5 rework the download into a library helper typed on a bus and address, shared per [2]: the PHY driver keeps its behavior through wrappers, and the helper skips the download when the MD32 already runs firmware - which is what lets the MDIO device and the PHY driver coexist, whichever runs first. Patch 6 adds the MDIO device driver, patch 7 the pass-through bus, patches 8-9 the phylink half. Patches 8-9 alone carry a board whose chip answers its ID before firmware: the MDIO layer buys the general case (chips mute before firmware, quad-PHY packages, reset ownership), not this board's necessity. Tested on an MT7981B board (MT7531 switch, EN8811H on a 2500base-x port), warm boots only - I have no remote way to cut power: - download path: U-Boot leaves the MD32 in its bootloader on every reboot here, so each boot exercises the MCU driver's pulse-reset and download; ~144KB lands in about half a second and the version register reads back - adopt path: rebinding the MDIO device against a running MD32 takes the no-reset branch and registers the bus in ~70ms - the PHY driver, probing on the child bus right after, finds the firmware running and skips its own download through the same check - phylink attaches the PHY ~0.7s later with its interrupt from DT (the poll-tick latency tax below), the port reaches forwarding, and the interrupt line counts link events across forced renegotiations - an ifdown/ifup cycle disconnects and reconnects cleanly The polling costs latency: the attach lands anywhere in [0, poll interval) after the PHY becomes ready. Three consecutive boots measured attach timestamps within 47us of each other, which is the tick phase showing through; mean tax ~500ms, worst case a full second. The exact event exists - BUS_NOTIFY_BOUND_DRIVER fires at probe completion - but mdio_bus_type is internal to phylib, so an event-driven follow-up means phylib owning the notifier behind a small API. Polling first was the plan agreed in [1]. Is that API a direction you want? Two more questions. The property is "slow-to-probe" on the port node, documented in ethernet-controller.yaml; better-scoped names welcome. And the MCU driver cycles reset only when the MD32 sits in its bootloader, since firmware lives in volatile RAM - so on a board without a reset line, running older firmware is adopted as-is and a newer file on disk takes effect only after a cold start. If that trade reads wrong, the alternative is pulsing reset on every probe and always downloading. Known and left out: the retry never gives up, because the errno out of a failed bringup cannot distinguish "still filling in link modes" from "genuinely incompatible" - the backoff exists since a failed bringup ends in phy_detach(), which pulses a PHY-node reset line. Unbinding the MDIO device at runtime while the port is up removes the child bus under an attached PHY and a later phy_stop() oopses; that path predates this series (any mdio-mux unbind does the same) and wants a phy-core fix rather than a workaround here. This is based on net-next at 91ec20351349. It textually overlaps in phylink_disconnect_phy() with the pending fix series [3]; a non-RFC respin will rebase over whichever lands first. [1] https://lore.kernel.org/netdev/a230d199-5d4d-4637-aff3-e725a37e1da1@lunn.ch/ (local) [2] https://lore.kernel.org/netdev/29f973e4-980d-4198-bbec-452f7421d416@lunn.ch/ (local) [3] https://lore.kernel.org/netdev/20260827211638.63395-1-f@lex.la/ (local) Aleksei Sviridkin (9): dt-bindings: net: add Airoha EN8811H PHY MCU dt-bindings: net: ethernet-controller: add slow-to-probe net: phy: air: type the buckpbus core on the bus and address net: phy: air: move the EN8811H firmware download into the library net: phy: air: skip the download when the MD32 is already running net: mdio: add Airoha EN8811H MDIO device driver net: mdio: en8811h: add the nested pass-through bus net: phylink: wait for PHYs that are known to probe late net: phylink: report no link modes while a late PHY is missing .../bindings/net/airoha,en8811h-mcu.yaml | 83 ++++ .../bindings/net/ethernet-controller.yaml | 9 + MAINTAINERS | 7 + drivers/net/mdio/Kconfig | 11 + drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-airoha-en8811h.c | 300 ++++++++++++++ drivers/net/phy/air_en8811h.c | 148 +------ drivers/net/phy/air_phy_lib.c | 381 ++++++++++++++++-- drivers/net/phy/air_phy_lib.h | 27 ++ drivers/net/phy/phylink.c | 225 ++++++++++- 10 files changed, 1011 insertions(+), 181 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml create mode 100644 drivers/net/mdio/mdio-airoha-en8811h.c -- 2.53.0