@@ -113,6 +113,27 @@ static void stmmac_exit_fs(struct net_device *dev);
#define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC))
+static int stmmac_bus_clks_enable(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;
+}
+
/**
* stmmac_verify_args - verify the driver parameters.
* Description: it checks the driver parameters and set a default in case of
@@ -2800,6 +2821,10 @@ static int stmmac_open(struct net_device *dev)
u32 chan;
int ret;
+ ret = stmmac_bus_clks_enable(priv, true);
+ if (ret)
+ return ret;
+
if (priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI &&
priv->hw->xpcs == NULL) {
@@ -2808,7 +2833,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 clk_enable_error;
}
}
@@ -2924,6 +2949,8 @@ static int stmmac_open(struct net_device *dev)
free_dma_desc_resources(priv);
dma_desc_error:
phylink_disconnect_phy(priv->phylink);
+clk_enable_error:
+ stmmac_bus_clks_enable(priv, false);
return ret;
}
@@ -2974,6 +3001,8 @@ static int stmmac_release(struct net_device *dev)
stmmac_release_ptp(priv);
+ stmmac_bus_clks_enable(priv, false);
+
return 0;
}
@@ -4624,6 +4653,10 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
bool is_double = false;
int ret;
+ ret = stmmac_bus_clks_enable(priv, true);
+ if (ret)
+ return ret;
+
if (be16_to_cpu(proto) == ETH_P_8021AD)
is_double = true;
@@ -4632,10 +4665,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 clk_enable_error;
}
- return stmmac_vlan_update(priv, is_double);
+ ret = stmmac_vlan_update(priv, is_double);
+
+clk_enable_error:
+ stmmac_bus_clks_enable(priv, false);
+
+ return ret;
}
static const struct net_device_ops stmmac_netdev_ops = {
@@ -5111,6 +5149,8 @@ int stmmac_dvr_probe(struct device *device,
stmmac_init_fs(ndev);
#endif
+ stmmac_bus_clks_enable(priv, false);
+
return ret;
error_serdes_powerup:
@@ -5125,6 +5165,7 @@ int stmmac_dvr_probe(struct device *device,
stmmac_napi_del(ndev);
error_hw_init:
destroy_workqueue(priv->wq);
+ stmmac_bus_clks_enable(priv, false);
return ret;
}
@@ -5140,6 +5181,7 @@ int stmmac_dvr_remove(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ bool netif_status = netif_running(ndev);
netdev_info(priv->dev, "%s: removing driver", __func__);
@@ -5157,8 +5199,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);
+ if (netif_status)
+ stmmac_bus_clks_enable(priv, false);
if (priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI)
stmmac_mdio_unregister(ndev);
@@ -5224,8 +5266,7 @@ 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);
+ stmmac_bus_clks_enable(priv, false);
}
mutex_unlock(&priv->lock);
@@ -5289,8 +5330,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 = stmmac_bus_clks_enable(priv, true);
+ 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 */
This patch intends to add clocks management for stmmac driver: 1. Keep clocks disabled after probe stage. 2. Enable clocks when up the net device, and disable clocks when down the net device. 3. If the driver is built as module, it also keeps clocks disabled when the module is removed. Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com> --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-)