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>
This commit is contained in:
Jakub Kicinski 2026-02-04 20:51:41 -08:00
commit 15dd03dfeb
2 changed files with 41 additions and 25 deletions

View File

@ -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;

View File

@ -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;