mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] clk: send abort notifications when a parent change is vetoed
@ 2026-10-21 21:28 James Hilliard
  2026-10-26 14:30 ` Konrad Dybcio
  0 siblings, 1 reply; 2+ messages in thread
From: James Hilliard @ 2026-10-21 21:28 UTC (permalink / raw)
  To: Stephen Boyd, Brian Masney, Jerome Brunet, Mike Turquette,
	Thomas Gleixner, Arnd Bergmann
  Cc: Konrad Dybcio, linux-clk, linux-kernel, James Hilliard

clk_core_set_parent_nolock() returns directly when a PRE_RATE_CHANGE
notifier rejects the proposed parent. Consumers notified before the veto
do not receive ABORT_RATE_CHANGE, even though they may have stopped I/O
or reserved resources until the transition finishes. The caller also
receives a positive notifier return value instead of a negative errno.

Recalculate and notify the unchanged subtree with ABORT_RATE_CHANGE before
returning -EBUSY, as for other failed parent changes. This lets prepared
consumers unwind without changing the parent or its rate.

Extend the mux notifier tests to cover both a self-veto and a later
notifier vetoing after the first consumer accepted the change. Check the
abort notification, errno and unchanged parent/rate in both cases.

Fixes: b2476490ef11 ("clk: introduce the common clock framework")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
 drivers/clk/clk.c      |  5 +++-
 drivers/clk/clk_test.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index fef87167a60b..a9620d9e0db1 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2983,8 +2983,11 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
 	ret = __clk_speculate_rates(core, p_rate);
 
 	/* abort if a driver objects */
-	if (ret & NOTIFY_STOP_MASK)
+	if (ret & NOTIFY_STOP_MASK) {
+		__clk_recalc_rates(core, true, ABORT_RATE_CHANGE);
+		ret = -EBUSY;
 		goto runtime_put;
+	}
 
 	/* do the re-parent */
 	ret = __clk_set_parent(core, parent, p_index);
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 1c5c8b7c1f3c..e9d0d6f5084b 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -2364,6 +2364,8 @@ struct clk_mux_notifier_ctx {
 	struct notifier_block clk_nb;
 	struct clk_mux_notifier_rate_change pre_rate_change;
 	struct clk_mux_notifier_rate_change post_rate_change;
+	bool veto;
+	bool aborted;
 };
 
 #define NOTIFIER_TIMEOUT_MS 100
@@ -2381,6 +2383,8 @@ static int clk_mux_notifier_callback(struct notifier_block *nb,
 		ctx->pre_rate_change.new_rate = clk_data->new_rate;
 		ctx->pre_rate_change.done = true;
 		wake_up_interruptible(&ctx->pre_rate_change.wq);
+		if (ctx->veto)
+			return NOTIFY_BAD;
 	}
 
 	if (action & POST_RATE_CHANGE) {
@@ -2390,7 +2394,10 @@ static int clk_mux_notifier_callback(struct notifier_block *nb,
 		wake_up_interruptible(&ctx->post_rate_change.wq);
 	}
 
-	return 0;
+	if (action == ABORT_RATE_CHANGE)
+		ctx->aborted = true;
+
+	return NOTIFY_OK;
 }
 
 static int clk_mux_notifier_test_init(struct kunit *test)
@@ -2488,8 +2495,61 @@ static void clk_mux_notifier_set_parent_test(struct kunit *test)
 	clk_put(clk);
 }
 
+static void clk_mux_notifier_veto_parent_test(struct kunit *test)
+{
+	struct clk_mux_notifier_ctx *ctx = test->priv;
+	struct clk *parent = clk_hw_get_clk(&ctx->mux_ctx.parents_ctx[1].hw, NULL);
+	int ret;
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+	ctx->veto = true;
+	ret = clk_set_parent(ctx->clk, parent);
+	clk_put(parent);
+
+	KUNIT_EXPECT_EQ(test, ret, -EBUSY);
+	KUNIT_EXPECT_TRUE(test, ctx->pre_rate_change.done);
+	KUNIT_EXPECT_TRUE(test, ctx->aborted);
+	KUNIT_EXPECT_FALSE(test, ctx->post_rate_change.done);
+	KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->clk), DUMMY_CLOCK_RATE_1);
+	KUNIT_EXPECT_EQ(test, ctx->mux_ctx.current_parent, 0);
+}
+
+static int clk_mux_veto_callback(struct notifier_block *nb,
+				 unsigned long action, void *data)
+{
+	return action == PRE_RATE_CHANGE ? NOTIFY_BAD : NOTIFY_OK;
+}
+
+static void clk_mux_notifier_abort_parent_test(struct kunit *test)
+{
+	struct clk_mux_notifier_ctx *ctx = test->priv;
+	struct notifier_block veto = { .notifier_call = clk_mux_veto_callback };
+	struct clk *parent = clk_hw_get_clk(&ctx->mux_ctx.parents_ctx[1].hw, NULL);
+	int ret;
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+	ret = clk_notifier_register(ctx->clk, &veto);
+	if (ret)
+		clk_put(parent);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	/* The first consumer accepts PRE before the second consumer vetoes it. */
+	ret = clk_set_parent(ctx->clk, parent);
+	clk_put(parent);
+	clk_notifier_unregister(ctx->clk, &veto);
+
+	KUNIT_EXPECT_EQ(test, ret, -EBUSY);
+	KUNIT_EXPECT_TRUE(test, ctx->pre_rate_change.done);
+	KUNIT_EXPECT_TRUE(test, ctx->aborted);
+	KUNIT_EXPECT_FALSE(test, ctx->post_rate_change.done);
+	KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->clk), DUMMY_CLOCK_RATE_1);
+	KUNIT_EXPECT_EQ(test, ctx->mux_ctx.current_parent, 0);
+}
+
 static struct kunit_case clk_mux_notifier_test_cases[] = {
 	KUNIT_CASE(clk_mux_notifier_set_parent_test),
+	KUNIT_CASE(clk_mux_notifier_veto_parent_test),
+	KUNIT_CASE(clk_mux_notifier_abort_parent_test),
 	{}
 };
 

---
base-commit: 81493c1dd1b1ebecb2843a7815973a5bd9a37e5a
change-id: 20261021-submit-clk-parent-abort-v1-b9232ac83dd1

Best regards,
--  
James Hilliard <james.hilliard1@gmail.com>


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] clk: send abort notifications when a parent change is vetoed
  2026-10-21 21:28 [PATCH] clk: send abort notifications when a parent change is vetoed James Hilliard
@ 2026-10-26 14:30 ` Konrad Dybcio
  0 siblings, 0 replies; 2+ messages in thread
