Add a test case that uses the clk divider with the v2 rate negotiation
logic, plus the Lowest Common Multiple (LCM) to calculate the optimal
parent rate. The test ensures that the parent clk rate is set to a rate
that's acceptable to both children, and the sibling clock is not
affected.

The test in this commit use the following simplified clk tree with
the initial state:

                     parent
                     24 MHz
                    /      \
              child1        child2
              24 MHz        24 MHz

child1 and child2 both divider-only clocks that have CLK_SET_RATE_PARENT
set, and the parent is capable of achieving any rate.

child1 requests 32 MHz, and the tree ends up with the correct state:

                     parent
                     96 MHz
                    /      \
              child1        child2
              32 MHz        24 MHz

Link: https://lore.kernel.org/linux-clk/[email protected]/
Link: https://lpc.events/event/19/contributions/2152/
Signed-off-by: Brian Masney <[email protected]>
---
 drivers/clk/clk-divider_test.c | 54 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/clk/clk-divider_test.c b/drivers/clk/clk-divider_test.c
index 
95a55835a29065fede0426f1c15ec158e8a703c1..a16c04d5d8a86952b42750d326f88754fbc91eb7
 100644
--- a/drivers/clk/clk-divider_test.c
+++ b/drivers/clk/clk-divider_test.c
@@ -110,6 +110,18 @@ clk_rate_change_divider_test_lcm_ops_v1_params[] = {
 KUNIT_ARRAY_PARAM_DESC(clk_rate_change_divider_test_lcm_ops_v1,
                       clk_rate_change_divider_test_lcm_ops_v1_params, desc)
 
+static const struct clk_rate_change_divider_test_param
+clk_rate_change_divider_test_regular_ops_v2_params[] = {
+       {
+               .desc = "regular_ops_v2",
+               .ops = &clk_dummy_div_ops,
+               .extra_child_flags = CLK_V2_RATE_NEGOTIATION,
+       },
+};
+
+KUNIT_ARRAY_PARAM_DESC(clk_rate_change_divider_test_regular_ops_v2,
+                      clk_rate_change_divider_test_regular_ops_v2_params, desc)
+
 static int clk_rate_change_divider_test_init(struct kunit *test)
 {
        const struct clk_rate_change_divider_test_param *param = 
test->param_value;
@@ -196,6 +208,11 @@ static void clk_test_rate_change_divider_1(struct kunit 
*test)
        KUNIT_EXPECT_EQ(test, ctx->child2.div, 1);
 }
 
+static inline bool __clk_has_v2_negotiation(struct clk *clk)
+{
+       return clk_hw_get_flags(__clk_get_hw(clk)) & CLK_V2_RATE_NEGOTIATION;
+}
+
 /*
  * Test that, for a parent with two divider-only children with 
CLK_SET_RATE_PARENT
  * set and one requests a rate incompatible with the existing parent rate, the
@@ -265,6 +282,39 @@ static void clk_test_rate_change_divider_3_v1(struct kunit 
*test)
        KUNIT_EXPECT_EQ(test, ctx->child2.div, 1);
 }
 
+/*
+ * Test that, for a parent with two divider-only children with 
CLK_SET_RATE_PARENT
+ * set and one requests a rate incompatible with the existing parent rate, the
+ * sibling rate is not affected, and maintains it's rate when the v2 rate
+ * negotiation logic is used.
+ */
+static void clk_test_rate_change_divider_4_v2(struct kunit *test)
+{
+       struct clk_rate_change_divider_context *ctx = test->priv;
+       int ret;
+
+       KUNIT_ASSERT_EQ(test, clk_get_rate(ctx->parent_clk), 24 * HZ_PER_MHZ);
+       KUNIT_ASSERT_EQ(test, clk_get_rate(ctx->child1_clk), 24 * HZ_PER_MHZ);
+       KUNIT_EXPECT_EQ(test, ctx->child1.div, 1);
+       KUNIT_ASSERT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ);
+       KUNIT_EXPECT_EQ(test, ctx->child2.div, 1);
+       KUNIT_ASSERT_TRUE(test, __clk_has_v2_negotiation(ctx->child1_clk));
+       KUNIT_ASSERT_TRUE(test, __clk_has_v2_negotiation(ctx->child2_clk));
+
+       ret = clk_set_rate(ctx->child1_clk, 32 * HZ_PER_MHZ);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       /*
+        * With LCM-based parent + v2 rate changes, the parent should be at
+        * 96 MHz (LCM of 32 and 24), child1 at 32 MHz, and child2 at 24 MHz.
+        */
+       KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 96 * HZ_PER_MHZ);
+       KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 32 * HZ_PER_MHZ);
+       KUNIT_EXPECT_EQ(test, ctx->child1.div, 3);
+       KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ);
+       KUNIT_EXPECT_EQ(test, ctx->child2.div, 4);
+}
+
 static struct kunit_case clk_rate_change_divider_cases[] = {
        KUNIT_CASE_PARAM(clk_test_rate_change_divider_1,
                         clk_rate_change_divider_test_regular_ops_gen_params),
@@ -272,6 +322,10 @@ static struct kunit_case clk_rate_change_divider_cases[] = 
{
                         clk_rate_change_divider_test_regular_ops_gen_params),
        KUNIT_CASE_PARAM(clk_test_rate_change_divider_3_v1,
                         clk_rate_change_divider_test_lcm_ops_v1_gen_params),
+       KUNIT_CASE_PARAM(clk_test_rate_change_divider_1,
+                        
clk_rate_change_divider_test_regular_ops_v2_gen_params),
+       KUNIT_CASE_PARAM(clk_test_rate_change_divider_4_v2,
+                        
clk_rate_change_divider_test_regular_ops_v2_gen_params),
        {}
 };
 

-- 
2.53.0


Reply via email to