Re: [PATCH RFC 01/16] clk: Propagate rate programming failures
From: Dmitry Baryshkov
Date: Wed Oct 14 2026 - 09:46:24 EST
On Wed, Oct 14, 2026 at 02:19:01PM +0200, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@xxxxxxxxxxxxxxxx>
>
> The clock rate-change walk ignores runtime PM, temporary prepare and
> enable, and provider programming failures. clk_set_rate() can therefore
> report success after a provider rejected the operation, while later
> clocks in the affected tree continue to be programmed. Consumers can
> then proceed with a configuration that was never successfully applied.
>
> A failed parent switch must not leave the software topology pointing at
> the rejected source or release the old parent's references. Likewise,
> rate notifiers must not announce success before the whole walk succeeds,
> or lose their ABORT notification when a PRE notifier vetoes the change.
>
> Propagate errors and stop the walk at the first failure. Keep topology,
> temporary references, and terminal notifications consistent with the
> outcome.
>
> Assisted-by: LLM
> Signed-off-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxxxxxxxx>
> ---
> drivers/clk/clk.c | 163 +++++++++++++++++++++++++++++++++++++------------
> drivers/clk/clk_test.c | 16 ++++-
> 2 files changed, 138 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 4d2cc86bfbeb..95669775f8cd 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -84,6 +84,7 @@ struct clk_parent_map {
> * clk_core->rate every time the clock is reparented, and
> * when we're doing the orphan -> !orphan transition.
> * @new_rate: New rate to be set during a rate change operation.
> + * @old_rate: Rate before the current rate change operation.
> * @new_parent: Pointer to new parent during parent change. This is also
> * used when a clk's rate is changed.
> * @new_child: Pointer to new child during reparenting. This is also
> @@ -130,6 +131,7 @@ struct clk_core {
> unsigned long rate;
> unsigned long req_rate;
> unsigned long new_rate;
> + unsigned long old_rate;
> struct clk_core *new_parent;
> struct clk_core *new_child;
> unsigned long flags;
> @@ -2163,11 +2165,14 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent)
> core->parent = new_parent;
> }
>
> -static struct clk_core *__clk_set_parent_before(struct clk_core *core,
> - struct clk_core *parent)
> +static int __clk_set_parent_before(struct clk_core *core,
> + struct clk_core *parent,
> + struct clk_core **old_parent)
Nit: we have an idiom for returning either a value or an error. Is there
a reason why you didn't adopt returning ERR_PTR here?
> {
> unsigned long flags;
> - struct clk_core *old_parent = core->parent;
> + int ret;
> +
> + *old_parent = core->parent;
And that's the reason for asking. A pointer argument is expected to be
in or in/out param.
>
> /*
> * 1. enable parents for CLK_OPS_PARENT_ENABLE clock
[...]
> @@ -2247,10 +2274,10 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
> trace_clk_set_parent_complete(core, parent);
>
> if (ret) {
> - flags = clk_enable_lock();
> + unsigned long flags = clk_enable_lock();
> +
> clk_reparent(core, old_parent);
> clk_enable_unlock(flags);
> -
Two unrelated changes?
> __clk_set_parent_after(core, old_parent, parent);
>
> return ret;
--
With best wishes
Dmitry