From: Konrad Dybcio @ 2026-10-26 14:30 UTC (permalink / raw)
  To: James Hilliard, Stephen Boyd, Brian Masney, Jerome Brunet,
	Mike Turquette, Thomas Gleixner, Arnd Bergmann
  Cc: linux-clk, linux-kernel

On 10/21/26 11:28 PM, James Hilliard wrote:
> clk_core_set_parent_nolock() returns directly when a PRE_RATE_CHANGE
> notifier rejects the proposed parent. Consumers notified before the veto
> do not receive ABORT_RATE_CHANGE, even though they may have stopped I/O
> or reserved resources until the transition finishes. The caller also
> receives a positive notifier return value instead of a negative errno.
> 
> Recalculate and notify the unchanged subtree with ABORT_RATE_CHANGE before
> returning -EBUSY, as for other failed parent changes. This lets prepared
> consumers unwind without changing the parent or its rate.
> 
> Extend the mux notifier tests to cover both a self-veto and a later
> notifier vetoing after the first consumer accepted the change. Check the
> abort notification, errno and unchanged parent/rate in both cases.
> 
> Fixes: b2476490ef11 ("clk: introduce the common clock framework")
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> ---

Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-26 14:30 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-21 21:28 [PATCH] clk: send abort notifications when a parent change is vetoed James Hilliard
2026-10-26 14:30 ` Konrad Dybcio

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®