linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Stephen Boyd <sboyd@codeaurora.org>
To: Mike Turquette <mturquette@linaro.org>
Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, ccross@android.com
Subject: Re: [PATCH v2 4/4] clk: Use ww_mutexes for clk_prepare_{lock/unlock}
Date: Mon, 29 Sep 2014 17:12:05 -0700	[thread overview]
Message-ID: <5429F555.9030108@codeaurora.org> (raw)
In-Reply-To: <20140928024131.19023.40641@quantum>

On 09/27/14 19:41, Mike Turquette wrote:
> Quoting Stephen Boyd (2014-09-03 18:01:06)
>> @@ -1069,11 +1305,24 @@ static void __clk_recalc_accuracies(struct clk *clk)
>>   */
>>  long clk_get_accuracy(struct clk *clk)
>>  {
>> +       struct ww_acquire_ctx ctx;
>> +       LIST_HEAD(list);
>>         unsigned long accuracy;
>>  
>> -       clk_prepare_lock();
>> +       if (clk && !(clk->flags & CLK_GET_ACCURACY_NOCACHE)) {
>> +               ww_mutex_lock(&clk->lock, NULL);
>> +       } else {
>> +               ww_acquire_init(&ctx, &prepare_ww_class);
>> +               clk_lock_subtree(clk, &list, &ctx);
>> +               ww_acquire_done(&ctx);
>> +       }
> It looks a little weird to access clk->flags outside of the lock, but
> flags is immutable after registration-time, so I guess it is OK. Let me
> know if I'm wrong.

Right. We can ww_acquire_init() and ww_mutex_lock() with that context
before checking the flags. In the single lock case it's better to just
grab the mutex though, without the context, to avoid the whole deadlock
detection overhead that we don't care about.

>
>> +
>>         rate = __clk_get_rate(clk);
>> -       clk_prepare_unlock();
>> +
>> +       if (clk && !(clk->flags & CLK_GET_RATE_NOCACHE))
>> +               ww_mutex_unlock(&clk->lock);
>> +       else
>> +               clk_unlock(&list, &ctx);
>>  
>>         return rate;
>>  }
>> @@ -1317,9 +1579,11 @@ out:
>>         return ret;
>>  }
>>  
>> -static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
>> -                            struct clk *new_parent, u8 p_index)
>> +static int clk_calc_subtree(struct clk *clk, unsigned long new_rate,
>> +                            struct clk *new_parent, u8 p_index,
>> +                            struct list_head *list, struct ww_acquire_ctx *ctx)
>>  {
>> +       int ret;
>>         struct clk *child;
>>  
>>         clk->new_rate = new_rate;
>> @@ -1331,27 +1595,43 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
>>                 new_parent->new_child = clk;
>>  
>>         hlist_for_each_entry(child, &clk->children, child_node) {
>> +               ret = clk_lock_one(child, list, ctx);
>> +               if (ret == -EDEADLK)
>> +                       return ret;
> Why bother with any locking here at all? Why not call clk_lock_subtree
> from clk_calc_new_rates? I guess you avoid an extra tree walk?

Yes we save on the tree walk.

>
>> +
>>                 child->new_rate = clk_recalc(child, new_rate);
>> -               clk_calc_subtree(child, child->new_rate, NULL, 0);
>> +               ret = clk_calc_subtree(child, child->new_rate, NULL, 0, list,
>> +                                       ctx);
>> +               if (ret)
>> +                       return ret;
>>         }
>> +
>> +       return 0;
>>  }
>>  
>>  /*
>>   * calculate the new rates returning the topmost clock that has to be
>>   * changed.
>>   */
>> -static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
>> +static struct clk *
>> +clk_calc_new_rates(struct clk *clk, unsigned long rate, struct list_head *list,
>> +                  struct ww_acquire_ctx *ctx)
>>  {
>>         struct clk *top = clk;
>>         struct clk *old_parent, *parent;
>>         unsigned long best_parent_rate = 0;
>>         unsigned long new_rate;
>>         int p_index = 0;
>> +       int ret;
>>  
>>         /* sanity */
>>         if (IS_ERR_OR_NULL(clk))
>>                 return NULL;
>>  
>> +       ret = clk_lock_one(clk, list, ctx);
>> +       if (ret == -EDEADLK)
>> +               return ERR_PTR(ret);
> It seems to me that we should call clk_parent_lock here instead, since
> we access the parent's rate. I know that any concurrent access to the
> parent which would change its rate would fail, since we can't lock the
> subtree (including *this* lock). But it still seems more correct to lock
> the parent to me. Let me know what you think.

Blocking the other user of the parent is bad. In our CPU case we have XO
-> PLLn -> CPUn for each CPU. So if we want to change the frequency of
CPU0 we change the frequency of PLL0. If we were to always lock the
parent, in this case XO, then we wouldn't gain anything because the two
CPUs trying to change rates independently would both be trying to
acquire the XO clock's lock, thus synchronizing the two things we're
trying to parallelize.

>
> It might also help the collision case fail faster since you will fail
> trying to grab the parent lock instead of grabbing the parent lock, then
> failing to lock the subtree.

I don't follow this part. Hopefully it doesn't matter though.

>
> Though in all honestly, I haven't finished thinking it through. The
> wait/wound algorithm opens up a lot of possibilities around very
> aggressive locking strategies to prevent contention. For example if we
> call clk_parent_lock it will lock the subtree starting from the parent,
> thus holding potentially a LOT more child locks, which only need to be
> updated during the recalc rate phase.  We could avoid holding those
> children until the moment that we need to lock them... I'll think about
> it some more.
>
> Oh wait, no we couldn't. We have to take all of our locks up front via
> ww_acquire_done(), which happens below.
>
>> +
>>         /* save parent rate, if it exists */
>>         parent = old_parent = clk->parent;
>>         if (parent)
> The context cuts it off, but the next line down accesses parent->rate.
> Again I think this happens without first having locked parent?

Yes.

>> +       ww_acquire_done(ctx);
> ww_acquire_done() happens here. OK. Neverrmind, just thinking through
> out loud.  This looks good.
>
> Let me know what you think about the questions above. I've also Cc'd
> Colin Cross who has experimented with per-clock locking before as well.
> He may or may not have an interest in this now.
>
>

Thanks for reviewing Mike. I've rebased the patches to clk-next as of
today. I still need to update the locking documentation before I send it
out again, hopefully by today or tomorrow. I'm also auditing clock
drivers to find potential brokenness.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

  reply	other threads:[~2014-09-30  0:12 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-04  1:01 [PATCH v2 0/4] Use wound/wait mutexes in the common clock framework Stephen Boyd
2014-09-04  1:01 ` [PATCH v2 1/4] clk: Recalc rate and accuracy in underscore functions if not caching Stephen Boyd
2014-09-04  1:01 ` [PATCH v2 2/4] clk: Make __clk_lookup() use a list instead of tree search Stephen Boyd
2014-09-04  1:01 ` [PATCH v2 3/4] clk: Use lockless functions for debug printing Stephen Boyd
2014-09-04  1:01 ` [PATCH v2 4/4] clk: Use ww_mutexes for clk_prepare_{lock/unlock} Stephen Boyd
2014-09-28  2:41   ` Mike Turquette
2014-09-30  0:12     ` Stephen Boyd [this message]
2014-10-08  1:09       ` Stephen Boyd
2014-10-09  2:59         ` Mike Turquette
2014-10-10  8:24           ` Peter De Schrijver
2014-10-11  0:20             ` Stephen Boyd
2014-10-13  8:23               ` Peter De Schrijver

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=5429F555.9030108@codeaurora.org \
    --to=sboyd@codeaurora.org \
    --cc=ccross@android.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mturquette@linaro.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).