Current clk notification handlers cannot know its new parent in PRE_RATE_CHANGE event. This patch simply adds parent clk to clk_notifier_data so the child clk is now able to know its future parent prior to reparenting.
Change-Id: I099a784d5302a93951bdc6254d85f8df8c770462 Signed-off-by: Ikjoon Jang <i...@chromium.org> --- drivers/clk/clk.c | 30 +++++++++++++++++------------- include/linux/clk.h | 9 ++++++--- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 3f588ed06ce3..62c4e7b50ae5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1458,6 +1458,7 @@ EXPORT_SYMBOL_GPL(clk_round_rate); /** * __clk_notify - call clk notifier chain * @core: clk that is changing rate + * @parent: new parent of core * @msg: clk notifier type (see include/linux/clk.h) * @old_rate: old clk rate * @new_rate: new clk rate @@ -1469,13 +1470,15 @@ EXPORT_SYMBOL_GPL(clk_round_rate); * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if * a driver returns that. */ -static int __clk_notify(struct clk_core *core, unsigned long msg, - unsigned long old_rate, unsigned long new_rate) +static int __clk_notify(struct clk_core *core, struct clk_core *parent, + unsigned long msg, unsigned long old_rate, + unsigned long new_rate) { struct clk_notifier *cn; struct clk_notifier_data cnd; int ret = NOTIFY_DONE; + cnd.parent = parent ? parent->hw->clk : NULL; cnd.old_rate = old_rate; cnd.new_rate = new_rate; @@ -1597,7 +1600,7 @@ static void __clk_recalc_rates(struct clk_core *core, unsigned long msg) * & ABORT_RATE_CHANGE notifiers */ if (core->notifier_count && msg) - __clk_notify(core, msg, old_rate, core->rate); + __clk_notify(core, core->parent, msg, old_rate, core->rate); hlist_for_each_entry(child, &core->children, child_node) __clk_recalc_rates(child, msg); @@ -1834,7 +1837,7 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent, /** * __clk_speculate_rates * @core: first clk in the subtree - * @parent_rate: the "future" rate of clk's parent + * @parent: the "future" parent of core * * Walks the subtree of clks starting with clk, speculating rates as it * goes and firing off PRE_RATE_CHANGE notifications as necessary. @@ -1846,7 +1849,7 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent, * take on the rate of its parent. */ static int __clk_speculate_rates(struct clk_core *core, - unsigned long parent_rate) + struct clk_core *parent) { struct clk_core *child; unsigned long new_rate; @@ -1854,11 +1857,12 @@ static int __clk_speculate_rates(struct clk_core *core, lockdep_assert_held(&prepare_lock); - new_rate = clk_recalc(core, parent_rate); + new_rate = clk_recalc(core, parent ? parent->rate : 0); /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ if (core->notifier_count) - ret = __clk_notify(core, PRE_RATE_CHANGE, core->rate, new_rate); + ret = __clk_notify(core, parent, PRE_RATE_CHANGE, + core->rate, new_rate); if (ret & NOTIFY_STOP_MASK) { pr_debug("%s: clk notifier callback for clock %s aborted with error %d\n", @@ -1867,7 +1871,7 @@ static int __clk_speculate_rates(struct clk_core *core, } hlist_for_each_entry(child, &core->children, child_node) { - ret = __clk_speculate_rates(child, new_rate); + ret = __clk_speculate_rates(child, core); if (ret & NOTIFY_STOP_MASK) break; } @@ -1996,7 +2000,8 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core, return NULL; if (core->notifier_count) { - ret = __clk_notify(core, event, core->rate, core->new_rate); + ret = __clk_notify(core, core->parent, event, + core->rate, core->new_rate); if (ret & NOTIFY_STOP_MASK) fail_clk = core; } @@ -2098,7 +2103,8 @@ static void clk_change_rate(struct clk_core *core) clk_core_disable_unprepare(parent); if (core->notifier_count && old_rate != core->rate) - __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate); + __clk_notify(core, core->parent, POST_RATE_CHANGE, + old_rate, core->rate); if (core->flags & CLK_RECALC_NEW_RATES) (void)clk_calc_new_rates(core, core->new_rate); @@ -2479,7 +2485,6 @@ static int clk_core_set_parent_nolock(struct clk_core *core, { int ret = 0; int p_index = 0; - unsigned long p_rate = 0; lockdep_assert_held(&prepare_lock); @@ -2508,7 +2513,6 @@ static int clk_core_set_parent_nolock(struct clk_core *core, __func__, parent->name, core->name); return p_index; } - p_rate = parent->rate; } ret = clk_pm_runtime_get(core); @@ -2516,7 +2520,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core, return ret; /* propagate PRE_RATE_CHANGE notifications */ - ret = __clk_speculate_rates(core, p_rate); + ret = __clk_speculate_rates(core, parent); /* abort if a driver objects */ if (ret & NOTIFY_STOP_MASK) diff --git a/include/linux/clk.h b/include/linux/clk.h index 7fd6a1febcf4..e246e160b290 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -60,16 +60,19 @@ struct clk_notifier { /** * struct clk_notifier_data - rate data to pass to the notifier callback * @clk: struct clk * being changed + * @parent: new parent of this clk * @old_rate: previous rate of this clk * @new_rate: new rate of this clk * * For a pre-notifier, old_rate is the clk's rate before this rate - * change, and new_rate is what the rate will be in the future. For a - * post-notifier, old_rate and new_rate are both set to the clk's - * current rate (this was done to optimize the implementation). + * change, new_rate is what the rate will be in the future, and parent is + * new parent of the clk after new_rate is applied, For a post-notifier, + * parent, old_rate, and new_rate are all set to the clk's current state. + * (this was done to optimize the implementation). */ struct clk_notifier_data { struct clk *clk; + struct clk *parent; unsigned long old_rate; unsigned long new_rate; }; -- 2.27.0.290.gba653c62da-goog