From: Justin Chen Date: Wed, 6 May 2026 21:31:14 +0000 (-0700) Subject: net: bcmasp: Keep phy link during WoL sleep cycle X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e447b677bb2658d358830919d661a27a415827f7;p=thirdparty%2Flinux.git net: bcmasp: Keep phy link during WoL sleep cycle We currently more or less restart all the HW on resume. Since we also stop the PHY, it takes a while for the PHY link to be re-negotiated on resume. Instead of doing a full restart, we keep the HW state and the PHY link, that way we can resume network traffic with a much smaller delay. Signed-off-by: Justin Chen Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20260506213114.2002886-3-justin.chen@broadcom.com Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index e2b51ec903af..ed0977832ce4 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -923,7 +923,7 @@ static void bcmasp_phy_hw_unprepare(struct bcmasp_intf *intf) bcmasp_rgmii_mode_en_set(intf, false); } -static void bcmasp_netif_deinit(struct net_device *dev) +static void bcmasp_netif_deinit(struct net_device *dev, bool stop_phy) { struct bcmasp_intf *intf = netdev_priv(dev); u32 reg, timeout = 1000; @@ -946,7 +946,8 @@ static void bcmasp_netif_deinit(struct net_device *dev) umac_enable_set(intf, UMC_CMD_TX_EN, 0); - phy_stop(dev->phydev); + if (stop_phy) + phy_stop(dev->phydev); umac_enable_set(intf, UMC_CMD_RX_EN, 0); @@ -974,7 +975,7 @@ static int bcmasp_stop(struct net_device *dev) /* Stop tx from updating HW */ netif_tx_disable(dev); - bcmasp_netif_deinit(dev); + bcmasp_netif_deinit(dev, true); bcmasp_reclaim_free_buffers(intf); @@ -1385,15 +1386,26 @@ int bcmasp_interface_suspend(struct bcmasp_intf *intf) { struct device *kdev = &intf->parent->pdev->dev; struct net_device *dev = intf->ndev; + bool wake; if (!netif_running(dev)) return 0; netif_device_detach(dev); - bcmasp_netif_deinit(dev); + wake = device_may_wakeup(kdev) && intf->wolopts; - if (!intf->wolopts) { + bcmasp_netif_deinit(dev, !wake); + + if (wake) { + /* Disable phy status updates while suspending */ + mutex_lock(&dev->phydev->lock); + dev->phydev->state = PHY_READY; + mutex_unlock(&dev->phydev->lock); + cancel_delayed_work_sync(&dev->phydev->state_queue); + + bcmasp_suspend_to_wol(intf); + } else { bcmasp_phy_hw_unprepare(intf); /* If Wake-on-LAN is disabled, we can safely @@ -1402,9 +1414,6 @@ int bcmasp_interface_suspend(struct bcmasp_intf *intf) bcmasp_core_clock_set_intf(intf, false); } - if (device_may_wakeup(kdev) && intf->wolopts) - bcmasp_suspend_to_wol(intf); - clk_disable_unprepare(intf->parent->clk); return 0; @@ -1428,8 +1437,11 @@ static void bcmasp_resume_from_wol(struct bcmasp_intf *intf) int bcmasp_interface_resume(struct bcmasp_intf *intf) { + struct device *kdev = &intf->parent->pdev->dev; struct net_device *dev = intf->ndev; + bool wake; int ret; + u32 reg; if (!netif_running(dev)) return 0; @@ -1438,17 +1450,39 @@ int bcmasp_interface_resume(struct bcmasp_intf *intf) if (ret) return ret; - bcmasp_core_clock_set_intf(intf, true); + wake = device_may_wakeup(kdev) && intf->wolopts; - bcmasp_resume_from_wol(intf); - - bcmasp_phy_hw_prepare(intf); + bcmasp_core_clock_set_intf(intf, true); - umac_reset_and_init(intf, dev->dev_addr); + /* The interface might be HW reset in some suspend modes, so we may + * need to restore the UNIMAC/PHY if that is the case. + */ + reg = umac_rl(intf, UMC_CMD); + if (wake && (reg & UMC_CMD_RX_EN)) { + umac_enable_set(intf, UMC_CMD_TX_EN, 1); + bcmasp_resume_from_wol(intf); + } else { + bcmasp_phy_hw_prepare(intf); + umac_reset_and_init(intf, dev->dev_addr); + } bcmasp_netif_init(dev); - phy_start(dev->phydev); + if (wake) { + /* If HW was reset, reprogram the unimac/PHY before resuming + * link status tracking to avoid racing the state machine. + */ + if (!(reg & UMC_CMD_RX_EN)) + bcmasp_adj_link(dev); + + /* Resume link status tracking */ + mutex_lock(&dev->phydev->lock); + dev->phydev->state = dev->phydev->link ? PHY_RUNNING : PHY_NOLINK; + mutex_unlock(&dev->phydev->lock); + phy_trigger_machine(dev->phydev); + } else { + phy_start(dev->phydev); + } netif_device_attach(dev);