Skip to content

Commit 2e9cad1

Browse files
mripardbebarino
authored andcommitted
clk: tests: Add some tests for orphan with multiple parents
Let's leverage the dummy mux with multiple parents we have to create a mux whose default parent will never be registered, and thus will always be orphan by default. We can then create some tests to make sure that the clock API behaves properly in such a case, and that the transition to a non-orphan clock when we change the parent is done properly. Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com> # imx8mp Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> # exynos4210, meson g12b Signed-off-by: Maxime Ripard <maxime@cerno.tech> Link: https://lore.kernel.org/r/20220816112530.1837489-12-maxime@cerno.tech Tested-by: Linux Kernel Functional Testing <lkft@linaro.org> Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 74933ef commit 2e9cad1

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed

drivers/clk/clk_test.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,242 @@ clk_multiple_parents_mux_test_suite = {
480480
.test_cases = clk_multiple_parents_mux_test_cases,
481481
};
482482

483+
static int
484+
clk_orphan_transparent_multiple_parent_mux_test_init(struct kunit *test)
485+
{
486+
struct clk_multiple_parent_ctx *ctx;
487+
const char *parents[2] = { "missing-parent", "proper-parent"};
488+
int ret;
489+
490+
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
491+
if (!ctx)
492+
return -ENOMEM;
493+
test->priv = ctx;
494+
495+
ctx->parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("proper-parent",
496+
&clk_dummy_rate_ops,
497+
0);
498+
ctx->parents_ctx[1].rate = DUMMY_CLOCK_INIT_RATE;
499+
ret = clk_hw_register(NULL, &ctx->parents_ctx[1].hw);
500+
if (ret)
501+
return ret;
502+
503+
ctx->hw.init = CLK_HW_INIT_PARENTS("test-orphan-mux", parents,
504+
&clk_multiple_parents_mux_ops,
505+
CLK_SET_RATE_PARENT);
506+
ret = clk_hw_register(NULL, &ctx->hw);
507+
if (ret)
508+
return ret;
509+
510+
return 0;
511+
}
512+
513+
static void
514+
clk_orphan_transparent_multiple_parent_mux_test_exit(struct kunit *test)
515+
{
516+
struct clk_multiple_parent_ctx *ctx = test->priv;
517+
518+
clk_hw_unregister(&ctx->hw);
519+
clk_hw_unregister(&ctx->parents_ctx[1].hw);
520+
}
521+
522+
/*
523+
* Test that, for a mux whose current parent hasn't been registered yet and is
524+
* thus orphan, clk_get_parent() will return NULL.
525+
*/
526+
static void
527+
clk_test_orphan_transparent_multiple_parent_mux_get_parent(struct kunit *test)
528+
{
529+
struct clk_multiple_parent_ctx *ctx = test->priv;
530+
struct clk_hw *hw = &ctx->hw;
531+
struct clk *clk = clk_hw_get_clk(hw, NULL);
532+
533+
KUNIT_EXPECT_PTR_EQ(test, clk_get_parent(clk), NULL);
534+
535+
clk_put(clk);
536+
}
537+
538+
/*
539+
* Test that, for a mux whose current parent hasn't been registered yet,
540+
* calling clk_set_parent() to a valid parent will properly update the
541+
* mux parent and its orphan status.
542+
*/
543+
static void
544+
clk_test_orphan_transparent_multiple_parent_mux_set_parent(struct kunit *test)
545+
{
546+
struct clk_multiple_parent_ctx *ctx = test->priv;
547+
struct clk_hw *hw = &ctx->hw;
548+
struct clk *clk = clk_hw_get_clk(hw, NULL);
549+
struct clk *parent, *new_parent;
550+
int ret;
551+
552+
parent = clk_hw_get_clk(&ctx->parents_ctx[1].hw, NULL);
553+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
554+
555+
ret = clk_set_parent(clk, parent);
556+
KUNIT_ASSERT_EQ(test, ret, 0);
557+
558+
new_parent = clk_get_parent(clk);
559+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
560+
KUNIT_EXPECT_TRUE(test, clk_is_match(parent, new_parent));
561+
562+
clk_put(parent);
563+
clk_put(clk);
564+
}
565+
566+
/*
567+
* Test that, for a mux that started orphan but got switched to a valid
568+
* parent, the rate of the mux and its new parent are consistent.
569+
*/
570+
static void
571+
clk_test_orphan_transparent_multiple_parent_mux_set_parent_get_rate(struct kunit *test)
572+
{
573+
struct clk_multiple_parent_ctx *ctx = test->priv;
574+
struct clk_hw *hw = &ctx->hw;
575+
struct clk *clk = clk_hw_get_clk(hw, NULL);
576+
struct clk *parent;
577+
unsigned long parent_rate, rate;
578+
int ret;
579+
580+
parent = clk_hw_get_clk(&ctx->parents_ctx[1].hw, NULL);
581+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
582+
583+
parent_rate = clk_get_rate(parent);
584+
KUNIT_ASSERT_GT(test, parent_rate, 0);
585+
586+
ret = clk_set_parent(clk, parent);
587+
KUNIT_ASSERT_EQ(test, ret, 0);
588+
589+
rate = clk_get_rate(clk);
590+
KUNIT_ASSERT_GT(test, rate, 0);
591+
KUNIT_EXPECT_EQ(test, parent_rate, rate);
592+
593+
clk_put(parent);
594+
clk_put(clk);
595+
}
596+
597+
/*
598+
* Test that, for a mux that started orphan but got switched to a valid
599+
* parent, calling clk_set_rate_range() will affect the parent state if
600+
* its rate is out of range.
601+
*/
602+
static void
603+
clk_test_orphan_transparent_multiple_parent_mux_set_parent_set_range_modified(struct kunit *test)
604+
{
605+
struct clk_multiple_parent_ctx *ctx = test->priv;
606+
struct clk_hw *hw = &ctx->hw;
607+
struct clk *clk = clk_hw_get_clk(hw, NULL);
608+
struct clk *parent;
609+
unsigned long rate;
610+
int ret;
611+
612+
parent = clk_hw_get_clk(&ctx->parents_ctx[1].hw, NULL);
613+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
614+
615+
ret = clk_set_parent(clk, parent);
616+
KUNIT_ASSERT_EQ(test, ret, 0);
617+
618+
ret = clk_set_rate_range(clk, DUMMY_CLOCK_RATE_1, DUMMY_CLOCK_RATE_2);
619+
KUNIT_ASSERT_EQ(test, ret, 0);
620+
621+
rate = clk_get_rate(clk);
622+
KUNIT_ASSERT_GT(test, rate, 0);
623+
KUNIT_EXPECT_GE(test, rate, DUMMY_CLOCK_RATE_1);
624+
KUNIT_EXPECT_LE(test, rate, DUMMY_CLOCK_RATE_2);
625+
626+
clk_put(parent);
627+
clk_put(clk);
628+
}
629+
630+
/*
631+
* Test that, for a mux whose current parent hasn't been registered yet,
632+
* calling clk_set_rate_range() will succeed, and will be taken into
633+
* account when rounding a rate.
634+
*/
635+
static void
636+
clk_test_orphan_transparent_multiple_parent_mux_set_range_round_rate(struct kunit *test)
637+
{
638+
struct clk_multiple_parent_ctx *ctx = test->priv;
639+
struct clk_hw *hw = &ctx->hw;
640+
struct clk *clk = clk_hw_get_clk(hw, NULL);
641+
unsigned long rate;
642+
int ret;
643+
644+
ret = clk_set_rate_range(clk, DUMMY_CLOCK_RATE_1, DUMMY_CLOCK_RATE_2);
645+
KUNIT_ASSERT_EQ(test, ret, 0);
646+
647+
rate = clk_round_rate(clk, DUMMY_CLOCK_RATE_1 - 1000);
648+
KUNIT_ASSERT_GT(test, rate, 0);
649+
KUNIT_EXPECT_GE(test, rate, DUMMY_CLOCK_RATE_1);
650+
KUNIT_EXPECT_LE(test, rate, DUMMY_CLOCK_RATE_2);
651+
652+
clk_put(clk);
653+
}
654+
655+
/*
656+
* Test that, for a mux that started orphan, was assigned and rate and
657+
* then got switched to a valid parent, its rate is eventually within
658+
* range.
659+
*
660+
* FIXME: Even though we update the rate as part of clk_set_parent(), we
661+
* don't evaluate whether that new rate is within range and needs to be
662+
* adjusted.
663+
*/
664+
static void
665+
clk_test_orphan_transparent_multiple_parent_mux_set_range_set_parent_get_rate(struct kunit *test)
666+
{
667+
struct clk_multiple_parent_ctx *ctx = test->priv;
668+
struct clk_hw *hw = &ctx->hw;
669+
struct clk *clk = clk_hw_get_clk(hw, NULL);
670+
struct clk *parent;
671+
unsigned long rate;
672+
int ret;
673+
674+
kunit_skip(test, "This needs to be fixed in the core.");
675+
676+
clk_hw_set_rate_range(hw, DUMMY_CLOCK_RATE_1, DUMMY_CLOCK_RATE_2);
677+
678+
parent = clk_hw_get_clk(&ctx->parents_ctx[1].hw, NULL);
679+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
680+
681+
ret = clk_set_parent(clk, parent);
682+
KUNIT_ASSERT_EQ(test, ret, 0);
683+
684+
rate = clk_get_rate(clk);
685+
KUNIT_ASSERT_GT(test, rate, 0);
686+
KUNIT_EXPECT_GE(test, rate, DUMMY_CLOCK_RATE_1);
687+
KUNIT_EXPECT_LE(test, rate, DUMMY_CLOCK_RATE_2);
688+
689+
clk_put(parent);
690+
clk_put(clk);
691+
}
692+
693+
static struct kunit_case clk_orphan_transparent_multiple_parent_mux_test_cases[] = {
694+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_get_parent),
695+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_set_parent),
696+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_set_parent_get_rate),
697+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_set_parent_set_range_modified),
698+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_set_range_round_rate),
699+
KUNIT_CASE(clk_test_orphan_transparent_multiple_parent_mux_set_range_set_parent_get_rate),
700+
{}
701+
};
702+
703+
/*
704+
* Test suite for a basic mux clock with two parents. The default parent
705+
* isn't registered, only the second parent is. By default, the clock
706+
* will thus be orphan.
707+
*
708+
* These tests exercise the behaviour of the consumer API when dealing
709+
* with an orphan clock, and how we deal with the transition to a valid
710+
* parent.
711+
*/
712+
static struct kunit_suite clk_orphan_transparent_multiple_parent_mux_test_suite = {
713+
.name = "clk-orphan-transparent-multiple-parent-mux-test",
714+
.init = clk_orphan_transparent_multiple_parent_mux_test_init,
715+
.exit = clk_orphan_transparent_multiple_parent_mux_test_exit,
716+
.test_cases = clk_orphan_transparent_multiple_parent_mux_test_cases,
717+
};
718+
483719
struct clk_single_parent_ctx {
484720
struct clk_dummy_context parent_ctx;
485721
struct clk_hw hw;
@@ -1460,6 +1696,7 @@ static struct kunit_suite clk_range_minimize_test_suite = {
14601696
kunit_test_suites(
14611697
&clk_test_suite,
14621698
&clk_multiple_parents_mux_test_suite,
1699+
&clk_orphan_transparent_multiple_parent_mux_test_suite,
14631700
&clk_orphan_transparent_single_parent_test_suite,
14641701
&clk_range_test_suite,
14651702
&clk_range_maximize_test_suite,

0 commit comments

Comments
 (0)