From: skannan@codeaurora.org (Saravana Kannan)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 3/5] clk: add support for clock reparent on set_rate
Date: Mon, 20 May 2013 22:10:55 -0700 [thread overview]
Message-ID: <519B01DF.1080700@codeaurora.org> (raw)
In-Reply-To: <1369056507-32521-4-git-send-email-james.hogan@imgtec.com>
On 05/20/2013 06:28 AM, James Hogan wrote:
> Add core support to allow clock implementations to select the best
> parent clock when rounding a rate, e.g. the one which can provide the
> closest clock rate to that requested. This is by way of adding a new
> clock op, determine_rate(), which is like round_rate() but has an extra
> parameter to allow the clock implementation to optionally select a
> different parent clock. The core then takes care of reparenting the
> clock when setting the rate.
>
> The parent change takes place with the help of some new private data
> members. struct clk::new_parent specifies a clock's new parent (NULL
> indicates no change), and struct clk::new_child specifies a clock's new
> child (whose new_parent member points back to it). The purpose of these
> are to allow correct walking of the future tree for notifications prior
> to actually reparenting any clocks, specifically to skip child clocks
> who are being reparented to another clock (they will be notified via the
> new parent), and to include any new child clock. These pointers are set
> by clk_calc_subtree(), and the new_child pointer gets cleared when a
> child is actually reparented to avoid duplicate POST_RATE_CHANGE
> notifications.
>
> Each place where round_rate() is called, determine_rate() is checked
> first and called in preference. This restructures a few of the call
> sites to simplify the logic into if/else blocks.
>
> Signed-off-by: James Hogan <james.hogan@imgtec.com>
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: linux-arm-kernel at lists.infradead.org
> ---
> Changes in v4:
>
> * (not included Stephen Boyd's Reviewed-by due to changes)
> * replace __clk_set_parent_no_recalc with __clk_set_parent.
> * never pass NULL to determine_rate's best_parent_clk parameter, and
> slight refactor of __clk_round_rate to use local copy of clk->parent.
> * a few new comments around use of clk::new_child.
>
> Changes in v3:
>
> * rebased on v3.10-rc1.
> * store new_parent_index in struct clk too (calculated from
> clk_fetch_parent_index, and passed through __clk_set_parent_no_recalc
> to __clk_set_parent).
> * allow determine_rate to satisfy recalc_rate check in __clk_init.
>
> Documentation/clk.txt | 4 ++
> drivers/clk/clk.c | 142 +++++++++++++++++++++++++++++--------------
> include/linux/clk-private.h | 3 +
> include/linux/clk-provider.h | 7 +++
> 4 files changed, 110 insertions(+), 46 deletions(-)
>
> diff --git a/Documentation/clk.txt b/Documentation/clk.txt
> index b9911c2..3110ba4 100644
> --- a/Documentation/clk.txt
> +++ b/Documentation/clk.txt
> @@ -70,6 +70,10 @@ the operations defined in clk.h:
> unsigned long parent_rate);
> long (*round_rate)(struct clk_hw *hw, unsigned long,
> unsigned long *);
> + long (*determine_rate)(struct clk_hw *hw,
> + unsigned long rate,
> + unsigned long *best_parent_rate,
> + struct clk **best_parent_clk);
> int (*set_parent)(struct clk_hw *hw, u8 index);
> u8 (*get_parent)(struct clk_hw *hw);
> int (*set_rate)(struct clk_hw *hw, unsigned long);
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index a4cd6bc..3ce4810 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -888,21 +888,24 @@ EXPORT_SYMBOL_GPL(clk_enable);
> unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
> {
> unsigned long parent_rate = 0;
> + struct clk *parent;
>
> if (!clk)
> return 0;
>
> - if (!clk->ops->round_rate) {
> - if (clk->flags & CLK_SET_RATE_PARENT)
> - return __clk_round_rate(clk->parent, rate);
> - else
> - return clk->rate;
> - }
> -
> - if (clk->parent)
> - parent_rate = clk->parent->rate;
> -
> - return clk->ops->round_rate(clk->hw, rate, &parent_rate);
> + parent = clk->parent;
> + if (parent)
> + parent_rate = parent->rate;
> +
> + if (clk->ops->determine_rate)
> + return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
> + &parent);
> + else if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk->hw, rate, &parent_rate);
> + else if (clk->flags & CLK_SET_RATE_PARENT)
> + return __clk_round_rate(clk->parent, rate);
> + else
> + return clk->rate;
> }
>
> /**
> @@ -1055,6 +1058,10 @@ static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
>
> static void clk_reparent(struct clk *clk, struct clk *new_parent)
> {
> + /* avoid duplicate POST_RATE_CHANGE notifications */
> + if (new_parent->new_child == clk)
> + new_parent->new_child = NULL;
> +
> hlist_del(&clk->child_node);
>
> if (new_parent)
> @@ -1173,18 +1180,25 @@ out:
> return ret;
> }
>
> -static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
> +static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
> + struct clk *new_parent, u8 p_index)
> {
> struct clk *child;
>
> clk->new_rate = new_rate;
> + clk->new_parent = new_parent;
> + clk->new_parent_index = p_index;
> + /* include clk in new parent's PRE_RATE_CHANGE notifications */
> + clk->new_child = NULL;
> + if (new_parent && new_parent != clk->parent)
> + new_parent->new_child = clk;
>
> hlist_for_each_entry(child, &clk->children, child_node) {
> if (child->ops->recalc_rate)
> child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
> else
> child->new_rate = new_rate;
> - clk_calc_subtree(child, child->new_rate);
> + clk_calc_subtree(child, child->new_rate, NULL, 0);
> }
> }
>
> @@ -1195,50 +1209,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
> static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
> {
> struct clk *top = clk;
> + struct clk *old_parent, *parent;
> unsigned long best_parent_rate = 0;
> unsigned long new_rate;
> + u8 p_index = 0;
>
> /* sanity */
> if (IS_ERR_OR_NULL(clk))
> return NULL;
>
> /* save parent rate, if it exists */
> - if (clk->parent)
> - best_parent_rate = clk->parent->rate;
> -
> - /* never propagate up to the parent */
> - if (!(clk->flags & CLK_SET_RATE_PARENT)) {
> - if (!clk->ops->round_rate) {
> - clk->new_rate = clk->rate;
> - return NULL;
> - }
> - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
> + parent = old_parent = clk->parent;
> + if (parent)
> + best_parent_rate = parent->rate;
> +
> + /* find the closest rate and parent clk/rate */
> + if (clk->ops->determine_rate) {
> + new_rate = clk->ops->determine_rate(clk->hw, rate,
> + &best_parent_rate,
> + &parent);
> + } else if (clk->ops->round_rate) {
> + new_rate = clk->ops->round_rate(clk->hw, rate,
> + &best_parent_rate);
> + } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
> + /* pass-through clock without adjustable parent */
> + clk->new_rate = clk->rate;
> + return NULL;
> + } else {
> + /* pass-through clock with adjustable parent */
> + top = clk_calc_new_rates(parent, rate);
> + new_rate = parent->new_rate;
> goto out;
> }
>
> - /* need clk->parent from here on out */
> - if (!clk->parent) {
> - pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
> + /* some clocks must be gated to change parent */
> + if (parent != old_parent &&
> + (clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
> + pr_debug("%s: %s not gated but wants to reparent\n",
> + __func__, clk->name);
> return NULL;
> }
>
> - if (!clk->ops->round_rate) {
> - top = clk_calc_new_rates(clk->parent, rate);
> - new_rate = clk->parent->new_rate;
> -
> - goto out;
> + /* try finding the new parent index */
> + if (parent) {
> + p_index = clk_fetch_parent_index(clk, parent);
> + if (p_index == clk->num_parents) {
> + pr_debug("%s: clk %s can not be parent of clk %s\n",
> + __func__, parent->name, clk->name);
> + return NULL;
> + }
> }
>
> - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
> -
> - if (best_parent_rate != clk->parent->rate) {
> - top = clk_calc_new_rates(clk->parent, best_parent_rate);
> -
> - goto out;
> - }
> + if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
> + best_parent_rate != parent->rate)
> + top = clk_calc_new_rates(parent, best_parent_rate);
>
> out:
> - clk_calc_subtree(clk, new_rate);
> + clk_calc_subtree(clk, new_rate, parent, p_index);
>
> return top;
> }
> @@ -1250,7 +1277,7 @@ out:
> */
> static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
> {
> - struct clk *child, *fail_clk = NULL;
> + struct clk *child, *tmp_clk, *fail_clk = NULL;
> int ret = NOTIFY_DONE;
>
> if (clk->rate == clk->new_rate)
> @@ -1263,9 +1290,19 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
> }
>
> hlist_for_each_entry(child, &clk->children, child_node) {
> - clk = clk_propagate_rate_change(child, event);
> - if (clk)
> - fail_clk = clk;
> + /* Skip children who will be reparented to another clock */
> + if (child->new_parent && child->new_parent != clk)
> + continue;
> + tmp_clk = clk_propagate_rate_change(child, event);
> + if (tmp_clk)
> + fail_clk = tmp_clk;
> + }
> +
> + /* handle the new child who might not be in clk->children yet */
> + if (clk->new_child) {
> + tmp_clk = clk_propagate_rate_change(clk->new_child, event);
> + if (tmp_clk)
> + fail_clk = tmp_clk;
> }
>
> return fail_clk;
> @@ -1283,6 +1320,10 @@ static void clk_change_rate(struct clk *clk)
>
> old_rate = clk->rate;
>
> + /* set parent */
> + if (clk->new_parent && clk->new_parent != clk->parent)
> + __clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
> +
> if (clk->parent)
> best_parent_rate = clk->parent->rate;
>
> @@ -1297,8 +1338,16 @@ static void clk_change_rate(struct clk *clk)
> if (clk->notifier_count && old_rate != clk->rate)
> __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
>
> - hlist_for_each_entry(child, &clk->children, child_node)
> + hlist_for_each_entry(child, &clk->children, child_node) {
> + /* Skip children who will be reparented to another clock */
> + if (child->new_parent && child->new_parent != clk)
> + continue;
> clk_change_rate(child);
> + }
> +
> + /* handle the new child who might not be in clk->children yet */
> + if (clk->new_child)
> + clk_change_rate(clk->new_child);
> }
>
> /**
> @@ -1545,8 +1594,9 @@ int __clk_init(struct device *dev, struct clk *clk)
>
> /* check that clk_ops are sane. See Documentation/clk.txt */
> if (clk->ops->set_rate &&
> - !(clk->ops->round_rate && clk->ops->recalc_rate)) {
> - pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
> + !((clk->ops->round_rate || clk->ops->determine_rate) &&
> + clk->ops->recalc_rate)) {
> + pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
> __func__, clk->name);
> ret = -EINVAL;
> goto out;
> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
> index dd7adff..8138c94 100644
> --- a/include/linux/clk-private.h
> +++ b/include/linux/clk-private.h
> @@ -33,8 +33,11 @@ struct clk {
> const char **parent_names;
> struct clk **parents;
> u8 num_parents;
> + u8 new_parent_index;
Why do you need this? Given the new_parent, can't the specific clock
implementation just look it up when set_rate() is called? Wouldn't that
be the only time you would actually need the index?
If it's just for optimization of some error cases, I think we should
drop this to keep the code simpler. One less state to keep track of when
reading, writing or reviewing the clock framework.
I would like to do a more thorough review of this patch, but it's been a
while since I have looked at clk.c. So, I might not be able to do it
soon enough. But I can't ask to hold off this patch just because I don't
have time. So, I'll see what I can do.
-Saravana
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
WARNING: multiple messages have this Message-ID (diff)
From: Saravana Kannan <skannan@codeaurora.org>
To: James Hogan <james.hogan@imgtec.com>
Cc: Mike Turquette <mturquette@linaro.org>,
linux-arm-kernel@lists.infradead.org,
Stephen Boyd <sboyd@codeaurora.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 3/5] clk: add support for clock reparent on set_rate
Date: Mon, 20 May 2013 22:10:55 -0700 [thread overview]
Message-ID: <519B01DF.1080700@codeaurora.org> (raw)
In-Reply-To: <1369056507-32521-4-git-send-email-james.hogan@imgtec.com>
On 05/20/2013 06:28 AM, James Hogan wrote:
> Add core support to allow clock implementations to select the best
> parent clock when rounding a rate, e.g. the one which can provide the
> closest clock rate to that requested. This is by way of adding a new
> clock op, determine_rate(), which is like round_rate() but has an extra
> parameter to allow the clock implementation to optionally select a
> different parent clock. The core then takes care of reparenting the
> clock when setting the rate.
>
> The parent change takes place with the help of some new private data
> members. struct clk::new_parent specifies a clock's new parent (NULL
> indicates no change), and struct clk::new_child specifies a clock's new
> child (whose new_parent member points back to it). The purpose of these
> are to allow correct walking of the future tree for notifications prior
> to actually reparenting any clocks, specifically to skip child clocks
> who are being reparented to another clock (they will be notified via the
> new parent), and to include any new child clock. These pointers are set
> by clk_calc_subtree(), and the new_child pointer gets cleared when a
> child is actually reparented to avoid duplicate POST_RATE_CHANGE
> notifications.
>
> Each place where round_rate() is called, determine_rate() is checked
> first and called in preference. This restructures a few of the call
> sites to simplify the logic into if/else blocks.
>
> Signed-off-by: James Hogan <james.hogan@imgtec.com>
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: linux-arm-kernel@lists.infradead.org
> ---
> Changes in v4:
>
> * (not included Stephen Boyd's Reviewed-by due to changes)
> * replace __clk_set_parent_no_recalc with __clk_set_parent.
> * never pass NULL to determine_rate's best_parent_clk parameter, and
> slight refactor of __clk_round_rate to use local copy of clk->parent.
> * a few new comments around use of clk::new_child.
>
> Changes in v3:
>
> * rebased on v3.10-rc1.
> * store new_parent_index in struct clk too (calculated from
> clk_fetch_parent_index, and passed through __clk_set_parent_no_recalc
> to __clk_set_parent).
> * allow determine_rate to satisfy recalc_rate check in __clk_init.
>
> Documentation/clk.txt | 4 ++
> drivers/clk/clk.c | 142 +++++++++++++++++++++++++++++--------------
> include/linux/clk-private.h | 3 +
> include/linux/clk-provider.h | 7 +++
> 4 files changed, 110 insertions(+), 46 deletions(-)
>
> diff --git a/Documentation/clk.txt b/Documentation/clk.txt
> index b9911c2..3110ba4 100644
> --- a/Documentation/clk.txt
> +++ b/Documentation/clk.txt
> @@ -70,6 +70,10 @@ the operations defined in clk.h:
> unsigned long parent_rate);
> long (*round_rate)(struct clk_hw *hw, unsigned long,
> unsigned long *);
> + long (*determine_rate)(struct clk_hw *hw,
> + unsigned long rate,
> + unsigned long *best_parent_rate,
> + struct clk **best_parent_clk);
> int (*set_parent)(struct clk_hw *hw, u8 index);
> u8 (*get_parent)(struct clk_hw *hw);
> int (*set_rate)(struct clk_hw *hw, unsigned long);
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index a4cd6bc..3ce4810 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -888,21 +888,24 @@ EXPORT_SYMBOL_GPL(clk_enable);
> unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
> {
> unsigned long parent_rate = 0;
> + struct clk *parent;
>
> if (!clk)
> return 0;
>
> - if (!clk->ops->round_rate) {
> - if (clk->flags & CLK_SET_RATE_PARENT)
> - return __clk_round_rate(clk->parent, rate);
> - else
> - return clk->rate;
> - }
> -
> - if (clk->parent)
> - parent_rate = clk->parent->rate;
> -
> - return clk->ops->round_rate(clk->hw, rate, &parent_rate);
> + parent = clk->parent;
> + if (parent)
> + parent_rate = parent->rate;
> +
> + if (clk->ops->determine_rate)
> + return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
> + &parent);
> + else if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk->hw, rate, &parent_rate);
> + else if (clk->flags & CLK_SET_RATE_PARENT)
> + return __clk_round_rate(clk->parent, rate);
> + else
> + return clk->rate;
> }
>
> /**
> @@ -1055,6 +1058,10 @@ static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
>
> static void clk_reparent(struct clk *clk, struct clk *new_parent)
> {
> + /* avoid duplicate POST_RATE_CHANGE notifications */
> + if (new_parent->new_child == clk)
> + new_parent->new_child = NULL;
> +
> hlist_del(&clk->child_node);
>
> if (new_parent)
> @@ -1173,18 +1180,25 @@ out:
> return ret;
> }
>
> -static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
> +static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
> + struct clk *new_parent, u8 p_index)
> {
> struct clk *child;
>
> clk->new_rate = new_rate;
> + clk->new_parent = new_parent;
> + clk->new_parent_index = p_index;
> + /* include clk in new parent's PRE_RATE_CHANGE notifications */
> + clk->new_child = NULL;
> + if (new_parent && new_parent != clk->parent)
> + new_parent->new_child = clk;
>
> hlist_for_each_entry(child, &clk->children, child_node) {
> if (child->ops->recalc_rate)
> child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
> else
> child->new_rate = new_rate;
> - clk_calc_subtree(child, child->new_rate);
> + clk_calc_subtree(child, child->new_rate, NULL, 0);
> }
> }
>
> @@ -1195,50 +1209,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
> static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
> {
> struct clk *top = clk;
> + struct clk *old_parent, *parent;
> unsigned long best_parent_rate = 0;
> unsigned long new_rate;
> + u8 p_index = 0;
>
> /* sanity */
> if (IS_ERR_OR_NULL(clk))
> return NULL;
>
> /* save parent rate, if it exists */
> - if (clk->parent)
> - best_parent_rate = clk->parent->rate;
> -
> - /* never propagate up to the parent */
> - if (!(clk->flags & CLK_SET_RATE_PARENT)) {
> - if (!clk->ops->round_rate) {
> - clk->new_rate = clk->rate;
> - return NULL;
> - }
> - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
> + parent = old_parent = clk->parent;
> + if (parent)
> + best_parent_rate = parent->rate;
> +
> + /* find the closest rate and parent clk/rate */
> + if (clk->ops->determine_rate) {
> + new_rate = clk->ops->determine_rate(clk->hw, rate,
> + &best_parent_rate,
> + &parent);
> + } else if (clk->ops->round_rate) {
> + new_rate = clk->ops->round_rate(clk->hw, rate,
> + &best_parent_rate);
> + } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
> + /* pass-through clock without adjustable parent */
> + clk->new_rate = clk->rate;
> + return NULL;
> + } else {
> + /* pass-through clock with adjustable parent */
> + top = clk_calc_new_rates(parent, rate);
> + new_rate = parent->new_rate;
> goto out;
> }
>
> - /* need clk->parent from here on out */
> - if (!clk->parent) {
> - pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
> + /* some clocks must be gated to change parent */
> + if (parent != old_parent &&
> + (clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
> + pr_debug("%s: %s not gated but wants to reparent\n",
> + __func__, clk->name);
> return NULL;
> }
>
> - if (!clk->ops->round_rate) {
> - top = clk_calc_new_rates(clk->parent, rate);
> - new_rate = clk->parent->new_rate;
> -
> - goto out;
> + /* try finding the new parent index */
> + if (parent) {
> + p_index = clk_fetch_parent_index(clk, parent);
> + if (p_index == clk->num_parents) {
> + pr_debug("%s: clk %s can not be parent of clk %s\n",
> + __func__, parent->name, clk->name);
> + return NULL;
> + }
> }
>
> - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
> -
> - if (best_parent_rate != clk->parent->rate) {
> - top = clk_calc_new_rates(clk->parent, best_parent_rate);
> -
> - goto out;
> - }
> + if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
> + best_parent_rate != parent->rate)
> + top = clk_calc_new_rates(parent, best_parent_rate);
>
> out:
> - clk_calc_subtree(clk, new_rate);
> + clk_calc_subtree(clk, new_rate, parent, p_index);
>
> return top;
> }
> @@ -1250,7 +1277,7 @@ out:
> */
> static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
> {
> - struct clk *child, *fail_clk = NULL;
> + struct clk *child, *tmp_clk, *fail_clk = NULL;
> int ret = NOTIFY_DONE;
>
> if (clk->rate == clk->new_rate)
> @@ -1263,9 +1290,19 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
> }
>
> hlist_for_each_entry(child, &clk->children, child_node) {
> - clk = clk_propagate_rate_change(child, event);
> - if (clk)
> - fail_clk = clk;
> + /* Skip children who will be reparented to another clock */
> + if (child->new_parent && child->new_parent != clk)
> + continue;
> + tmp_clk = clk_propagate_rate_change(child, event);
> + if (tmp_clk)
> + fail_clk = tmp_clk;
> + }
> +
> + /* handle the new child who might not be in clk->children yet */
> + if (clk->new_child) {
> + tmp_clk = clk_propagate_rate_change(clk->new_child, event);
> + if (tmp_clk)
> + fail_clk = tmp_clk;
> }
>
> return fail_clk;
> @@ -1283,6 +1320,10 @@ static void clk_change_rate(struct clk *clk)
>
> old_rate = clk->rate;
>
> + /* set parent */
> + if (clk->new_parent && clk->new_parent != clk->parent)
> + __clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
> +
> if (clk->parent)
> best_parent_rate = clk->parent->rate;
>
> @@ -1297,8 +1338,16 @@ static void clk_change_rate(struct clk *clk)
> if (clk->notifier_count && old_rate != clk->rate)
> __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
>
> - hlist_for_each_entry(child, &clk->children, child_node)
> + hlist_for_each_entry(child, &clk->children, child_node) {
> + /* Skip children who will be reparented to another clock */
> + if (child->new_parent && child->new_parent != clk)
> + continue;
> clk_change_rate(child);
> + }
> +
> + /* handle the new child who might not be in clk->children yet */
> + if (clk->new_child)
> + clk_change_rate(clk->new_child);
> }
>
> /**
> @@ -1545,8 +1594,9 @@ int __clk_init(struct device *dev, struct clk *clk)
>
> /* check that clk_ops are sane. See Documentation/clk.txt */
> if (clk->ops->set_rate &&
> - !(clk->ops->round_rate && clk->ops->recalc_rate)) {
> - pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
> + !((clk->ops->round_rate || clk->ops->determine_rate) &&
> + clk->ops->recalc_rate)) {
> + pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
> __func__, clk->name);
> ret = -EINVAL;
> goto out;
> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
> index dd7adff..8138c94 100644
> --- a/include/linux/clk-private.h
> +++ b/include/linux/clk-private.h
> @@ -33,8 +33,11 @@ struct clk {
> const char **parent_names;
> struct clk **parents;
> u8 num_parents;
> + u8 new_parent_index;
Why do you need this? Given the new_parent, can't the specific clock
implementation just look it up when set_rate() is called? Wouldn't that
be the only time you would actually need the index?
If it's just for optimization of some error cases, I think we should
drop this to keep the code simpler. One less state to keep track of when
reading, writing or reviewing the clock framework.
I would like to do a more thorough review of this patch, but it's been a
while since I have looked at clk.c. So, I might not be able to do it
soon enough. But I can't ask to hold off this patch just because I don't
have time. So, I'll see what I can do.
-Saravana
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
next prev parent reply other threads:[~2013-05-21 5:10 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-20 13:28 [PATCH v4 0/5] clk: implement remuxing during set_rate James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 13:28 ` [PATCH v4 1/5] clk: abstract parent cache James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 13:28 ` [PATCH v4 2/5] clk: move some parent related functions upwards James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 21:16 ` Stephen Boyd
2013-05-20 21:16 ` Stephen Boyd
2013-05-20 13:28 ` [PATCH v4 3/5] clk: add support for clock reparent on set_rate James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 21:17 ` Stephen Boyd
2013-05-20 21:17 ` Stephen Boyd
2013-06-13 14:31 ` James Hogan
2013-06-13 14:31 ` James Hogan
2013-05-21 5:10 ` Saravana Kannan [this message]
2013-05-21 5:10 ` Saravana Kannan
2013-05-22 10:13 ` James Hogan
2013-05-22 10:13 ` James Hogan
2013-05-20 13:28 ` [PATCH v4 4/5] clk: add CLK_SET_RATE_NO_REPARENT flag James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-20 20:44 ` Stephen Warren
2013-05-20 20:44 ` Stephen Warren
[not found] ` <1369056507-32521-5-git-send-email-james.hogan-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
2013-05-22 15:52 ` Maxime Ripard
2013-05-22 15:52 ` Maxime Ripard
2013-05-22 15:52 ` Maxime Ripard
2013-05-20 13:28 ` [PATCH v4 5/5] clk: clk-mux: implement remuxing on set_rate James Hogan
2013-05-20 13:28 ` James Hogan
2013-05-21 4:44 ` Saravana Kannan
2013-05-21 4:44 ` Saravana Kannan
2013-06-12 1:01 ` Doug Anderson
2013-06-12 1:01 ` Doug Anderson
2013-06-12 17:45 ` Mike Turquette
2013-06-12 17:45 ` Mike Turquette
2013-06-12 17:55 ` Doug Anderson
2013-06-12 17:55 ` Doug Anderson
2013-06-12 18:07 ` Mike Turquette
2013-06-12 18:07 ` Mike Turquette
2013-06-13 15:18 ` James Hogan
2013-06-13 15:18 ` James Hogan
2013-06-13 15:02 ` James Hogan
2013-06-13 15:02 ` James Hogan
2013-06-06 1:39 ` [PATCH v4 0/5] clk: implement remuxing during set_rate Haojian Zhuang
2013-06-06 1:39 ` Haojian Zhuang
2013-06-13 1:35 ` Stephen Boyd
2013-06-13 1:35 ` Stephen Boyd
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=519B01DF.1080700@codeaurora.org \
--to=skannan@codeaurora.org \
--cc=linux-arm-kernel@lists.infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.