drivers/net/phy/mdio_device.c | 6 ++++++ 1 file changed, 6 insertions(+)
From: Leonardo Mörlein <leo.moerlein@proton.me>
Some PHY devices are discovered again after the MDIO bus is torn down and
reprobed, for example when a parent driver first returns -EPROBE_DEFER and
is probed again later.
This breaks boards where external PHYs have per-device reset lines
described through reset-gpios. mdiobus_register_device() acquires the
reset GPIO and asserts reset, mdio_probe() later deasserts it for the
active device, but mdiobus_unregister_device() used to release the GPIO
descriptor without first driving the line back to the inactive state.
If that descriptor was the last owner, then the PHY could remain held
in reset across the next bus registration and disappear from the reprobe
scan.
On a Lantiq GSWIP based FRITZ!Box 7360 v2 this left PHYs 0 and 1 missing
after a deferred reprobe, while PHYs without external reset lines were
still found. DSA then failed to attach those ports with -ENODEV.
Before releasing optional reset resources, deassert reset again for
PHY devices so the hardware stays discoverable across a later reprobe.
Link: https://github.com/openwrt/openwrt/issues/20629
Fixes: 8ea25274ebaf2 ("net: mdiobus: release reset_gpio in mdiobus_unregister_device()")
Cc: stable@vger.kernel.org
Signed-off-by: Leonardo Mörlein <leo.moerlein@proton.me>
Assisted-by: GitHubCopilot:GPT-5.4
---
drivers/net/phy/mdio_device.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index 56080d3d2d25..9caeb9ea5248 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -215,6 +215,12 @@ int mdiobus_unregister_device(struct mdio_device *mdiodev)
if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
return -EINVAL;
+ /*
+ * Leave optional reset lines deasserted before releasing them so devices
+ * remain discoverable across a later bus reprobe.
+ */
+ mdio_device_reset(mdiodev, 0);
+
mdio_device_unregister_reset(mdiodev);
mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
--
2.51.2
On Wed, May 20, 2026 at 03:13:59PM +0000, leo.moerlein@proton.me wrote: > From: Leonardo Mörlein <leo.moerlein@proton.me> > > Some PHY devices are discovered again after the MDIO bus is torn down and > reprobed, for example when a parent driver first returns -EPROBE_DEFER and > is probed again later. > > This breaks boards where external PHYs have per-device reset lines > described through reset-gpios. mdiobus_register_device() acquires the > reset GPIO and asserts reset, mdio_probe() later deasserts it for the > active device, but mdiobus_unregister_device() used to release the GPIO > descriptor without first driving the line back to the inactive state. > If that descriptor was the last owner, then the PHY could remain held > in reset across the next bus registration and disappear from the reprobe > scan. I'm wondering if we are fixing the wrong thing here. Rather than take it out of reset, should it not be put into reset? I assume the bootloader is taking it out of reset? Or does it have a pullup/down so if the GPIO defaults as an input/HiZ, it defaults out of reset? When the GPIO is unregistered, are we leaving it as an output? Andrew
> I'm wondering if we are fixing the wrong thing here.
In general, I see two options to fix this. Either we fix the
tear down or we fix the setup of the device.
Let's look at the current state of the setup code:
Assuming, the reset is asserted when the PHY setup takes place,
it fails because of_mdiobus_phy_device_register() fails with
ENODEV.
This happens the following way:
- of_mdiobus_phy_device_register() -> ENODEV
- fwnode_mdiobus_register_phy() -> ENODEV
- get_phy_device() -> ENODEV
- Asks for the device on the bus.
- (The phy could only answer if reset is deasserted here,
but get_phy_device() currently does not ensure this.)
- Returns ENODEV since there is no PHY present on the bus.
- —— early return here: ENODEV ——
- If the early return wouldn’t happen, the code would continue
calling phy_device_register().
- phy_device_register():
- Handling the reset gpio would start here.
- mdiobus_register_device()
- Asserts reset.
- Deasserts reset.
- Things would go their proper way...
Currently, it seems that this case only occurs when the kernel
leaves the reset asserted. The bootloader initially leaves the
reset deasserted, at least for my current hardware.
Now, we have two options:
a) Deassert the reset in get_phy_device() (or somewhere around it)
before asking for the device on the bus.
b) Deassert the reset in the tear down of the device.
My current patch implements option b).
> Rather than take it out of reset, should it not be put into reset?
If we go for option a), we could do this. But then, I do not see why
we would care at all how we leave the reset?
> When the GPIO is unregistered, are we leaving it as an output?
My current understanding is yes, since mdio_device_unregister_reset()
only calls gpiod_put().
Cheers,
Leo
>> I'm wondering if we are fixing the wrong thing here. > > In general, I see two options to fix this. Either we fix the > tear down or we fix the setup of the device. I have been fighting a different problem with a similar cause. - you should not rely on the bootloader setting anything up. The kernel should be able to perform the initialization without any assumptions about bootloader OR previous state behavior. - from this follows, that the correct way to handle resets is always during the initialization, not leaving it in a known state. - mdio_unregister_device() should reverse mdiobus_register_device(). The reset was in an unknown state before mdiobus_register_device(), so both can be argued: a) you can leave it in either state, since it was not determined before b) you should leave it asserted, to save power If I understand correctly, your resets are asserted by default (when the GPIOs are inputs). I have sent patches that would have taken control of resets before the device is established, but there were problems with that. It would have served a different purpose (PHY ID autodetection), but I think if implemented correctly, it would also help your situation. Russell King replied with a constructive letter, but I lacked the time since to do anything on that thread. See: https://lore.kernel.org/all/5701a9faafd1769b650b79c2d0c72cc10b5bdbc8.1764337894.git.buday.csaba@prolan.hu/#t Please also check out this letter by Andrew about the PHY ID autodetection: https://lore.kernel.org/netdev/23c1bed1-3f95-48b9-8ff0-71696bdcd62b@lunn.ch/ Perhaps specifying the PHY ID would help? It did help me. Regards, Csaba
On Wed, May 20, 2026 at 10:53:04PM +0000, Leonardo Mörlein wrote: > > I'm wondering if we are fixing the wrong thing here. > > In general, I see two options to fix this. Either we fix the > tear down or we fix the setup of the device. Can we take a step back, and look at your actual hardware. What is the state of the hardware when Linux boots, but before the MDIO bus is enumerated? Is the GPIO is configured as an input, and there is a resistor keeping the PHY out of reset? Is the GPIO configured as an output with the reset not asserted, by the bootloader? Maybe when we probe the PHY we need to ask the GPIO subsystem how the GPIO is configured. On unregistered of the PHY we need to put the GPIO back into that state? > Currently, it seems that this case only occurs when the kernel > leaves the reset asserted. The bootloader initially leaves the > reset deasserted, at least for my current hardware. Are you sure about this? Maybe it is simply an input by default, with a resistor pulling the reset line the right way? Andrew
© 2016 - 2026 Red Hat, Inc.