forked from mirrors/linux
		
	net: stmmac: add clocks management for gmac driver
This patch intends to add clocks management for stmmac driver: If CONFIG_PM enabled: 1. Keep clocks disabled after driver probed. 2. Enable clocks when up the net device, and disable clocks when down the net device. If CONFIG_PM disabled: Keep clocks always enabled after driver probed. Note: 1. It is fine for ethtool, since the way of implementing ethtool_ops::begin in stmmac is only can be accessed when interface is enabled, so the clocks are ticked. 2. The MDIO bus has a different life cycle to the MAC, need ensure clocks are enabled when _mdio_read/write() need clocks, because these functions can be called while the interface it not opened. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									91de5ac99a
								
							
						
					
					
						commit
						5ec5582343
					
				
					 4 changed files with 174 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -272,6 +272,7 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
 | 
			
		|||
bool stmmac_eee_init(struct stmmac_priv *priv);
 | 
			
		||||
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
 | 
			
		||||
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
 | 
			
		||||
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
 | 
			
		||||
void stmmac_selftest_run(struct net_device *dev,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
#include <linux/if_vlan.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/pm_runtime.h>
 | 
			
		||||
#include <linux/prefetch.h>
 | 
			
		||||
#include <linux/pinctrl/consumer.h>
 | 
			
		||||
#ifdef CONFIG_DEBUG_FS
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +114,28 @@ static void stmmac_exit_fs(struct net_device *dev);
 | 
			
		|||
 | 
			
		||||
#define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC))
 | 
			
		||||
 | 
			
		||||
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (enabled) {
 | 
			
		||||
		ret = clk_prepare_enable(priv->plat->stmmac_clk);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
		ret = clk_prepare_enable(priv->plat->pclk);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			clk_disable_unprepare(priv->plat->stmmac_clk);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		clk_disable_unprepare(priv->plat->stmmac_clk);
 | 
			
		||||
		clk_disable_unprepare(priv->plat->pclk);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(stmmac_bus_clks_config);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * stmmac_verify_args - verify the driver parameters.
 | 
			
		||||
 * Description: it checks the driver parameters and set a default in case of
 | 
			
		||||
| 
						 | 
				
			
			@ -2896,6 +2919,12 @@ static int stmmac_open(struct net_device *dev)
 | 
			
		|||
	u32 chan;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
 | 
			
		||||
	    priv->hw->pcs != STMMAC_PCS_RTBI &&
 | 
			
		||||
	    priv->hw->xpcs_args.an_mode != DW_AN_C73) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2904,7 +2933,7 @@ static int stmmac_open(struct net_device *dev)
 | 
			
		|||
			netdev_err(priv->dev,
 | 
			
		||||
				   "%s: Cannot attach to PHY (error: %d)\n",
 | 
			
		||||
				   __func__, ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto init_phy_error;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3020,6 +3049,8 @@ static int stmmac_open(struct net_device *dev)
 | 
			
		|||
	free_dma_desc_resources(priv);
 | 
			
		||||
dma_desc_error:
 | 
			
		||||
	phylink_disconnect_phy(priv->phylink);
 | 
			
		||||
init_phy_error:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3070,6 +3101,8 @@ static int stmmac_release(struct net_device *dev)
 | 
			
		|||
 | 
			
		||||
	stmmac_release_ptp(priv);
 | 
			
		||||
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4706,6 +4739,12 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
 | 
			
		|||
	bool is_double = false;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (be16_to_cpu(proto) == ETH_P_8021AD)
 | 
			
		||||
		is_double = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4739,10 +4778,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
 | 
			
		|||
	if (priv->hw->num_vlan) {
 | 
			
		||||
		ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto del_vlan_error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return stmmac_vlan_update(priv, is_double);
 | 
			
		||||
	ret = stmmac_vlan_update(priv, is_double);
 | 
			
		||||
 | 
			
		||||
del_vlan_error:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct net_device_ops stmmac_netdev_ops = {
 | 
			
		||||
| 
						 | 
				
			
			@ -5181,6 +5225,10 @@ int stmmac_dvr_probe(struct device *device,
 | 
			
		|||
 | 
			
		||||
	stmmac_check_pcs_mode(priv);
 | 
			
		||||
 | 
			
		||||
	pm_runtime_get_noresume(device);
 | 
			
		||||
	pm_runtime_set_active(device);
 | 
			
		||||
	pm_runtime_enable(device);
 | 
			
		||||
 | 
			
		||||
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
 | 
			
		||||
	    priv->hw->pcs != STMMAC_PCS_RTBI) {
 | 
			
		||||
		/* MDIO bus Registration */
 | 
			
		||||
| 
						 | 
				
			
			@ -5218,6 +5266,11 @@ int stmmac_dvr_probe(struct device *device,
 | 
			
		|||
	stmmac_init_fs(ndev);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Let pm_runtime_put() disable the clocks.
 | 
			
		||||
	 * If CONFIG_PM is not enabled, the clocks will stay powered.
 | 
			
		||||
	 */
 | 
			
		||||
	pm_runtime_put(device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
error_serdes_powerup:
 | 
			
		||||
| 
						 | 
				
			
			@ -5232,6 +5285,7 @@ int stmmac_dvr_probe(struct device *device,
 | 
			
		|||
	stmmac_napi_del(ndev);
 | 
			
		||||
error_hw_init:
 | 
			
		||||
	destroy_workqueue(priv->wq);
 | 
			
		||||
	stmmac_bus_clks_config(priv, false);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5267,8 +5321,8 @@ int stmmac_dvr_remove(struct device *dev)
 | 
			
		|||
	phylink_destroy(priv->phylink);
 | 
			
		||||
	if (priv->plat->stmmac_rst)
 | 
			
		||||
		reset_control_assert(priv->plat->stmmac_rst);
 | 
			
		||||
	clk_disable_unprepare(priv->plat->pclk);
 | 
			
		||||
	clk_disable_unprepare(priv->plat->stmmac_clk);
 | 
			
		||||
	pm_runtime_put(dev);
 | 
			
		||||
	pm_runtime_disable(dev);
 | 
			
		||||
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
 | 
			
		||||
	    priv->hw->pcs != STMMAC_PCS_RTBI)
 | 
			
		||||
		stmmac_mdio_unregister(ndev);
 | 
			
		||||
| 
						 | 
				
			
			@ -5291,6 +5345,7 @@ int stmmac_suspend(struct device *dev)
 | 
			
		|||
	struct net_device *ndev = dev_get_drvdata(dev);
 | 
			
		||||
	struct stmmac_priv *priv = netdev_priv(ndev);
 | 
			
		||||
	u32 chan;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!ndev || !netif_running(ndev))
 | 
			
		||||
		return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -5334,8 +5389,9 @@ int stmmac_suspend(struct device *dev)
 | 
			
		|||
		pinctrl_pm_select_sleep_state(priv->device);
 | 
			
		||||
		/* Disable clock in case of PWM is off */
 | 
			
		||||
		clk_disable_unprepare(priv->plat->clk_ptp_ref);
 | 
			
		||||
		clk_disable_unprepare(priv->plat->pclk);
 | 
			
		||||
		clk_disable_unprepare(priv->plat->stmmac_clk);
 | 
			
		||||
		ret = pm_runtime_force_suspend(dev);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&priv->lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5401,8 +5457,9 @@ int stmmac_resume(struct device *dev)
 | 
			
		|||
	} else {
 | 
			
		||||
		pinctrl_pm_select_default_state(priv->device);
 | 
			
		||||
		/* enable the clk previously disabled */
 | 
			
		||||
		clk_prepare_enable(priv->plat->stmmac_clk);
 | 
			
		||||
		clk_prepare_enable(priv->plat->pclk);
 | 
			
		||||
		ret = pm_runtime_force_resume(dev);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
		if (priv->plat->clk_ptp_ref)
 | 
			
		||||
			clk_prepare_enable(priv->plat->clk_ptp_ref);
 | 
			
		||||
		/* reset the phy so that it's ready */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
#include <linux/iopoll.h>
 | 
			
		||||
#include <linux/mii.h>
 | 
			
		||||
#include <linux/of_mdio.h>
 | 
			
		||||
#include <linux/pm_runtime.h>
 | 
			
		||||
#include <linux/phy.h>
 | 
			
		||||
#include <linux/property.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -87,21 +88,29 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 | 
			
		|||
	u32 tmp, addr, value = MII_XGMAC_BUSY;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (phyreg & MII_ADDR_C45) {
 | 
			
		||||
		phyreg &= ~MII_ADDR_C45;
 | 
			
		||||
 | 
			
		||||
		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto err_disable_clks;
 | 
			
		||||
	} else {
 | 
			
		||||
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto err_disable_clks;
 | 
			
		||||
 | 
			
		||||
		value |= MII_XGMAC_SADDR;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -112,8 +121,10 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 | 
			
		|||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set the MII address register to read */
 | 
			
		||||
	writel(addr, priv->ioaddr + mii_address);
 | 
			
		||||
| 
						 | 
				
			
			@ -121,11 +132,18 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 | 
			
		|||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Read the data from the MII data register */
 | 
			
		||||
	return readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
 | 
			
		||||
	ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
 | 
			
		||||
 | 
			
		||||
err_disable_clks:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
 | 
			
		||||
| 
						 | 
				
			
			@ -138,21 +156,29 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
 | 
			
		|||
	u32 addr, tmp, value = MII_XGMAC_BUSY;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (phyreg & MII_ADDR_C45) {
 | 
			
		||||
		phyreg &= ~MII_ADDR_C45;
 | 
			
		||||
 | 
			
		||||
		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto err_disable_clks;
 | 
			
		||||
	} else {
 | 
			
		||||
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
			goto err_disable_clks;
 | 
			
		||||
 | 
			
		||||
		value |= MII_XGMAC_SADDR;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -164,16 +190,23 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
 | 
			
		|||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set the MII address register to write */
 | 
			
		||||
	writel(addr, priv->ioaddr + mii_address);
 | 
			
		||||
	writel(value, priv->ioaddr + mii_data);
 | 
			
		||||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	return readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
	ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
 | 
			
		||||
				 !(tmp & MII_XGMAC_BUSY), 100, 10000);
 | 
			
		||||
 | 
			
		||||
err_disable_clks:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +229,12 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 | 
			
		|||
	int data = 0;
 | 
			
		||||
	u32 v;
 | 
			
		||||
 | 
			
		||||
	data = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (data < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value |= (phyaddr << priv->hw->mii.addr_shift)
 | 
			
		||||
		& priv->hw->mii.addr_mask;
 | 
			
		||||
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,19 +255,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
 | 
			
		||||
			       100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       100, 10000)) {
 | 
			
		||||
		data = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(data, priv->ioaddr + mii_data);
 | 
			
		||||
	writel(value, priv->ioaddr + mii_address);
 | 
			
		||||
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
 | 
			
		||||
			       100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       100, 10000)) {
 | 
			
		||||
		data = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Read the data from the MII data register */
 | 
			
		||||
	data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
 | 
			
		||||
 | 
			
		||||
err_disable_clks:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -247,10 +293,16 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
 | 
			
		|||
	struct stmmac_priv *priv = netdev_priv(ndev);
 | 
			
		||||
	unsigned int mii_address = priv->hw->mii.addr;
 | 
			
		||||
	unsigned int mii_data = priv->hw->mii.data;
 | 
			
		||||
	int ret, data = phydata;
 | 
			
		||||
	u32 value = MII_BUSY;
 | 
			
		||||
	int data = phydata;
 | 
			
		||||
	u32 v;
 | 
			
		||||
 | 
			
		||||
	ret = pm_runtime_get_sync(priv->device);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		pm_runtime_put_noidle(priv->device);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value |= (phyaddr << priv->hw->mii.addr_shift)
 | 
			
		||||
		& priv->hw->mii.addr_mask;
 | 
			
		||||
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
 | 
			
		||||
| 
						 | 
				
			
			@ -275,16 +327,23 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
 | 
			
		|||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
 | 
			
		||||
			       100, 10000))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
			       100, 10000)) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto err_disable_clks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set the MII address register to write */
 | 
			
		||||
	writel(data, priv->ioaddr + mii_data);
 | 
			
		||||
	writel(value, priv->ioaddr + mii_address);
 | 
			
		||||
 | 
			
		||||
	/* Wait until any existing MII operation is complete */
 | 
			
		||||
	return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
 | 
			
		||||
	ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
 | 
			
		||||
				 100, 10000);
 | 
			
		||||
 | 
			
		||||
err_disable_clks:
 | 
			
		||||
	pm_runtime_put(priv->device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -744,10 +744,30 @@ static int stmmac_pltfr_resume(struct device *dev)
 | 
			
		|||
 | 
			
		||||
	return stmmac_resume(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int stmmac_runtime_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *ndev = dev_get_drvdata(dev);
 | 
			
		||||
	struct stmmac_priv *priv = netdev_priv(ndev);
 | 
			
		||||
 | 
			
		||||
	stmmac_bus_clks_config(priv, false);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int stmmac_runtime_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *ndev = dev_get_drvdata(dev);
 | 
			
		||||
	struct stmmac_priv *priv = netdev_priv(ndev);
 | 
			
		||||
 | 
			
		||||
	return stmmac_bus_clks_config(priv, true);
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_PM_SLEEP */
 | 
			
		||||
 | 
			
		||||
SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
 | 
			
		||||
				       stmmac_pltfr_resume);
 | 
			
		||||
const struct dev_pm_ops stmmac_pltfr_pm_ops = {
 | 
			
		||||
	SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume)
 | 
			
		||||
	SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL)
 | 
			
		||||
};
 | 
			
		||||
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue