diff mbox

[3/6] stmmac: Add support for CPU freq notifiers.

Message ID 1330692928-30330-4-git-send-email-deepak.sikri@st.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Deepak Sikri March 2, 2012, 12:55 p.m. UTC
This patch adds in the support for CPU freq notifiers. In case the system freq
is changed using the CPU freq governors, the CSR input clock is also affected.

To maintain the CSR mdio clock within the limits of 1-2.5 Mhz the input clock
has to be properly scaled using the appropriate scaling factors.
This patch looks into the input clock frequency changes and selects the apt
scaling factor once a notifier alert is received.
Additionally the stmmac clock has been defined to support cpu freq notifiers.

Signed-off-by: Deepak Sikri <deepak.sikri@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |   10 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  124 ++++++++++++++++++++-
 2 files changed, 130 insertions(+), 4 deletions(-)

Comments

David Miller March 5, 2012, 1:50 a.m. UTC | #1
From: Deepak Sikri <deepak.sikri@st.com>
Date: Fri, 2 Mar 2012 18:25:25 +0530

> +{
> +
> +	if ((clk_rate >= CSR_F_20M) && (clk_rate < CSR_F_35M))
 ...
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
> +
> +}

Unnecessary empty lines, remove them.

> +			/*
> +			 * Decide on the MDC clock dynamically based on the
> +			 * csr clock input.

Format comments:

	/* Like
	 * this.
	 */

Not:

	/*
	 * Like
	 * this.
	 */

