diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-02-04 20:51:41 -0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-02-04 20:51:41 -0800 |
| commit | 15dd03dfeb1ca0c851092628d397233370fa8367 (patch) | |
| tree | 1bd699a2adf679b032d5bbe92db4c5c55f52bf38 | |
| parent | 677bd4bf5c685d98d9a8ab74cc02bd17c996a4ef (diff) | |
| parent | 61aaa625371440938b55d703501f8820018f737e (diff) | |
Merge branch 'net-stmmac-fix-serdes-power-methods'
Russell King says:
====================
net: stmmac: fix serdes power methods
The stmmac serdes powerup/powerdown methods are not guaranteed to be
called in a balancing fashion, but these are used to call the generic
PHY subsystem's phy_power_up() and phy_power_down() methods which do
require balanced calls.
This series addresses this by making the stmmac serdes methods balanced.
====================
Link: https://patch.msgid.link/aYHHWm5UkD1JVa7D@shell.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 65 |
2 files changed, 41 insertions, 25 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 012b0a477255..5bd97aaaba86 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -303,6 +303,7 @@ struct stmmac_priv { bool eee_enabled; bool eee_active; bool eee_sw_timer_en; + bool legacy_serdes_is_powered; unsigned int mode; unsigned int chain_mode; int extend_desc; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9500b332a152..d561b0a0f5ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -882,6 +882,30 @@ static void stmmac_release_ptp(struct stmmac_priv *priv) clk_disable_unprepare(priv->plat->clk_ptp_ref); } +static void stmmac_legacy_serdes_power_down(struct stmmac_priv *priv) +{ + if (priv->plat->serdes_powerdown && priv->legacy_serdes_is_powered) + priv->plat->serdes_powerdown(priv->dev, priv->plat->bsp_priv); + + priv->legacy_serdes_is_powered = false; +} + +static int stmmac_legacy_serdes_power_up(struct stmmac_priv *priv) +{ + int ret; + + if (!priv->plat->serdes_powerup) + return 0; + + ret = priv->plat->serdes_powerup(priv->dev, priv->plat->bsp_priv); + if (ret < 0) + netdev_err(priv->dev, "SerDes powerup failed\n"); + else + priv->legacy_serdes_is_powered = true; + + return ret; +} + /** * stmmac_mac_flow_ctrl - Configure flow control in all queues * @priv: driver private structure @@ -981,9 +1005,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, u32 old_ctrl, ctrl; int ret; - if ((priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) && - priv->plat->serdes_powerup) - priv->plat->serdes_powerup(priv->dev, priv->plat->bsp_priv); + if (priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) + stmmac_legacy_serdes_power_up(priv); old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ctrl = old_ctrl & ~priv->hw->link.speed_mask; @@ -4111,16 +4134,6 @@ static int __stmmac_open(struct net_device *dev, stmmac_reset_queues_param(priv); - if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) && - priv->plat->serdes_powerup) { - ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv); - if (ret < 0) { - netdev_err(priv->dev, "%s: Serdes powerup failed\n", - __func__); - goto init_error; - } - } - ret = stmmac_hw_setup(dev); if (ret < 0) { netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); @@ -4176,9 +4189,15 @@ static int stmmac_open(struct net_device *dev) if (ret) goto err_runtime_pm; + if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP)) { + ret = stmmac_legacy_serdes_power_up(priv); + if (ret < 0) + goto err_disconnect_phy; + } + ret = __stmmac_open(dev, dma_conf); if (ret) - goto err_disconnect_phy; + goto err_serdes; kfree(dma_conf); @@ -4187,6 +4206,8 @@ static int stmmac_open(struct net_device *dev) return ret; +err_serdes: + stmmac_legacy_serdes_power_down(priv); err_disconnect_phy: phylink_disconnect_phy(priv->phylink); err_runtime_pm: @@ -4221,10 +4242,6 @@ static void __stmmac_release(struct net_device *dev) /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv, &priv->dma_conf); - /* Powerdown Serdes if there is */ - if (priv->plat->serdes_powerdown) - priv->plat->serdes_powerdown(dev, priv->plat->bsp_priv); - stmmac_release_ptp(priv); if (stmmac_fpe_supported(priv)) @@ -4250,6 +4267,7 @@ static int stmmac_release(struct net_device *dev) __stmmac_release(dev); + stmmac_legacy_serdes_power_down(priv); phylink_disconnect_phy(priv->phylink); pm_runtime_put(priv->device); @@ -8130,8 +8148,7 @@ int stmmac_suspend(struct device *dev) /* Stop TX/RX DMA */ stmmac_stop_all_dma(priv); - if (priv->plat->serdes_powerdown) - priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); + stmmac_legacy_serdes_power_down(priv); /* Enable Power down mode by programming the PMT regs */ if (priv->wolopts) { @@ -8233,11 +8250,8 @@ int stmmac_resume(struct device *dev) stmmac_mdio_reset(priv->mii); } - if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) && - priv->plat->serdes_powerup) { - ret = priv->plat->serdes_powerup(ndev, - priv->plat->bsp_priv); - + if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP)) { + ret = stmmac_legacy_serdes_power_up(priv); if (ret < 0) return ret; } @@ -8259,6 +8273,7 @@ int stmmac_resume(struct device *dev) ret = stmmac_hw_setup(ndev); if (ret < 0) { netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); + stmmac_legacy_serdes_power_down(priv); mutex_unlock(&priv->lock); rtnl_unlock(); return ret; |
