lan78xx_disconnect() stops phylink before unregistering the net device.
phylink_start() is only called from lan78xx_open(), so when the device is
unplugged before the interface has been brought up, the attached PHY is
still in PHY_READY and phy_stop() reports:
called from state READY
WARNING: drivers/net/phy/phy.c:1670 at phy_stop+0xad/0x380
The same warning is emitted after an ifup/ifdown cycle, where the PHY is
already in PHY_HALTED.
unregister_netdev() already closes a running device, which calls
lan78xx_stop() and phylink_stop() with dev->dev_mutex held and after the
URBs have been terminated. Unregister first and disconnect the PHY
afterwards, so the interface is stopped exactly once and only while it is
running, and the net device can no longer be opened while its phylink
instance has no PHY attached.
Fixes: e110bc825897 ("net: usb: lan78xx: Convert to PHYLINK for improved PHY and MAC management")
Cc: <redacted>
Co-developed-by: Bin Yu <redacted>
Signed-off-by: Bin Yu <redacted>
Co-developed-by: Cheng Wen <redacted>
Signed-off-by: Cheng Wen <redacted>
Signed-off-by: YuanZhe Liu <redacted>
---
v2:
- Drop the explicit phylink_stop() and call unregister_netdev() first, as
pointed out in review. A running interface is stopped by lan78xx_stop()
with dev->dev_mutex held and after the URBs have been terminated; an
interface that was never started is not stopped at all.
- The PHY interrupt mapping is released by lan78xx_remove_irq_domain() in
lan78xx_unbind(), not by phylink_disconnect_phy(); that ordering is
unchanged by this patch.
- Link: https://lore.kernel.org/r/20261029160204.2567-1-25031212351@stu.xidian.edu.cn (local)
drivers/net/usb/lan78xx.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 5655941f1478..c1f3141326ac 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -4580,13 +4580,12 @@ static void lan78xx_disconnect(struct usb_interface *intf)
net = dev->net;
+ unregister_netdev(net);
+
rtnl_lock();
- phylink_stop(dev->phylink);
phylink_disconnect_phy(dev->phylink);
rtnl_unlock();
- unregister_netdev(net);
-
timer_shutdown_sync(&dev->stat_monitor);
set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
cancel_delayed_work_sync(&dev->wq);
--
2.34.1