> +static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
> +{
> +
> +	cpufreq_unregister_notifier(&priv->freq_transition,

Unnecessary empty line.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Giuseppe CAVALLARO March 5, 2012, 3:05 p.m. UTC | #2
On 3/2/2012 1:55 PM, Deepak Sikri wrote:
> This patch adds in the support for CPU freq notifiers. In case the system freq
> is changed using the CPU freq governors, the CSR input clock is also affected.
> 
> To maintain the CSR mdio clock within the limits of 1-2.5 Mhz the input clock
> has to be properly scaled using the appropriate scaling factors.
> This patch looks into the input clock frequency changes and selects the apt
> scaling factor once a notifier alert is received.
> Additionally the stmmac clock has been defined to support cpu freq notifiers.

Hello Deepak

this patch doesn't apply on net.git.

Concerning the stmmac_clk_csr_set it should treat all the other divisor
values as I've just told you in the email #2.

All the defines from the patch #2:

+/* CSR Frequency Access Defines*/
+#define CSR_F_20M	20000000
+#define CSR_F_35M	35000000
+#define CSR_F_60M	60000000
+#define CSR_F_100M	100000000
+#define CSR_F_150M	150000000
+#define CSR_F_250M	50000000
+#define CSR_F_300M	300000000


should be moved from linux/stmmac.h to stmicro/stmmac/common.h

In the end, I kindly ask you to try to remove some of not necessary
#ifdef CONFIG_HAVE_CLK  inside the C file.

Indeed stmmac_clk is be null in case of there is not this support.

Also I wonder if stmmac_clk could be renamed as: stmmac_csr_clk.

Pls, resend the patch against net-git so i'll be happy to continue the
review ;-)

Peppe

> 
> Signed-off-by: Deepak Sikri <deepak.sikri@st.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac.h      |   10 ++
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  124 ++++++++++++++++++++-
>  2 files changed, 130 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 1207400..67b9757 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -22,6 +22,10 @@
>  
>  #define STMMAC_RESOURCE_NAME   "stmmaceth"
>  #define DRV_MODULE_VERSION	"Dec_2011"
> +
> +#ifdef CONFIG_HAVE_CLK
> +#include <linux/clk.h>
> +#endif
>  #include <linux/stmmac.h>
>  #include <linux/phy.h>
>  #include "common.h"
> @@ -81,6 +85,12 @@ struct stmmac_priv {
>  	struct stmmac_counters mmc;
>  	struct dma_features dma_cap;
>  	int hw_cap_support;
> +#ifdef CONFIG_CPU_FREQ
> +	struct notifier_block freq_transition;
> +#endif
> +#ifdef CONFIG_HAVE_CLK
> +	struct clk *stmmac_clk;
> +#endif
>  };
>  
>  extern int phyaddr;
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 96fa2da..001b8f3 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -35,6 +35,7 @@
>  #include <linux/skbuff.h>
>  #include <linux/ethtool.h>
>  #include <linux/if_ether.h>
> +#include <linux/cpufreq.h>
>  #include <linux/crc32.h>
>  #include <linux/mii.h>
>  #include <linux/if.h>
> @@ -180,6 +181,92 @@ static void print_pkt(unsigned char *buf, int len)
>  /* minimum number of free TX descriptors required to wake up TX process */
>  #define STMMAC_TX_THRESH(x)	(x->dma_tx_size/4)
>  
> +#ifdef CONFIG_CPU_FREQ
> +static inline void stmmac_clk_csr_set(struct stmmac_priv *priv, int clk_rate)
> +{
> +
> +	if ((clk_rate >= CSR_F_20M) && (clk_rate < CSR_F_35M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_20_35M;
> +	else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_35_60M;
> +	else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_60_100M;
> +	else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_100_150M;
> +	else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
> +	else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_250_300M;
> +	else
> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
> +
> +}
> +
> +static int stmmac_cpufreq_transition(struct notifier_block *nb,
> +		unsigned long val, void *data)
> +{
> +	struct stmmac_priv *priv;
> +	u32 clk_rate;
> +
> +	priv = container_of(nb, struct stmmac_priv, freq_transition);
> +
> +	if (val == CPUFREQ_PRECHANGE) {
> +		/* Stop TX/RX DMA */
> +		priv->hw->dma->stop_tx(priv->ioaddr);
> +		priv->hw->dma->stop_rx(priv->ioaddr);
> +
> +	} else if (val == CPUFREQ_POSTCHANGE) {
> +		/* Start DMA Tx/Rx */
> +		priv->hw->dma->start_tx(priv->ioaddr);
> +		priv->hw->dma->start_rx(priv->ioaddr);
> +		priv->hw->dma->enable_dma_transmission(priv->ioaddr);
> +
> +		if (priv->stmmac_clk) {
> +			/*
> +			 * Decide on the MDC clock dynamically based on the
> +			 * csr clock input.
> +			 * This is helpfull in case the cpu frequency is changed
> +			 * on the run using the cpu freq framework, and based
> +			 * on that the bus frequency is also changed.
> +			 * In case the clock framework is not established for an
> +			 * architecture, use the default value that has to be
> +			 * set through the platform.
> +			 */
> +			clk_rate = clk_get_rate(priv->stmmac_clk);
> +			stmmac_clk_csr_set(priv, clk_rate);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static inline void stmmac_cpufreq_register(struct stmmac_priv *priv)
> +{
> +	priv->freq_transition.notifier_call = stmmac_cpufreq_transition;
> +	cpufreq_register_notifier(&priv->freq_transition,
> +			CPUFREQ_TRANSITION_NOTIFIER);
> +}
> +
> +static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
> +{
> +
> +	cpufreq_unregister_notifier(&priv->freq_transition,
> +			CPUFREQ_TRANSITION_NOTIFIER);
> +}
> +
> +#else
> +
> +static inline void stmmac_cpufreq_register(struct stmmac_priv *priv)
> +{
> +	return 0;
> +}
> +
> +static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
> +{
> +}
> +
> +#endif
> +
>  static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
>  {
>  	return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
> @@ -930,10 +1017,14 @@ static int stmmac_open(struct net_device *dev)
>  	struct stmmac_priv *priv = netdev_priv(dev);
>  	int ret;
>  
> +#ifdef CONFIG_HAVE_CLK
> +	if (priv->stmmac_clk)
> +		clk_enable(priv->stmmac_clk);
> +#endif
>  	/* MAC HW device setup */
>  	ret = stmmac_mac_device_setup(dev);
>  	if (ret < 0)
> -		return ret;
> +		goto open_clk_dis;
>  
>  	stmmac_check_ether_addr(priv);
>  
> @@ -949,14 +1040,15 @@ static int stmmac_open(struct net_device *dev)
>  	if (ret < 0) {
>  		pr_debug("%s: MDIO bus (id: %d) registration failed",
>  			 __func__, priv->plat->bus_id);
> -		return ret;
> +		goto open_clk_dis;
>  	}
>  
>  #ifdef CONFIG_STMMAC_TIMER
>  	priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
>  	if (unlikely(priv->tm == NULL)) {
>  		pr_err("%s: ERROR: timer memory alloc failed\n", __func__);
> -		return -ENOMEM;
> +		ret = -ENOMEM;
> +		goto open_clk_dis;
>  	}
>  	priv->tm->freq = tmrate;
>  
> @@ -1093,7 +1185,11 @@ open_error:
>  #endif
>  	if (priv->phydev)
>  		phy_disconnect(priv->phydev);
> -
> +open_clk_dis:
> +#ifdef CONFIG_HAVE_CLK
> +	if (priv->stmmac_clk)
> +		clk_disable(priv->stmmac_clk);
> +#endif
>  	return ret;
>  }
>  
> @@ -1145,6 +1241,11 @@ static int stmmac_release(struct net_device *dev)
>  #endif
>  	stmmac_mdio_unregister(dev);
>  
> +#ifdef CONFIG_HAVE_CLK
> +	if (priv->stmmac_clk)
> +		clk_disable(priv->stmmac_clk);
> +#endif
> +
>  	return 0;
>  }
>  
> @@ -1844,6 +1945,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
>  		goto error;
>  	}
>  
> +#ifdef CONFIG_HAVE_CLK
> +	priv->stmmac_clk = clk_get(device, NULL);
> +	if (IS_ERR(priv->stmmac_clk)) {
> +		ret = PTR_ERR(priv->stmmac_clk);
> +		pr_err("%s: ERROR %i clock get \n", __func__, ret);
> +		goto error;
> +	}
> +#endif
> +	stmmac_cpufreq_register(priv);
> +
>  	DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n",
>  	    ndev->name, (ndev->features & NETIF_F_SG) ? "on" : "off",
>  	    (ndev->features & NETIF_F_IP_CSUM) ? "on" : "off");
> @@ -1875,6 +1986,11 @@ int stmmac_dvr_remove(struct net_device *ndev)
>  	priv->hw->dma->stop_tx(priv->ioaddr);
>  
>  	stmmac_set_mac(priv->ioaddr, false);
> +	stmmac_cpufreq_deregister(priv);
> +#ifdef CONFIG_HAVE_CLK
> +	if (priv->stmmac_clk)
> +		clk_put(priv->stmmac_clk);
> +#endif
>  	netif_carrier_off(ndev);
>  	unregister_netdev(ndev);
>  	free_netdev(ndev);

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Giuseppe CAVALLARO March 6, 2012, 8:04 a.m. UTC | #3
On 3/5/2012 4:05 PM, Giuseppe CAVALLARO wrote:
[snip]
>> +#ifdef CONFIG_CPU_FREQ
>> +static inline void stmmac_clk_csr_set(struct stmmac_priv *priv, int clk_rate)
>> +{
>> +
>> +	if ((clk_rate >= CSR_F_20M) && (clk_rate < CSR_F_35M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_20_35M;
>> +	else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_35_60M;
>> +	else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_60_100M;
>> +	else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_100_150M;
>> +	else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
>> +	else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_250_300M;
>> +	else
>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;


Another note is that you are overriding the priv->plat->clk_csr that was
passed through the platform and used in some case on other architectures.

peppe
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepak Sikri March 7, 2012, 7:17 a.m. UTC | #4
Hello Peppe,

> Hello Deepak
>
> this patch doesn't apply on net.git.

I would rebase it again on net.git and send
>
> Concerning the stmmac_clk_csr_set it should treat all the other divisor
> values as I've just told you in the email #2.

I looked through the other divisor values also,. The input clock range 
coming through those divisors were
very much overlapping the 2.5 MHz range.

As I had requested to consider the 12.5 MHz MDIO clock provision as a 
separate patch, I would seek
some more discussions on this particular thing.

> All the defines from the patch #2:
>
> +/* CSR Frequency Access Defines*/
> +#define CSR_F_20M	20000000
> +#define CSR_F_35M	35000000
> +#define CSR_F_60M	60000000
> +#define CSR_F_100M	100000000
> +#define CSR_F_150M	150000000
> +#define CSR_F_250M	50000000
> +#define CSR_F_300M	300000000
>
>
> should be moved from linux/stmmac.h to stmicro/stmmac/common.h

ok

>
> In the end, I kindly ask you to try to remove some of not necessary
> #ifdef CONFIG_HAVE_CLK  inside the C file.
>
> Indeed stmmac_clk is be null in case of there is not this support.
>
> Also I wonder if stmmac_clk could be renamed as: stmmac_csr_clk.

Its only at one place that we will need the conditional macro, while we 
do clk_get. Rest of the
macros could be do away with.
I would also rename the stmmac_clk to stmmac_csr_clk.

>
> Pls, resend the patch against net-git so i'll be happy to continue the
> review ;-)
Sure


Regards
Deepak
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepak Sikri March 7, 2012, 7:18 a.m. UTC | #5
Hi David

+		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
+
+}

> Unnecessary empty lines, remove them.

ok

>> +			/*
>> +			 * Decide on the MDC clock dynamically based on the
>> +			 * csr clock input.
> Format comments:
>
> 	/* Like
> 	 * this.
> 	 */
>
> Not:
>
> 	/*
> 	 * Like
> 	 * this.
> 	 */

ok

>> +static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
>> +{
>> +
>> +	cpufreq_unregister_notifier(&priv->freq_transition,
> Unnecessary empty line.
>

Will remove.

Regards
Deepak
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepak Sikri March 7, 2012, 8:28 a.m. UTC | #6
Hi Peppe,

On 3/6/2012 1:34 PM, Giuseppe CAVALLARO wrote:
> On 3/5/2012 4:05 PM, Giuseppe CAVALLARO wrote:
> [snip]
>>> +	else
>>> +		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
>
> Another note is that you are overriding the priv->plat->clk_csr that was
> passed through the platform and used in some case on other architectures.
>
> peppe

I would cross verify and update the code.

Regards
Deepak

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 1207400..67b9757 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -22,6 +22,10 @@ 
 
 #define STMMAC_RESOURCE_NAME   "stmmaceth"
 #define DRV_MODULE_VERSION	"Dec_2011"
+
+#ifdef CONFIG_HAVE_CLK
+#include <linux/clk.h>
+#endif
 #include <linux/stmmac.h>
 #include <linux/phy.h>
 #include "common.h"
@@ -81,6 +85,12 @@  struct stmmac_priv {
 	struct stmmac_counters mmc;
 	struct dma_features dma_cap;
 	int hw_cap_support;
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block freq_transition;
+#endif
+#ifdef CONFIG_HAVE_CLK
+	struct clk *stmmac_clk;
+#endif
 };
 
 extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 96fa2da..001b8f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -35,6 +35,7 @@ 
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/if_ether.h>
+#include <linux/cpufreq.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/if.h>
@@ -180,6 +181,92 @@  static void print_pkt(unsigned char *buf, int len)
 /* minimum number of free TX descriptors required to wake up TX process */
 #define STMMAC_TX_THRESH(x)	(x->dma_tx_size/4)
 
+#ifdef CONFIG_CPU_FREQ
+static inline void stmmac_clk_csr_set(struct stmmac_priv *priv, int clk_rate)
+{
+
+	if ((clk_rate >= CSR_F_20M) && (clk_rate < CSR_F_35M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_20_35M;
+	else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_35_60M;
+	else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_60_100M;
+	else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_100_150M;
+	else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
+	else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_250_300M;
+	else
+		priv->plat->clk_csr = STMMAC_CLK_RANGE_150_250M;
+
+}
+
+static int stmmac_cpufreq_transition(struct notifier_block *nb,
+		unsigned long val, void *data)
+{
+	struct stmmac_priv *priv;
+	u32 clk_rate;
+
+	priv = container_of(nb, struct stmmac_priv, freq_transition);
+
+	if (val == CPUFREQ_PRECHANGE) {
+		/* Stop TX/RX DMA */
+		priv->hw->dma->stop_tx(priv->ioaddr);
+		priv->hw->dma->stop_rx(priv->ioaddr);
+
+	} else if (val == CPUFREQ_POSTCHANGE) {
+		/* Start DMA Tx/Rx */
+		priv->hw->dma->start_tx(priv->ioaddr);
+		priv->hw->dma->start_rx(priv->ioaddr);
+		priv->hw->dma->enable_dma_transmission(priv->ioaddr);
+
+		if (priv->stmmac_clk) {
+			/*
+			 * Decide on the MDC clock dynamically based on the
+			 * csr clock input.
+			 * This is helpfull in case the cpu frequency is changed
+			 * on the run using the cpu freq framework, and based
+			 * on that the bus frequency is also changed.
+			 * In case the clock framework is not established for an
+			 * architecture, use the default value that has to be
+			 * set through the platform.
+			 */
+			clk_rate = clk_get_rate(priv->stmmac_clk);
+			stmmac_clk_csr_set(priv, clk_rate);
+		}
+	}
+
+	return 0;
+}
+
+static inline void stmmac_cpufreq_register(struct stmmac_priv *priv)
+{
+	priv->freq_transition.notifier_call = stmmac_cpufreq_transition;
+	cpufreq_register_notifier(&priv->freq_transition,
+			CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
+{
+
+	cpufreq_unregister_notifier(&priv->freq_transition,
+			CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+
+static inline void stmmac_cpufreq_register(struct stmmac_priv *priv)
+{
+	return 0;
+}
+
+static inline void stmmac_cpufreq_deregister(struct stmmac_priv *priv)
+{
+}
+
+#endif
+
 static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
 {
 	return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
@@ -930,10 +1017,14 @@  static int stmmac_open(struct net_device *dev)
 	struct stmmac_priv *priv = netdev_priv(dev);
 	int ret;
 
+#ifdef CONFIG_HAVE_CLK
+	if (priv->stmmac_clk)
+		clk_enable(priv->stmmac_clk);
+#endif
 	/* MAC HW device setup */
 	ret = stmmac_mac_device_setup(dev);
 	if (ret < 0)
-		return ret;
+		goto open_clk_dis;
 
 	stmmac_check_ether_addr(priv);
 
@@ -949,14 +1040,15 @@  static int stmmac_open(struct net_device *dev)
 	if (ret < 0) {
 		pr_debug("%s: MDIO bus (id: %d) registration failed",
 			 __func__, priv->plat->bus_id);
-		return ret;
+		goto open_clk_dis;
 	}
 
 #ifdef CONFIG_STMMAC_TIMER
 	priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
 	if (unlikely(priv->tm == NULL)) {
 		pr_err("%s: ERROR: timer memory alloc failed\n", __func__);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto open_clk_dis;
 	}
 	priv->tm->freq = tmrate;
 
@@ -1093,7 +1185,11 @@  open_error:
 #endif
 	if (priv->phydev)
 		phy_disconnect(priv->phydev);
-
+open_clk_dis:
+#ifdef CONFIG_HAVE_CLK
+	if (priv->stmmac_clk)
+		clk_disable(priv->stmmac_clk);
+#endif
 	return ret;
 }
 
@@ -1145,6 +1241,11 @@  static int stmmac_release(struct net_device *dev)
 #endif
 	stmmac_mdio_unregister(dev);
 
+#ifdef CONFIG_HAVE_CLK
+	if (priv->stmmac_clk)
+		clk_disable(priv->stmmac_clk);
+#endif
+
 	return 0;
 }
 
@@ -1844,6 +1945,16 @@  struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 		goto error;
 	}
 
+#ifdef CONFIG_HAVE_CLK
+	priv->stmmac_clk = clk_get(device, NULL);
+	if (IS_ERR(priv->stmmac_clk)) {
+		ret = PTR_ERR(priv->stmmac_clk);
+		pr_err("%s: ERROR %i clock get \n", __func__, ret);
+		goto error;
+	}
+#endif
+	stmmac_cpufreq_register(priv);
+
 	DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n",
 	    ndev->name, (ndev->features & NETIF_F_SG) ? "on" : "off",
 	    (ndev->features & NETIF_F_IP_CSUM) ? "on" : "off");
@@ -1875,6 +1986,11 @@  int stmmac_dvr_remove(struct net_device *ndev)
 	priv->hw->dma->stop_tx(priv->ioaddr);
 
 	stmmac_set_mac(priv->ioaddr, false);
+	stmmac_cpufreq_deregister(priv);
+#ifdef CONFIG_HAVE_CLK
+	if (priv->stmmac_clk)
+		clk_put(priv->stmmac_clk);
+#endif
 	netif_carrier_off(ndev);
 	unregister_netdev(ndev);
 	free_netdev(ndev);