linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ikjoon Jang <ikjn@chromium.org>
To: linux-clk@vger.kernel.org
Cc: Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>,
	linux-kernel@vger.kernel.org, Ikjoon Jang <ikjn@chromium.org>
Subject: [PATCH] clk: Provide future parent in clk notification
Date: Tue, 16 Jun 2020 13:52:23 +0800	[thread overview]
Message-ID: <20200616055223.119360-1-ikjn@chromium.org> (raw)

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 <ikjn@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


             reply	other threads:[~2020-06-16  5:52 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-16  5:52 Ikjoon Jang [this message]
2020-06-23 19:08 ` [PATCH] clk: Provide future parent in clk notification Stephen Boyd
2020-06-29 10:24   ` Ikjoon Jang

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=20200616055223.119360-1-ikjn@chromium.org \
    --to=ikjn@chromium.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=sboyd@kernel.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).