Commit 15dd03df authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents 677bd4bf 61aaa625
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+40 −25
Original line number Diff line number Diff line
@@ -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;