Skip to content

Commit

Permalink
net: stmmac: add clocks management for gmac driver
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Joakim Zhang <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Joakim Zhang authored and davem330 committed Mar 15, 2021
1 parent 91de5ac commit 5ec5582
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 37 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/stmicro/stmmac/stmmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
75 changes: 66 additions & 9 deletions drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -3070,6 +3101,8 @@ static int stmmac_release(struct net_device *dev)

stmmac_release_ptp(priv);

pm_runtime_put(priv->device);

return 0;
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 5ec5582

Please sign in to comment.