From: Brian Masney <bmasney@redhat.com>
To: sboyd@kernel.org
Cc: mturquette@baylibre.com, mripard@kernel.org,
linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/2] clk: preserve original rate when a sibling clk changes it's rate
Date: Tue, 20 May 2025 15:28:45 -0400 [thread overview]
Message-ID: <20250520192846.9614-2-bmasney@redhat.com> (raw)
In-Reply-To: <20250520192846.9614-1-bmasney@redhat.com>
When a clk requests a new rate, there are times when the requested rate
cannot be fulfilled due to the current rate of the parent clk. If
CLK_SET_RATE_PARENT is set, then the parent rate can also be changed.
However, the clk core currently doesn't negotiate with any of the other
children to see if the new parent rate is acceptable, and will currently
just change the rates of the sibling clks.
When a parent changes it's rate, only ensure that the section of the
clk tree where the rate change request propagated up is changed. All
other sibling nodes should try to keep a rate close to where they
were originally at. The rate will go through a recalc_rate() with the
new parent rate, so the rate may possibly change.
This doesn't fix all of the issues where a clk can unknowingly change
the rate of it's siblings, however this is a relatively small change
that can fix some issues. A correct change that includes voting across
the various nodes in the subtree, and works across the various types
of clks will involve a much more elaborate patch set.
This change was tested with kunit tests, and also boot tested on a
Lenovo Thinkpad x13s laptop.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 0565c87656cf..713d4d8a9b1e 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -72,6 +72,7 @@ struct clk_core {
unsigned long rate;
unsigned long req_rate;
unsigned long new_rate;
+ bool rate_directly_changed;
struct clk_core *new_parent;
struct clk_core *new_child;
unsigned long flags;
@@ -2254,6 +2255,7 @@ static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
struct clk_core *new_parent, u8 p_index)
{
struct clk_core *child;
+ unsigned long tmp_rate;
core->new_rate = new_rate;
core->new_parent = new_parent;
@@ -2264,7 +2266,14 @@ static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
new_parent->new_child = core;
hlist_for_each_entry(child, &core->children, child_node) {
- child->new_rate = clk_recalc(child, new_rate);
+ /*
+ * When a parent changes it's rate, only ensure that the section
+ * of the clk tree where the rate change request propagated up
+ * is changed. All other sibling nodes should try to keep a rate
+ * close to where they were originally at.
+ */
+ tmp_rate = child->rate_directly_changed ? new_rate : child->rate;
+ child->new_rate = clk_recalc(child, tmp_rate);
clk_calc_subtree(child, child->new_rate, NULL, 0);
}
}
@@ -2346,8 +2355,10 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
}
if ((core->flags & CLK_SET_RATE_PARENT) && parent &&
- best_parent_rate != parent->rate)
+ best_parent_rate != parent->rate) {
+ parent->rate_directly_changed = true;
top = clk_calc_new_rates(parent, best_parent_rate);
+ }
out:
clk_calc_subtree(core, new_rate, parent, p_index);
@@ -2487,6 +2498,15 @@ static void clk_change_rate(struct clk_core *core)
clk_pm_runtime_put(core);
}
+static void clk_clear_rate_flags(struct clk_core *top)
+{
+ struct clk_core *child;
+
+ top->rate_directly_changed = false;
+ hlist_for_each_entry(child, &top->children, child_node) {
+ clk_clear_rate_flags(child);
+ }
+}
static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
unsigned long req_rate)
{
@@ -2537,6 +2557,8 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
if (clk_core_rate_is_protected(core))
return -EBUSY;
+ core->rate_directly_changed = true;
+
/* calculate new rates and get the topmost changed clock */
top = clk_calc_new_rates(core, req_rate);
if (!top)
@@ -2559,6 +2581,8 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
/* change the rates */
clk_change_rate(top);
+ clk_clear_rate_flags(top);
+
core->req_rate = req_rate;
err:
clk_pm_runtime_put(core);
--
2.49.0
next prev parent reply other threads:[~2025-05-20 19:29 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-20 19:28 [PATCH 0/2] clk: preserve original rate when a sibling clk changes it's rate Brian Masney
2025-05-20 19:28 ` Brian Masney [this message]
2025-05-27 12:36 ` [PATCH 1/2] " Maxime Ripard
2025-05-27 19:07 ` Brian Masney
2025-05-20 19:28 ` [PATCH 2/2] clk: test: remove kunit_skip() for divider tests that have been fixed Brian Masney
2025-05-28 23:23 ` [PATCH 0/2] clk: preserve original rate when a sibling clk changes it's rate Brian Masney
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=20250520192846.9614-2-bmasney@redhat.com \
--to=bmasney@redhat.com \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mripard@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