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 <justin.chen@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://patch.msgid.link/20260506213114.2002886-3-justin.chen@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Justin Chen 2026-05-06 14:31:14 -07:00 committed by Jakub Kicinski
parent e97ffa4e97
commit e447b677bb

View File

@ -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;
wake = device_may_wakeup(kdev) && intf->wolopts;
bcmasp_core_clock_set_intf(intf, true);
bcmasp_resume_from_wol(intf);
bcmasp_phy_hw_prepare(intf);
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);