drivers/clk/clk-composite.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
In clk_composite_determine_rate(), the rate request is currently
modified using clk_hw_forward_rate_request() before being passed to the
rate_hw (divider). This behavior was inadvertently introduced by commit
20220816112530.1837489-22-maxime@cerno.tech ("clk: Stop forwarding
clk_rate_requests to the parent").
While clk_hw_forward_rate_request() effectively prevents context
pollution for pure multiplexers, using it for the internal components
of a composite clock introduces an unintended side effect. It fetches
the parent's rate boundaries and overwrites tmp_req.min_rate and
tmp_req.max_rate.
Consequently, the divider evaluates its own output constraints based on
the parent's operating constraints. For example, if a target rate is
50MHz, but the parent PLL hardware boundaries are [100MHz, 200MHz], the
divider erroneously assumes its output cannot be lower than 100MHz. It
then refuses to divide the frequency down, clamping the output to 100MHz.
Fix this by reverting to a local copy of the request (*req) without
applying parent boundaries before passing it to the rate_hw. This allows
the divider to evaluate boundaries correctly based on its own requirements.
I am submitting this as an RFC because I want to make sure I am not missing
a specific reason why the parent's boundaries must be forwarded to the
divider's output request in this context. Any insights would be
appreciated.
Fixes: 262ca38f4b6e ("clk: Stop forwarding clk_rate_requests to the parent")
Signed-off-by: YuXuan Liu <2021020915018@std.uestc.edu.cn>
---
drivers/clk/clk-composite.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 66759fe28fad..952df88518c2 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -85,11 +85,10 @@ static int clk_composite_determine_rate(struct clk_hw *hw,
req->best_parent_hw = NULL;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
- struct clk_rate_request tmp_req;
+ struct clk_rate_request tmp_req = *req;
parent = clk_hw_get_parent(mux_hw);
- clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
ret = clk_composite_determine_rate_for_parent(rate_hw,
&tmp_req,
parent,
@@ -105,13 +104,12 @@ static int clk_composite_determine_rate(struct clk_hw *hw,
}
for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
- struct clk_rate_request tmp_req;
+ struct clk_rate_request tmp_req = *req;
parent = clk_hw_get_parent_by_index(mux_hw, i);
if (!parent)
continue;
- clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
ret = clk_composite_determine_rate_for_parent(rate_hw,
&tmp_req,
parent,
--
2.53.0
© 2016 - 2026 Red Hat, Inc.