linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Heiko Stübner" <heiko@sntech.de>
To: Stephen Boyd <sboyd@codeaurora.org>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>,
	Pavel Machek <pavel@ucw.cz>
Cc: mturquette@baylibre.com, linux-clk@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org
Subject: Re: [PATCH] clk: readd refcounting for struct clk instances [when used in pm_clk_add_clk(), genpd]
Date: Wed, 16 Sep 2015 11:18:05 +0200	[thread overview]
Message-ID: <9158634.8HmHM8CzF6@diego> (raw)
In-Reply-To: <20150916003931.GK23081@codeaurora.org>

Hi Stephen,

Am Dienstag, 15. September 2015, 17:39:31 schrieb Stephen Boyd:
> On 09/15, Heiko Stübner wrote:
> > With the split into struct clk and struct clk_core, clocks lost the
> > ability for nested __clk_get clkdev calls. While it stays possible to
> > call __clk_get, the first call to (__)clk_put will clear the struct clk,
> > making subsequent clk_put calls run into a NULL pointer dereference.
> > 
> > One prime example of this sits in the generic power domain code, where it
> > is possible to add the clocks both by name and by passing in a struct clk
> > via pm_clk_add_clk(). __pm_clk_add() in turn then calls __clk_get to
> > increase the refcount, so that the original code can put the clock again.
> > 
> > A possible call-path looks like
> > clk = of_clk_get();
> > pm_clk_add_clk(dev, clk);
> > clk_put(clk);
> > 
> > with pm_clk_add_clk() => __pm_clk_add() then calling __clk_get on the clk
> > and later clk_put when the pm clock list gets destroyed, thus creating
> > a NULL pointer deref, as the struct clk doesn't exist anymore.
> > 
> > So add a separate refcounting for struct clk instances and only clean up
> > once the refcount reaches zero.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > I stumbled upon this while applying the new Rockchip power-domain driver,
> > but I guess the underlying issue is universal and probably present since
> > the original clk/clk_core split, so this probably counts as fix.
> 
> Ok. The fix makes sense, but I wonder why we do this. Perhaps we
> should stop exporting __clk_get() and __clk_put() to everything
> that uses clkdev in the kernel. They're called per-user clks for
> a reason. There's one user. Now we have two users of the same
> struct clk instance, so we have to refcount it too? I hope the
> shared clk instance isn't being used to set rates in two pieces
> of code.
> 
> And this only affects pm_clk_add_clk() callers right? So the only
> caller in the kernel (drivers/clk/shmobile/clk-mstp.c) doesn't
> seem to have this problem right now because it never calls
> clk_put() on the pointer it passes to pm_clk_add_clk().

As written above, I stumbled upon this with the new Rockchip power-domain 
driver [0] which calls pm_clk_add_clk in its rockchip_pd_attach_dev() function


[0] http://www.spinics.net/lists/kernel/msg2070432.html

> So what if we did the patch below? This would rely on callers not
> calling clk_put() before calling pm_clk_remove() or
> pm_clk_destroy(), and the life cycle would be clear, but the
> sharing is still there. Or we could say that after a clk is given
> to pm_clk_add_clk() that the caller shouldn't touch it anymore,
> like shmobile is doing right now. Then there's nothing to do
> besides remove the extra __clk_get() call in the pm layer.

I guess that is the call of the genpd people (Rafael and Pavel according to 
get_maintainers.pl). I'm very much fine with adapting the Rockchip power-
domain driver as needed to new handling paradigms.

Personally I'd prefer your solution of making the initial handler do all the 
getting and putting, as doing clk_get in the power-domain driver and relying 
on clk_put being done in the genpd core feels awkward. Although that solution 
would mean, the calling driver would also need to keep track of clocks, while 
the current rockchip power-domain driver can just call clk_put after handing 
the clock of to genpd.


> 
> > @@ -2606,6 +2607,18 @@ static void __clk_release(struct kref *ref)
> > 
> >  	kfree(core);
> >  
> >  }
> > 
> > +static void __clk_release(struct kref *ref)
> > +{
> > +	struct clk *clk = container_of(ref, struct clk, ref);
> > +
> > +	hlist_del(&clk->clks_node);
> > +	if ((clk->min_rate > clk->core->req_rate ||
> > +	     clk->max_rate < clk->core->req_rate))
> 
> Why did we grow a pair of parenthesis?

Remnant of me moving code around, sorry about that.
As it seems you prefer a different solution, I'll refrain from sending a fixed 
version, till we decide which way to go :-).


> 
> > +		clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
> > +
> > +	kfree(clk);
> > +}
> > +
> > 
> >  /*
> >  
> >   * Empty clk_ops for unregistered clocks. These are used temporarily
> >   * after clk_unregister() was called on a clock and until last clock
> 
> diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
> index 652b5a367c1f..ef62bb3d7b26 100644
> --- a/drivers/base/power/clock_ops.c
> +++ b/drivers/base/power/clock_ops.c
> @@ -31,6 +31,7 @@ struct pm_clock_entry {
>  	char *con_id;
>  	struct clk *clk;
>  	enum pce_status status;
> +	bool needs_clk_put;
>  };
> 
>  /**
> @@ -59,8 +60,10 @@ static inline void __pm_clk_enable(struct device *dev,
> struct pm_clock_entry *ce */
>  static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
>  {
> -	if (!ce->clk)
> +	if (!ce->clk) {
>  		ce->clk = clk_get(dev, ce->con_id);
> +		ce->needs_clk_put = true;
> +	}
>  	if (IS_ERR(ce->clk)) {
>  		ce->status = PCE_STATUS_ERROR;
>  	} else {
> @@ -93,7 +96,7 @@ static int __pm_clk_add(struct device *dev, const char
> *con_id, return -ENOMEM;
>  		}
>  	} else {
> -		if (IS_ERR(clk) || !__clk_get(clk)) {
> +		if (IS_ERR(clk)) {
>  			kfree(ce);
>  			return -ENOENT;
>  		}
> @@ -149,7 +152,8 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
> 
>  		if (ce->status >= PCE_STATUS_ACQUIRED) {
>  			clk_unprepare(ce->clk);
> -			clk_put(ce->clk);
> +			if (ce->needs_clk_put)
> +				clk_put(ce->clk);
>  		}
>  	}

  reply	other threads:[~2015-09-16  9:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-15 14:50 [PATCH] clk: readd refcounting for struct clk instances Heiko Stübner
2015-09-16  0:39 ` Stephen Boyd
2015-09-16  9:18   ` Heiko Stübner [this message]
2015-09-20 12:38     ` [PATCH] clk: readd refcounting for struct clk instances [when used in pm_clk_add_clk(), genpd] Heiko Stübner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9158634.8HmHM8CzF6@diego \
    --to=heiko@sntech.de \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=pavel@ucw.cz \
    --cc=rjw@rjwysocki.net \
    --cc=sboyd@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).