* [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework
@ 2025-04-07 13:12 Brian Masney
2025-04-07 13:12 ` [PATCH 1/8] clk: test: introduce a few specific rate constants for mock testing Brian Masney
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Here's a series that introduces some clock provider kunit tests. These
tests are centered around inconsistencies and limitations in the clock
framework that may lead to some clocks unknowingly changing rates during
a rate change of their siblings.
The intent of the clock framework is to keep the siblings clock rate
stable during such an operation:
clk_set_rate(clk, MY_NEW_RATE);
However, it assumes that the sibling can generate that rate in the first
place. In many situations, it can't, and it leads to numerous bugs and
solutions over the years.
https://lore.kernel.org/lkml/20230825-pll-mipi_keep_rate-v1-0-35bc43570730@oltmanns.dev/
https://lore.kernel.org/linux-kernel/20230807-pll-mipi_set_rate_parent-v6-0-f173239a4b59@oltmanns.dev/
https://lore.kernel.org/all/20241114065759.3341908-1-victor.liu@nxp.com/
https://lore.kernel.org/linux-clk/20241121-ge-ian-debug-imx8-clk-tree-v1-0-0f1b722588fe@bootlin.com/
We intend to fix these issues, but first we need to agree and document
what these shortcomings are. These patches are meant to do that, even
though some will be skipped as they are currently broken.
Special thanks to Maxime Ripard for the guidance and feedback on this
project so far.
Brian Masney (8):
clk: test: introduce a few specific rate constants for mock testing
clk: test: introduce clk_dummy_div for a mock divider
clk: test: introduce test suite for sibling rate changes on a divider
clk: test: introduce clk_dummy_gate for a mock gate
clk: test: introduce test suite for sibling rate changes on a gate
clk: test: introduce helper to create a mock mux
clk: test: introduce test variation for sibling rate changes on a mux
clk: test: introduce test variation for sibling rate changes on a
gate/mux
drivers/clk/clk_test.c | 601 +++++++++++++++++++++++++++++++++++------
1 file changed, 513 insertions(+), 88 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/8] clk: test: introduce a few specific rate constants for mock testing
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 2/8] clk: test: introduce clk_dummy_div for a mock divider Brian Masney
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Some of the mock tests care about the relationship between two
different rates, and the specific numbers are important, such as for
mocking a divider.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index f08feeaa3750..1b34d54ec9c6 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -24,6 +24,10 @@ static const struct clk_ops empty_clk_ops = { };
#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000)
+#define DUMMY_CLOCK_RATE_6_MHZ (6 * 1000 * 1000)
+#define DUMMY_CLOCK_RATE_16_MHZ (16 * 1000 * 1000)
+#define DUMMY_CLOCK_RATE_24_MHZ (24 * 1000 * 1000)
+#define DUMMY_CLOCK_RATE_48_MHZ (48 * 1000 * 1000)
struct clk_dummy_context {
struct clk_hw hw;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/8] clk: test: introduce clk_dummy_div for a mock divider
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
2025-04-07 13:12 ` [PATCH 1/8] clk: test: introduce a few specific rate constants for mock testing Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 3/8] clk: test: introduce test suite for sibling rate changes on a divider Brian Masney
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
This is used to mock up a divider in the clk kunit tests.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 1b34d54ec9c6..4908fb9c0c46 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -140,6 +140,47 @@ static const struct clk_ops clk_dummy_single_parent_ops = {
.get_parent = clk_dummy_single_get_parent,
};
+// 4 ought to be enough for anybody
+#define CLK_DUMMY_DIV_WIDTH 4
+
+struct clk_dummy_div {
+ struct clk_hw hw;
+ unsigned int div;
+};
+
+static unsigned long clk_dummy_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_dummy_div *div = container_of(hw, struct clk_dummy_div, hw);
+
+ return divider_recalc_rate(hw, parent_rate, div->div, NULL,
+ CLK_DIVIDER_ROUND_CLOSEST, CLK_DUMMY_DIV_WIDTH);
+}
+
+static long clk_dummy_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return divider_round_rate(hw, rate, parent_rate, NULL,
+ CLK_DUMMY_DIV_WIDTH, CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int clk_dummy_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_dummy_div *div = container_of(hw, struct clk_dummy_div, hw);
+
+ div->div = divider_get_val(rate, parent_rate, NULL, CLK_DUMMY_DIV_WIDTH,
+ CLK_DIVIDER_ROUND_CLOSEST);
+
+ return 0;
+}
+
+static const struct clk_ops clk_dummy_div_ops = {
+ .recalc_rate = clk_dummy_div_recalc_rate,
+ .round_rate = clk_dummy_div_round_rate,
+ .set_rate = clk_dummy_div_set_rate,
+};
+
struct clk_multiple_parent_ctx {
struct clk_dummy_context parents_ctx[2];
struct clk_hw hw;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/8] clk: test: introduce test suite for sibling rate changes on a divider
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
2025-04-07 13:12 ` [PATCH 1/8] clk: test: introduce a few specific rate constants for mock testing Brian Masney
2025-04-07 13:12 ` [PATCH 2/8] clk: test: introduce clk_dummy_div for a mock divider Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 4/8] clk: test: introduce clk_dummy_gate for a mock gate Brian Masney
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Introduce a test suite that creates a parent with two divider-only
children, and ensure that changing the rate of one child does not
affect the rate of the sibling.
Some of the tests are disabled until the relevant issue(s) are fixed in
the clk core.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 135 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 4908fb9c0c46..7d4dd1a559db 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -653,6 +653,140 @@ clk_multiple_parents_mux_test_suite = {
.test_cases = clk_multiple_parents_mux_test_cases,
};
+struct clk_rate_change_sibling_div_div_context {
+ struct clk_dummy_context parent;
+ struct clk_dummy_div child1, child2;
+ struct clk *parent_clk, *child1_clk, *child2_clk;
+};
+
+static int clk_rate_change_sibling_div_div_test_init(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx;
+ int ret;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ test->priv = ctx;
+
+ ctx->parent.hw.init = CLK_HW_INIT_NO_PARENT("parent", &clk_dummy_rate_ops, 0);
+ ctx->parent.rate = DUMMY_CLOCK_RATE_24_MHZ;
+ ret = clk_hw_register_kunit(test, NULL, &ctx->parent.hw);
+ if (ret)
+ return ret;
+
+ ctx->child1.hw.init = CLK_HW_INIT_HW("child1", &ctx->parent.hw,
+ &clk_dummy_div_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child1.hw);
+ if (ret)
+ return ret;
+
+ ctx->child2.hw.init = CLK_HW_INIT_HW("child2", &ctx->parent.hw,
+ &clk_dummy_div_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child2.hw);
+ if (ret)
+ return ret;
+
+ ctx->parent_clk = clk_hw_get_clk(&ctx->parent.hw, NULL);
+ ctx->child1_clk = clk_hw_get_clk(&ctx->child1.hw, NULL);
+ ctx->child2_clk = clk_hw_get_clk(&ctx->child2.hw, NULL);
+
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_24_MHZ);
+
+ return 0;
+}
+
+static void clk_rate_change_sibling_div_div_test_exit(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx = test->priv;
+
+ clk_put(ctx->parent_clk);
+ clk_put(ctx->child1_clk);
+ clk_put(ctx->child2_clk);
+}
+
+/*
+ * Test that, for a parent with two divider-only children and one requests a
+ * rate compatible with the existing parent rate, the parent and sibling rates
+ * are not affected.
+ */
+static void clk_test_rate_change_sibling_div_div_1(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx = test->priv;
+ int ret;
+
+ ret = clk_set_rate(ctx->child1_clk, DUMMY_CLOCK_RATE_6_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_24_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), DUMMY_CLOCK_RATE_6_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+}
+
+/*
+ * Test that, for a parent with two divider-only children and one requests a
+ * rate incompatible with the existing parent rate, the sibling rate is not
+ * affected.
+ */
+static void clk_test_rate_change_sibling_div_div_2(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx = test->priv;
+ int ret;
+
+ kunit_skip(test, "This needs to be fixed in the core.");
+
+ ret = clk_set_rate(ctx->child1_clk, DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_GE(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+}
+
+/*
+ * Test that, for a parent with two divider-only children that request rates
+ * incompatible with the existing parent rate, both children end up with the
+ * requested rates.
+ */
+static void clk_test_rate_change_sibling_div_div_3(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_div_context *ctx = test->priv;
+ int ret;
+
+ kunit_skip(test, "This needs to be fixed in the core.");
+
+ ret = clk_set_rate(ctx->child1_clk, DUMMY_CLOCK_RATE_16_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = clk_set_rate(ctx->child2_clk, DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_GE(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), DUMMY_CLOCK_RATE_16_MHZ);
+}
+
+static struct kunit_case clk_rate_change_sibling_div_div_cases[] = {
+ KUNIT_CASE(clk_test_rate_change_sibling_div_div_1),
+ KUNIT_CASE(clk_test_rate_change_sibling_div_div_2),
+ KUNIT_CASE(clk_test_rate_change_sibling_div_div_3),
+ {}
+};
+
+/*
+ * Test suite that creates a parent with two divider-only children, and
+ * ensures that changing the rate of one child does not affect the rate
+ * of the other child.
+ */
+static struct kunit_suite clk_rate_change_sibling_div_div_test_suite = {
+ .name = "clk-rate-change-sibling-div-div",
+ .init = clk_rate_change_sibling_div_div_test_init,
+ .exit = clk_rate_change_sibling_div_div_test_exit,
+ .test_cases = clk_rate_change_sibling_div_div_cases,
+};
+
static int
clk_orphan_transparent_multiple_parent_mux_test_init(struct kunit *test)
{
@@ -3445,6 +3579,7 @@ kunit_test_suites(
&clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite,
&clk_multiple_parents_mux_test_suite,
+ &clk_rate_change_sibling_div_div_test_suite,
&clk_mux_no_reparent_test_suite,
&clk_mux_notifier_test_suite,
&clk_orphan_transparent_multiple_parent_mux_test_suite,
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/8] clk: test: introduce clk_dummy_gate for a mock gate
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (2 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 3/8] clk: test: introduce test suite for sibling rate changes on a divider Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 5/8] clk: test: introduce test suite for sibling rate changes on a gate Brian Masney
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
This is used to mock up a gate in the clk kunit tests.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 7d4dd1a559db..14ae88df5389 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -181,6 +181,40 @@ static const struct clk_ops clk_dummy_div_ops = {
.set_rate = clk_dummy_div_set_rate,
};
+struct clk_dummy_gate {
+ struct clk_hw hw;
+ bool enabled;
+};
+
+static int clk_dummy_gate_enable(struct clk_hw *hw)
+{
+ struct clk_dummy_gate *gate = container_of(hw, struct clk_dummy_gate, hw);
+
+ gate->enabled = true;
+
+ return 0;
+}
+
+static void clk_dummy_gate_disable(struct clk_hw *hw)
+{
+ struct clk_dummy_gate *gate = container_of(hw, struct clk_dummy_gate, hw);
+
+ gate->enabled = false;
+}
+
+static int clk_dummy_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_dummy_gate *gate = container_of(hw, struct clk_dummy_gate, hw);
+
+ return gate->enabled;
+}
+
+static const struct clk_ops clk_dummy_gate_ops = {
+ .enable = clk_dummy_gate_enable,
+ .disable = clk_dummy_gate_disable,
+ .is_enabled = clk_dummy_gate_is_enabled,
+};
+
struct clk_multiple_parent_ctx {
struct clk_dummy_context parents_ctx[2];
struct clk_hw hw;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/8] clk: test: introduce test suite for sibling rate changes on a gate
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (3 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 4/8] clk: test: introduce clk_dummy_gate for a mock gate Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 6/8] clk: test: introduce helper to create a mock mux Brian Masney
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Introduce a test suite that creates a parent with two children: a
divider and a gate. Ensure that changing the rate of one child does
not affect the rate of the gate.
Some of the tests are disabled until the relevant issue(s) are fixed in
the clk core. This is also implemented as a parameterized kunit test
since additional test variations will be added.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 156 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 156 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 14ae88df5389..df5d4b25aa69 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -821,6 +821,161 @@ static struct kunit_suite clk_rate_change_sibling_div_div_test_suite = {
.test_cases = clk_rate_change_sibling_div_div_cases,
};
+struct clk_test_rate_change_sibling_clk_ctx {
+ struct clk *parent_clk, *child1_clk, *child2_clk;
+};
+
+static void
+clk_test_rate_change_sibling_clk_ctx_put(struct clk_test_rate_change_sibling_clk_ctx *clk_ctx)
+{
+ clk_put(clk_ctx->parent_clk);
+ clk_put(clk_ctx->child1_clk);
+ clk_put(clk_ctx->child2_clk);
+}
+
+struct clk_rate_change_sibling_div_gate_sibling_context {
+ struct clk_dummy_context parent;
+ struct clk_dummy_div child1;
+ struct clk_dummy_gate child2;
+ struct clk_test_rate_change_sibling_clk_ctx clk_ctx;
+};
+
+static struct clk_test_rate_change_sibling_clk_ctx *
+clk_rate_change_sibling_div_gate_test_init(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_gate_sibling_context *ctx;
+ int ret;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+ test->priv = ctx;
+
+ ctx->parent.hw.init = CLK_HW_INIT_NO_PARENT("parent", &clk_dummy_rate_ops, 0);
+ ctx->parent.rate = DUMMY_CLOCK_RATE_24_MHZ;
+ ret = clk_hw_register_kunit(test, NULL, &ctx->parent.hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ctx->child1.hw.init = CLK_HW_INIT_HW("child1", &ctx->parent.hw,
+ &clk_dummy_div_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child1.hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ctx->child2.hw.init = CLK_HW_INIT_HW("child2", &ctx->parent.hw,
+ &clk_dummy_gate_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child2.hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ctx->clk_ctx.parent_clk = clk_hw_get_clk(&ctx->parent.hw, NULL);
+ ctx->clk_ctx.child1_clk = clk_hw_get_clk(&ctx->child1.hw, NULL);
+ ctx->clk_ctx.child2_clk = clk_hw_get_clk(&ctx->child2.hw, NULL);
+
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->clk_ctx.parent_clk),
+ DUMMY_CLOCK_RATE_24_MHZ);
+
+ return &ctx->clk_ctx;
+}
+
+struct clk_test_rate_change_sibling_test_case {
+ const char *desc;
+ struct clk_test_rate_change_sibling_clk_ctx *(*init)(struct kunit *test);
+};
+
+static struct clk_test_rate_change_sibling_test_case clk_test_rate_change_sibling_test_cases[] = {
+ {
+ .desc = "div_gate",
+ .init = clk_rate_change_sibling_div_gate_test_init,
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(clk_test_rate_change_sibling_test_case,
+ clk_test_rate_change_sibling_test_cases, desc);
+
+/*
+ * Test that, for a parent with two children and one requests a rate change that
+ * requires a change to the parent rate, the sibling rates are not affected.
+ */
+static void clk_test_rate_change_sibling_1(struct kunit *test)
+{
+ struct clk_test_rate_change_sibling_test_case *testcase =
+ (struct clk_test_rate_change_sibling_test_case *) test->param_value;
+ struct clk_test_rate_change_sibling_clk_ctx *ctx;
+ int ret;
+
+ kunit_skip(test, "This needs to be fixed in the core.");
+
+ ctx = testcase->init(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+
+ ret = clk_set_rate(ctx->child1_clk, DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_GE(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+
+ clk_test_rate_change_sibling_clk_ctx_put(ctx);
+}
+
+/*
+ * Test that, for a parent with two children where one requests an exclusive
+ * rate and the other requests a rate change that requires a change to the
+ * parent rate, the sibling rates are not affected.
+ */
+static void clk_test_rate_change_sibling_2(struct kunit *test)
+{
+ struct clk_test_rate_change_sibling_test_case *testcase =
+ (struct clk_test_rate_change_sibling_test_case *)(test->param_value);
+ struct clk_test_rate_change_sibling_clk_ctx *ctx;
+ int ret;
+
+ ctx = testcase->init(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ ret = clk_rate_exclusive_get(ctx->child2_clk);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+
+ ret = clk_set_rate(ctx->child1_clk, DUMMY_CLOCK_RATE_48_MHZ);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_GE(test, clk_get_rate(ctx->parent_clk), DUMMY_CLOCK_RATE_24_MHZ);
+ /* child1 is rounded to the closest supported rate */
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), DUMMY_CLOCK_RATE_24_MHZ);
+ KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), DUMMY_CLOCK_RATE_24_MHZ);
+
+ clk_rate_exclusive_put(ctx->child2_clk);
+
+ clk_test_rate_change_sibling_clk_ctx_put(ctx);
+}
+
+
+static struct kunit_case clk_rate_change_sibling_cases[] = {
+ KUNIT_CASE_PARAM(clk_test_rate_change_sibling_1,
+ clk_test_rate_change_sibling_test_case_gen_params),
+ KUNIT_CASE_PARAM(clk_test_rate_change_sibling_2,
+ clk_test_rate_change_sibling_test_case_gen_params),
+ {}
+};
+
+/*
+ * Test suite that creates a parent with two children: a gate and a mux.
+ * Ensure that changing the rate of one child does affect the rate of the
+ * other child.
+ */
+static struct kunit_suite clk_rate_change_sibling_test_suite = {
+ .name = "clk-rate-change-sibling",
+ .test_cases = clk_rate_change_sibling_cases,
+};
+
static int
clk_orphan_transparent_multiple_parent_mux_test_init(struct kunit *test)
{
@@ -3614,6 +3769,7 @@ kunit_test_suites(
&clk_test_suite,
&clk_multiple_parents_mux_test_suite,
&clk_rate_change_sibling_div_div_test_suite,
+ &clk_rate_change_sibling_test_suite,
&clk_mux_no_reparent_test_suite,
&clk_mux_notifier_test_suite,
&clk_orphan_transparent_multiple_parent_mux_test_suite,
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/8] clk: test: introduce helper to create a mock mux
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (4 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 5/8] clk: test: introduce test suite for sibling rate changes on a gate Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 7/8] clk: test: introduce test variation for sibling rate changes on a mux Brian Masney
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Introduce a helper to create a mock mux to reduce code duplication.
This also changes it so that the relevant clk_hws are registered with
the kunit framework.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 141 +++++++++++++++--------------------------
1 file changed, 52 insertions(+), 89 deletions(-)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index df5d4b25aa69..d72ce0226dc7 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -538,45 +538,64 @@ static struct kunit_suite clk_uncached_test_suite = {
.test_cases = clk_uncached_test_cases,
};
-static int
-clk_multiple_parents_mux_test_init(struct kunit *test)
-{
- struct clk_multiple_parent_ctx *ctx;
- const char *parents[2] = { "parent-0", "parent-1"};
+static int clk_init_multiple_parent_ctx(struct kunit *test,
+ struct clk_multiple_parent_ctx *ctx,
+ const char *parent0_name,
+ unsigned long parent0_rate,
+ const char *parent1_name,
+ unsigned long parent1_rate,
+ const char *mux_name, int mux_flags,
+ const struct clk_ops *mux_ops)
+{
+ const struct clk_hw *parents[2];
int ret;
- ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
- test->priv = ctx;
-
- ctx->parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT("parent-0",
+ ctx->parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT(parent0_name,
&clk_dummy_rate_ops,
0);
- ctx->parents_ctx[0].rate = DUMMY_CLOCK_RATE_1;
+ ctx->parents_ctx[0].rate = parent0_rate;
ret = clk_hw_register_kunit(test, NULL, &ctx->parents_ctx[0].hw);
if (ret)
return ret;
- ctx->parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("parent-1",
+ ctx->parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT(parent1_name,
&clk_dummy_rate_ops,
0);
- ctx->parents_ctx[1].rate = DUMMY_CLOCK_RATE_2;
+ ctx->parents_ctx[1].rate = parent1_rate;
ret = clk_hw_register_kunit(test, NULL, &ctx->parents_ctx[1].hw);
if (ret)
return ret;
- ctx->current_parent = 0;
- ctx->hw.init = CLK_HW_INIT_PARENTS("test-mux", parents,
- &clk_multiple_parents_mux_ops,
- CLK_SET_RATE_PARENT);
+ parents[0] = &ctx->parents_ctx[0].hw;
+ parents[1] = &ctx->parents_ctx[1].hw;
+ ctx->hw.init = CLK_HW_INIT_PARENTS_HW(mux_name, parents,
+ mux_ops, mux_flags);
ret = clk_hw_register_kunit(test, NULL, &ctx->hw);
if (ret)
return ret;
+ ctx->current_parent = 0;
+
return 0;
}
+static int
+clk_multiple_parents_mux_test_init(struct kunit *test)
+{
+ struct clk_multiple_parent_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ test->priv = ctx;
+
+ return clk_init_multiple_parent_ctx(test, ctx,
+ "parent-0", DUMMY_CLOCK_RATE_1,
+ "parent-1", DUMMY_CLOCK_RATE_2,
+ "test-mux", CLK_SET_RATE_PARENT,
+ &clk_multiple_parents_mux_ops);
+}
+
/*
* Test that for a clock with multiple parents, clk_get_parent()
* actually returns the current one.
@@ -2532,7 +2551,6 @@ static int
clk_leaf_mux_set_rate_parent_test_init(struct kunit *test)
{
struct clk_leaf_mux_ctx *ctx;
- const char *top_parents[2] = { "parent-0", "parent-1" };
int ret;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
@@ -2540,27 +2558,11 @@ clk_leaf_mux_set_rate_parent_test_init(struct kunit *test)
return -ENOMEM;
test->priv = ctx;
- ctx->mux_ctx.parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT("parent-0",
- &clk_dummy_rate_ops,
- 0);
- ctx->mux_ctx.parents_ctx[0].rate = DUMMY_CLOCK_RATE_1;
- ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[0].hw);
- if (ret)
- return ret;
-
- ctx->mux_ctx.parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("parent-1",
- &clk_dummy_rate_ops,
- 0);
- ctx->mux_ctx.parents_ctx[1].rate = DUMMY_CLOCK_RATE_2;
- ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[1].hw);
- if (ret)
- return ret;
-
- ctx->mux_ctx.current_parent = 0;
- ctx->mux_ctx.hw.init = CLK_HW_INIT_PARENTS("test-mux", top_parents,
- &clk_multiple_parents_mux_ops,
- 0);
- ret = clk_hw_register(NULL, &ctx->mux_ctx.hw);
+ ret = clk_init_multiple_parent_ctx(test, &ctx->mux_ctx,
+ "parent-0", DUMMY_CLOCK_RATE_1,
+ "parent-1", DUMMY_CLOCK_RATE_2,
+ "test-mux", 0,
+ &clk_multiple_parents_mux_ops);
if (ret)
return ret;
@@ -2748,7 +2750,6 @@ static int clk_mux_notifier_callback(struct notifier_block *nb,
static int clk_mux_notifier_test_init(struct kunit *test)
{
struct clk_mux_notifier_ctx *ctx;
- const char *top_parents[2] = { "parent-0", "parent-1" };
int ret;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
@@ -2759,27 +2760,11 @@ static int clk_mux_notifier_test_init(struct kunit *test)
init_waitqueue_head(&ctx->pre_rate_change.wq);
init_waitqueue_head(&ctx->post_rate_change.wq);
- ctx->mux_ctx.parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT("parent-0",
- &clk_dummy_rate_ops,
- 0);
- ctx->mux_ctx.parents_ctx[0].rate = DUMMY_CLOCK_RATE_1;
- ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[0].hw);
- if (ret)
- return ret;
-
- ctx->mux_ctx.parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("parent-1",
- &clk_dummy_rate_ops,
- 0);
- ctx->mux_ctx.parents_ctx[1].rate = DUMMY_CLOCK_RATE_2;
- ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[1].hw);
- if (ret)
- return ret;
-
- ctx->mux_ctx.current_parent = 0;
- ctx->mux_ctx.hw.init = CLK_HW_INIT_PARENTS("test-mux", top_parents,
- &clk_multiple_parents_mux_ops,
- 0);
- ret = clk_hw_register(NULL, &ctx->mux_ctx.hw);
+ ret = clk_init_multiple_parent_ctx(test, &ctx->mux_ctx,
+ "parent-0", DUMMY_CLOCK_RATE_1,
+ "parent-1", DUMMY_CLOCK_RATE_2,
+ "test-mux", 0,
+ &clk_multiple_parents_mux_ops);
if (ret)
return ret;
@@ -2862,39 +2847,17 @@ static int
clk_mux_no_reparent_test_init(struct kunit *test)
{
struct clk_multiple_parent_ctx *ctx;
- const char *parents[2] = { "parent-0", "parent-1"};
- int ret;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
test->priv = ctx;
- ctx->parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT("parent-0",
- &clk_dummy_rate_ops,
- 0);
- ctx->parents_ctx[0].rate = DUMMY_CLOCK_RATE_1;
- ret = clk_hw_register(NULL, &ctx->parents_ctx[0].hw);
- if (ret)
- return ret;
-
- ctx->parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("parent-1",
- &clk_dummy_rate_ops,
- 0);
- ctx->parents_ctx[1].rate = DUMMY_CLOCK_RATE_2;
- ret = clk_hw_register(NULL, &ctx->parents_ctx[1].hw);
- if (ret)
- return ret;
-
- ctx->current_parent = 0;
- ctx->hw.init = CLK_HW_INIT_PARENTS("test-mux", parents,
- &clk_multiple_parents_no_reparent_mux_ops,
- 0);
- ret = clk_hw_register(NULL, &ctx->hw);
- if (ret)
- return ret;
-
- return 0;
+ return clk_init_multiple_parent_ctx(test, ctx,
+ "parent-0", DUMMY_CLOCK_RATE_1,
+ "parent-1", DUMMY_CLOCK_RATE_2,
+ "test-mux", 0,
+ &clk_multiple_parents_no_reparent_mux_ops);
}
static void
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/8] clk: test: introduce test variation for sibling rate changes on a mux
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (5 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 6/8] clk: test: introduce helper to create a mock mux Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-04-07 13:12 ` [PATCH 8/8] clk: test: introduce test variation for sibling rate changes on a gate/mux Brian Masney
2025-05-28 23:22 ` [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Introduce a test variation that creates a parent with two children: a
divider and a mux. Ensure that changing the rate of the divider does not
affect the rate of the mux.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index d72ce0226dc7..97909caa71b2 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -900,6 +900,48 @@ clk_rate_change_sibling_div_gate_test_init(struct kunit *test)
return &ctx->clk_ctx;
}
+struct clk_rate_change_sibling_div_mux_sibling_context {
+ struct clk_dummy_div child1;
+ struct clk_multiple_parent_ctx child2_mux;
+ struct clk_test_rate_change_sibling_clk_ctx clk_ctx;
+};
+
+static struct clk_test_rate_change_sibling_clk_ctx *
+clk_rate_change_sibling_div_mux_test_init(struct kunit *test)
+{
+ struct clk_rate_change_sibling_div_mux_sibling_context *ctx;
+ int ret;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+ test->priv = ctx;
+
+ ret = clk_init_multiple_parent_ctx(test, &ctx->child2_mux,
+ "parent0", DUMMY_CLOCK_RATE_24_MHZ,
+ "parent1", DUMMY_CLOCK_RATE_48_MHZ,
+ "child2", CLK_SET_RATE_NO_REPARENT,
+ &clk_multiple_parents_mux_ops);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ctx->child1.hw.init = CLK_HW_INIT_HW("child1",
+ &ctx->child2_mux.parents_ctx[0].hw,
+ &clk_dummy_div_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child1.hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ctx->clk_ctx.parent_clk = clk_hw_get_clk(&ctx->child2_mux.parents_ctx[0].hw, NULL);
+ ctx->clk_ctx.child1_clk = clk_hw_get_clk(&ctx->child1.hw, NULL);
+ ctx->clk_ctx.child2_clk = clk_hw_get_clk(&ctx->child2_mux.hw, NULL);
+
+ return &ctx->clk_ctx;
+}
+
struct clk_test_rate_change_sibling_test_case {
const char *desc;
struct clk_test_rate_change_sibling_clk_ctx *(*init)(struct kunit *test);
@@ -910,6 +952,10 @@ static struct clk_test_rate_change_sibling_test_case clk_test_rate_change_siblin
.desc = "div_gate",
.init = clk_rate_change_sibling_div_gate_test_init,
},
+ {
+ .desc = "div_mux",
+ .init = clk_rate_change_sibling_div_mux_test_init,
+ },
};
KUNIT_ARRAY_PARAM_DESC(clk_test_rate_change_sibling_test_case,
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/8] clk: test: introduce test variation for sibling rate changes on a gate/mux
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (6 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 7/8] clk: test: introduce test variation for sibling rate changes on a mux Brian Masney
@ 2025-04-07 13:12 ` Brian Masney
2025-05-28 23:22 ` [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-04-07 13:12 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
Introduce a test variation that creates a parent with two children: a
gate and a mux. Ensure that changing the rate of the gate does not
affect the rate of the mux.
Signed-off-by: Brian Masney <bmasney@redhat.com>
---
drivers/clk/clk_test.c | 46 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 97909caa71b2..e6df1d2274b2 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -942,6 +942,48 @@ clk_rate_change_sibling_div_mux_test_init(struct kunit *test)
return &ctx->clk_ctx;
}
+struct clk_rate_change_sibling_gate_mux_sibling_context {
+ struct clk_dummy_gate child1;
+ struct clk_multiple_parent_ctx child2_mux;
+ struct clk_test_rate_change_sibling_clk_ctx clk_ctx;
+};
+
+static struct clk_test_rate_change_sibling_clk_ctx *
+clk_rate_change_sibling_gate_mux_test_init(struct kunit *test)
+{
+ struct clk_rate_change_sibling_gate_mux_sibling_context *ctx;
+ int ret;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+ test->priv = ctx;
+
+ ret = clk_init_multiple_parent_ctx(test, &ctx->child2_mux,
+ "parent0", DUMMY_CLOCK_RATE_24_MHZ,
+ "parent1", DUMMY_CLOCK_RATE_48_MHZ,
+ "child2", CLK_SET_RATE_NO_REPARENT,
+ &clk_multiple_parents_mux_ops);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ctx->child1.hw.init = CLK_HW_INIT_HW("child1",
+ &ctx->child2_mux.parents_ctx[0].hw,
+ &clk_dummy_gate_ops,
+ CLK_SET_RATE_PARENT);
+ ret = clk_hw_register_kunit(test, NULL, &ctx->child1.hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ctx->clk_ctx.parent_clk = clk_hw_get_clk(&ctx->child2_mux.parents_ctx[0].hw, NULL);
+ ctx->clk_ctx.child1_clk = clk_hw_get_clk(&ctx->child1.hw, NULL);
+ ctx->clk_ctx.child2_clk = clk_hw_get_clk(&ctx->child2_mux.hw, NULL);
+
+ return &ctx->clk_ctx;
+}
+
struct clk_test_rate_change_sibling_test_case {
const char *desc;
struct clk_test_rate_change_sibling_clk_ctx *(*init)(struct kunit *test);
@@ -956,6 +998,10 @@ static struct clk_test_rate_change_sibling_test_case clk_test_rate_change_siblin
.desc = "div_mux",
.init = clk_rate_change_sibling_div_mux_test_init,
},
+ {
+ .desc = "gate_mux",
+ .init = clk_rate_change_sibling_gate_mux_test_init,
+ },
};
KUNIT_ARRAY_PARAM_DESC(clk_test_rate_change_sibling_test_case,
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
` (7 preceding siblings ...)
2025-04-07 13:12 ` [PATCH 8/8] clk: test: introduce test variation for sibling rate changes on a gate/mux Brian Masney
@ 2025-05-28 23:22 ` Brian Masney
8 siblings, 0 replies; 10+ messages in thread
From: Brian Masney @ 2025-05-28 23:22 UTC (permalink / raw)
To: sboyd, mturquette; +Cc: linux-clk, linux-kernel, mripard
On Mon, Apr 07, 2025 at 09:12:50AM -0400, Brian Masney wrote:
> Here's a series that introduces some clock provider kunit tests. These
> tests are centered around inconsistencies and limitations in the clock
> framework that may lead to some clocks unknowingly changing rates during
> a rate change of their siblings.
I posted a v2 of this series with a new title for the cover letter. This
combines another series related to fixing an issue in the clk core.
https://lore.kernel.org/lkml/20250528-clk-wip-v2-v2-0-0d2c2f220442@redhat.com/T/#t
Brian
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-05-28 23:23 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-07 13:12 [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
2025-04-07 13:12 ` [PATCH 1/8] clk: test: introduce a few specific rate constants for mock testing Brian Masney
2025-04-07 13:12 ` [PATCH 2/8] clk: test: introduce clk_dummy_div for a mock divider Brian Masney
2025-04-07 13:12 ` [PATCH 3/8] clk: test: introduce test suite for sibling rate changes on a divider Brian Masney
2025-04-07 13:12 ` [PATCH 4/8] clk: test: introduce clk_dummy_gate for a mock gate Brian Masney
2025-04-07 13:12 ` [PATCH 5/8] clk: test: introduce test suite for sibling rate changes on a gate Brian Masney
2025-04-07 13:12 ` [PATCH 6/8] clk: test: introduce helper to create a mock mux Brian Masney
2025-04-07 13:12 ` [PATCH 7/8] clk: test: introduce test variation for sibling rate changes on a mux Brian Masney
2025-04-07 13:12 ` [PATCH 8/8] clk: test: introduce test variation for sibling rate changes on a gate/mux Brian Masney
2025-05-28 23:22 ` [PATCH 0/8] clk: test: add tests for inconsistencies and limitations in the framework Brian Masney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox