[RFC PATCH net-next v3 0/2] net: phylink: wait for a PHY that probes after the MAC
From: Aleksei Sviridkin
Date: Mon Sep 14 2026 - 17:26:18 EST
On an MT7981B board with an MT7531 switch, the Airoha EN8811H behind
lan4 has its PHY driver built as a module on the root filesystem. The
switch sets up its ports before that filesystem is mounted, so the port
is validated against the generic driver, fails its phy-mode and stays
dead for the uptime. Nothing retries it.
Let the PHY node say so with needs-host-firmware and have phylink poll
for the PHY instead of giving up. Patch 1 adds the property, patch 2
does the waiting; the reasoning behind each choice is in patch 2. On
that board the port now attaches at 7.0 s and links up on its own.
Changes since v2:
- A connect that fails with the real driver bound is retried up to
three times at the poll rate, then given up on with one error naming
the PHY node. v2 did not retry and asked whether to retry unless the
PHY node owns a reset line. That condition does not hold up: the
detach asserts whatever reset the DT describes, but the re-attach
runs phy_init_hw() with the driver's soft reset and config_init on
every board, so what a retry costs depends on the board and the PHY
in ways phylink cannot see. It is bounded rather than conditioned.
- The poller returns without attaching if a PHY arrived by another
path while it was queued.
- phylink_destroy() cancels the poller before any teardown instead of
in the middle of it.
- The NULL phydev->drv window v2 asked about is not specific to this
series; phy_attach_direct() meets it from any caller racing a driver
unbind. The guard is posted for net on its own [2] and covers an
unbind already in flight.
- The link_state fix v2 needed is in net-next now, as 113998aa372f
("net: phylink: initialise link_state before a forced major
config"), so this applies without it.
- The MDIO device driver posted beside v2 is withdrawn [3]; nothing
here depends on it.
- Rebased onto net-next.
Still needed underneath: patch 1 of the phylink/phylib pair pending for
net [4]. A late bringup failure has to leave pl->phydev clear: the
poller takes a set pl->phydev for a PHY that arrived by another path,
so without it the first such failure ends the wait with no retry and no
give-up line. It is the prerequisite listed below.
Tested on that board, with these two patches and the prerequisite
backported to its OpenWrt 6.18 tree, warm boots. The retry paths need a
connect that fails after a successful attach, which this chip does not
produce, so those runs used a debug-only module parameter that, after
a successful attach, detaches and fails the connect with -EIO a given
number of times, on an image without the PHY driver so the poller was
still waiting when the driver was loaded by hand:
- one warning after the first minute naming the PHY node, then the
interval doubling up to the 30 s ceiling
- two injected failures: retried 30 s apart, the third attempt
attaches and the link comes up, no give-up line
- failures that do not stop: four attempts at 1 s intervals, one
"giving up on ... after 4 attempts", and with per-iteration tracing
on no further poll in the 237 s the capture covers after it
Retries inherit the interval the wait has reached rather than choosing
one, as the two runs show.
Not tested: cancelling the poller from a teardown while it runs, because
the only path to it on this board, unbinding the switch driver, oopsed
earlier in mt7530_remove() until the fixes in [5]; and a PHY arriving by
a second path, which this board does not offer - that rests on the check
at the top of the poll body.
The runs above also went through both attach branches: in the
two-failure run the PHY attached to a port up since 15.8 s and linked
2.9 s later, and with the driver present it attached at 7.0 s to a port
not yet started, which linked once brought up. Not repeated on v3:
ifdown/ifup with the PHY attached, and checking that the PHY interrupt
fires after a running-port attach.
No in-tree device tree sets needs-host-firmware yet. The board is
supported out of tree, in OpenWrt.
Still asking, which is why this stays RFC:
1. The poller repeats what phylink_fwnode_phy_connect() does - choose
the interface, attach, bring up, detach on failure - with a
different point at which the reference is dropped. Do you want a
shared helper before the rest?
2. Polling was the plan set out in [6]. BUS_NOTIFY_BOUND_DRIVER
gives the exact edge; do you want the notifier in this series
instead?
[1] v2: https://lore.kernel.org/r/20260908155729.4164814-1-f@xxxxxx/
[2] https://lore.kernel.org/r/20260914204200.2743251-1-f@xxxxxx/
[3] https://lore.kernel.org/r/20260912130430.2246285-1-f@xxxxxx/
[4] https://lore.kernel.org/r/20260909204306.2374562-1-f@xxxxxx/
[5] https://lore.kernel.org/r/20260914202421.2737079-1-f@xxxxxx/
[6] https://lore.kernel.org/r/a230d199-5d4d-4637-aff3-e725a37e1da1@xxxxxxx/
Aleksei Sviridkin (2):
dt-bindings: net: ethernet-phy: add needs-host-firmware
net: phylink: wait for PHYs that are known to probe late
.../devicetree/bindings/net/ethernet-phy.yaml | 8 +
drivers/net/phy/phylink.c | 227 +++++++++++++++++-
2 files changed, 228 insertions(+), 7 deletions(-)
base-commit: 879e280b8486d4612ad1aa050d6fada2dd80cf1c
prerequisite-patch-id: 293623f600b825505376e5c5bf72df2ac1f58e1e
--
2.53.0