lan78xx_suspend() calls phylink_suspend(dev->phylink, false) on an open interface, which always stops phylink and halts the PHY. The matching phylink_resume() is only called from lan78xx_reset_resume(). When the USB device stays powered across system sleep (e.g. s2idle) and the USB core calls .resume instead, the link stays down until the interface is brought down and up by hand. The ifdown triggers: WARNING: drivers/net/phy/phy.c:1670 at phy_stop+0x44/0xc8 called from state HALTED Move phylink_resume() to the end of lan78xx_resume(), which both resume paths go through, and call it only if the resume succeeded and the interface was open, mirroring lan78xx_suspend(). As a side effect, lan78xx_reset_resume() no longer starts phylink on a closed interface. Tested on a Raspberry Pi 3B+ (LAN7515) with s2idle: the link now comes back up on its own after resume and ifdown no longer warns. Fixes: e110bc825897 ("net: usb: lan78xx: Convert to PHYLINK for improved PHY and MAC management") Signed-off-by: Stefano Munari --- ftrace on unpatched kernel (s2idle, woken from PL011 UART IRQ): lan78xx_suspend <- usb_suspend_both phylink_suspend <- lan78xx_suspend phylink_stop <- phylink_suspend phy_stop <- phylink_stop lan78xx_resume <- usb_resume_interface No lan78xx_reset_resume() or phylink_resume() on the resume path. ftrace on patched kernel: lan78xx_resume <- usb_resume_interface phylink_resume <- lan78xx_resume phylink_start <- lan78xx_resume phy_start <- lan78xx_resume phylink_start + phy_start report lan78xx_resume as parent since both are tail calls. On tested kernel phylink_start is tail call optimized since with CONFIG_SFP=n sfp_upstream_start() is an empty stub. --- drivers/net/usb/lan78xx.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 181e8c087655..0136818e8cb0 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -5371,6 +5371,12 @@ static int lan78xx_resume(struct usb_interface *intf) out: mutex_unlock(&dev->dev_mutex); + if (!ret && dev_open) { + rtnl_lock(); + phylink_resume(dev->phylink); + rtnl_unlock(); + } + return ret; } @@ -5385,15 +5391,7 @@ static int lan78xx_reset_resume(struct usb_interface *intf) if (ret < 0) return ret; - ret = lan78xx_resume(intf); - if (ret < 0) - return ret; - - rtnl_lock(); - phylink_resume(dev->phylink); - rtnl_unlock(); - - return 0; + return lan78xx_resume(intf); } static const struct usb_device_id products[] = { -- 2.55.0