diff mbox series

[RFC,1/2] clk: ti: add a usecount for autoidle

Message ID 20181004055147.23048-2-andreas@kemnade.info (mailing list archive)
State New, archived
Headers show
Series mach-omap2: handle autoidle denial | expand

Commit Message

Andreas Kemnade Oct. 4, 2018, 5:51 a.m. UTC
We have the scenario that first autoidle is disabled for all clocks,
then it is disabled for selected ones and then enabled for all. So
we should have some counting here, also according to the
comment in  _setup_iclk_autoidle()

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
 drivers/clk/ti/autoidle.c | 20 ++++++++++++--------
 include/linux/clk/ti.h    |  1 +
 2 files changed, 13 insertions(+), 8 deletions(-)

Comments

Tero Kristo Oct. 4, 2018, 2:40 p.m. UTC | #1
On 04/10/18 08:51, Andreas Kemnade wrote:
> We have the scenario that first autoidle is disabled for all clocks,
> then it is disabled for selected ones and then enabled for all. So
> we should have some counting here, also according to the
> comment in  _setup_iclk_autoidle()
> 
> Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
> ---
>   drivers/clk/ti/autoidle.c | 20 ++++++++++++--------
>   include/linux/clk/ti.h    |  1 +
>   2 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
> index 7bb9afbe4058..be2ce42e4f33 100644
> --- a/drivers/clk/ti/autoidle.c
> +++ b/drivers/clk/ti/autoidle.c
> @@ -48,8 +48,11 @@ int omap2_clk_deny_idle(struct clk *clk)
>   	struct clk_hw_omap *c;
>   
>   	c = to_clk_hw_omap(__clk_get_hw(clk));
> -	if (c->ops && c->ops->deny_idle)
> -		c->ops->deny_idle(c);
> +	if (c->ops && c->ops->deny_idle) {
> +		c->autoidle_count--;
> +		if (c->autoidle_count == -1)
> +			c->ops->deny_idle(c);

This code is racy as you have no locking in place. Please fix.

Also, this should be verified that it doesn't cause any PM regressions, 
I hope you have done that?

-Tero

> +	}
>   	return 0;
>   }
>   
> @@ -64,8 +67,11 @@ int omap2_clk_allow_idle(struct clk *clk)
>   	struct clk_hw_omap *c;
>   
>   	c = to_clk_hw_omap(__clk_get_hw(clk));
> -	if (c->ops && c->ops->allow_idle)
> -		c->ops->allow_idle(c);
> +	if (c->ops && c->ops->allow_idle) {
> +		c->autoidle_count++;
> +		if (c->autoidle_count == 0)
> +			c->ops->allow_idle(c);
> +	}
>   	return 0;
>   }
>   
> @@ -201,8 +207,7 @@ int omap2_clk_enable_autoidle_all(void)
>   	struct clk_hw_omap *c;
>   
>   	list_for_each_entry(c, &clk_hw_omap_clocks, node)
> -		if (c->ops && c->ops->allow_idle)
> -			c->ops->allow_idle(c);
> +		omap2_clk_allow_idle(c->hw.clk);
>   
>   	_clk_generic_allow_autoidle_all();
>   
> @@ -223,8 +228,7 @@ int omap2_clk_disable_autoidle_all(void)
>   	struct clk_hw_omap *c;
>   
>   	list_for_each_entry(c, &clk_hw_omap_clocks, node)
> -		if (c->ops && c->ops->deny_idle)
> -			c->ops->deny_idle(c);
> +		omap2_clk_deny_idle(c->hw.clk);
>   
>   	_clk_generic_deny_autoidle_all();
>   
> diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
> index a8faa38b1ed6..c460355419c0 100644
> --- a/include/linux/clk/ti.h
> +++ b/include/linux/clk/ti.h
> @@ -159,6 +159,7 @@ struct clk_hw_omap {
>   	const char		*clkdm_name;
>   	struct clockdomain	*clkdm;
>   	const struct clk_hw_omap_ops	*ops;
> +	int autoidle_count;
>   };
>   
>   /*
> 

--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
Andreas Kemnade Oct. 4, 2018, 7:34 p.m. UTC | #2
Hi,

On Thu, 4 Oct 2018 17:40:06 +0300
Tero Kristo <t-kristo@ti.com> wrote:

> On 04/10/18 08:51, Andreas Kemnade wrote:
> > We have the scenario that first autoidle is disabled for all clocks,
> > then it is disabled for selected ones and then enabled for all. So
> > we should have some counting here, also according to the
> > comment in  _setup_iclk_autoidle()
> > 
> > Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
> > ---
> >   drivers/clk/ti/autoidle.c | 20 ++++++++++++--------
> >   include/linux/clk/ti.h    |  1 +
> >   2 files changed, 13 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
> > index 7bb9afbe4058..be2ce42e4f33 100644
> > --- a/drivers/clk/ti/autoidle.c
> > +++ b/drivers/clk/ti/autoidle.c
> > @@ -48,8 +48,11 @@ int omap2_clk_deny_idle(struct clk *clk)
> >   	struct clk_hw_omap *c;
> >   
> >   	c = to_clk_hw_omap(__clk_get_hw(clk));
> > -	if (c->ops && c->ops->deny_idle)
> > -		c->ops->deny_idle(c);
> > +	if (c->ops && c->ops->deny_idle) {
> > +		c->autoidle_count--;
> > +		if (c->autoidle_count == -1)
> > +			c->ops->deny_idle(c);  
> 
> This code is racy as you have no locking in place. Please fix.
> 

hmm, yes, it is. Due to low risk (things are only called from init
before the drivers are initialized, if I understand that correctly). I
kept that for final polishing and not for a rfc patch.
The deny_idle/allow_idle are also racy themselves. Multiple clocks with
bits in the same register changed at the same time would also create a
mess.

> Also, this should be verified that it doesn't cause any PM regressions, 
> I hope you have done that?
> 
Tested things: I checked various autoidle registers for changes.
I checked registers by reading out /dev/mem
Seen changes: hdq iclk no autoidle (that is the goal of all this)
dss iclk no autoidle. This one is really interesting: There are
multiple users of dss_ick, so that is a special case. I will check
whether I can handle that (I have already an idea) or just delete that
flag there for sorting out that later, we could somehow live with not
disabled autoidle flag there but needed some strange fixes in the past.
Now dss_ick does unecessarily enabled, so yes, a little regression.

CORE/PER idlest seems to behave as well as before that change.

Regards,
Andreas
diff mbox series

Patch

diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
index 7bb9afbe4058..be2ce42e4f33 100644
--- a/drivers/clk/ti/autoidle.c
+++ b/drivers/clk/ti/autoidle.c
@@ -48,8 +48,11 @@  int omap2_clk_deny_idle(struct clk *clk)
 	struct clk_hw_omap *c;
 
 	c = to_clk_hw_omap(__clk_get_hw(clk));
-	if (c->ops && c->ops->deny_idle)
-		c->ops->deny_idle(c);
+	if (c->ops && c->ops->deny_idle) {
+		c->autoidle_count--;
+		if (c->autoidle_count == -1)
+			c->ops->deny_idle(c);
+	}
 	return 0;
 }
 
@@ -64,8 +67,11 @@  int omap2_clk_allow_idle(struct clk *clk)
 	struct clk_hw_omap *c;
 
 	c = to_clk_hw_omap(__clk_get_hw(clk));
-	if (c->ops && c->ops->allow_idle)
-		c->ops->allow_idle(c);
+	if (c->ops && c->ops->allow_idle) {
+		c->autoidle_count++;
+		if (c->autoidle_count == 0)
+			c->ops->allow_idle(c);
+	}
 	return 0;
 }
 
@@ -201,8 +207,7 @@  int omap2_clk_enable_autoidle_all(void)
 	struct clk_hw_omap *c;
 
 	list_for_each_entry(c, &clk_hw_omap_clocks, node)
-		if (c->ops && c->ops->allow_idle)
-			c->ops->allow_idle(c);
+		omap2_clk_allow_idle(c->hw.clk);
 
 	_clk_generic_allow_autoidle_all();
 
@@ -223,8 +228,7 @@  int omap2_clk_disable_autoidle_all(void)
 	struct clk_hw_omap *c;
 
 	list_for_each_entry(c, &clk_hw_omap_clocks, node)
-		if (c->ops && c->ops->deny_idle)
-			c->ops->deny_idle(c);
+		omap2_clk_deny_idle(c->hw.clk);
 
 	_clk_generic_deny_autoidle_all();
 
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index a8faa38b1ed6..c460355419c0 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -159,6 +159,7 @@  struct clk_hw_omap {
 	const char		*clkdm_name;
 	struct clockdomain	*clkdm;
 	const struct clk_hw_omap_ops	*ops;
+	int autoidle_count;
 };
 
 /*