Skip to content

Commit 589a200

Browse files
mripardbebarino
authored andcommitted
clk: tests: Add tests for notifiers
We're recently encountered a regression due to the rates reported through the clk_notifier_data being off when changing parents. Let's add a test suite and a test to make sure that we do get notified and with the proper rates. Suggested-by: Stephen Boyd <sboyd@kernel.org> Signed-off-by: Maxime Ripard <maxime@cerno.tech> Link: https://lore.kernel.org/r/20221010-rpi-clk-fixes-again-v1-2-d87ba82ac404@cerno.tech Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 096f2a0 commit 589a200

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

drivers/clk/clk_test.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,10 +2239,166 @@ static struct kunit_suite clk_leaf_mux_set_rate_parent_test_suite = {
22392239
.test_cases = clk_leaf_mux_set_rate_parent_test_cases,
22402240
};
22412241

2242+
struct clk_mux_notifier_rate_change {
2243+
bool done;
2244+
unsigned long old_rate;
2245+
unsigned long new_rate;
2246+
wait_queue_head_t wq;
2247+
};
2248+
2249+
struct clk_mux_notifier_ctx {
2250+
struct clk_multiple_parent_ctx mux_ctx;
2251+
struct clk *clk;
2252+
struct notifier_block clk_nb;
2253+
struct clk_mux_notifier_rate_change pre_rate_change;
2254+
struct clk_mux_notifier_rate_change post_rate_change;
2255+
};
2256+
2257+
#define NOTIFIER_TIMEOUT_MS 100
2258+
2259+
static int clk_mux_notifier_callback(struct notifier_block *nb,
2260+
unsigned long action, void *data)
2261+
{
2262+
struct clk_notifier_data *clk_data = data;
2263+
struct clk_mux_notifier_ctx *ctx = container_of(nb,
2264+
struct clk_mux_notifier_ctx,
2265+
clk_nb);
2266+
2267+
if (action & PRE_RATE_CHANGE) {
2268+
ctx->pre_rate_change.old_rate = clk_data->old_rate;
2269+
ctx->pre_rate_change.new_rate = clk_data->new_rate;
2270+
ctx->pre_rate_change.done = true;
2271+
wake_up_interruptible(&ctx->pre_rate_change.wq);
2272+
}
2273+
2274+
if (action & POST_RATE_CHANGE) {
2275+
ctx->post_rate_change.old_rate = clk_data->old_rate;
2276+
ctx->post_rate_change.new_rate = clk_data->new_rate;
2277+
ctx->post_rate_change.done = true;
2278+
wake_up_interruptible(&ctx->post_rate_change.wq);
2279+
}
2280+
2281+
return 0;
2282+
}
2283+
2284+
static int clk_mux_notifier_test_init(struct kunit *test)
2285+
{
2286+
struct clk_mux_notifier_ctx *ctx;
2287+
const char *top_parents[2] = { "parent-0", "parent-1" };
2288+
int ret;
2289+
2290+
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2291+
if (!ctx)
2292+
return -ENOMEM;
2293+
test->priv = ctx;
2294+
ctx->clk_nb.notifier_call = clk_mux_notifier_callback;
2295+
init_waitqueue_head(&ctx->pre_rate_change.wq);
2296+
init_waitqueue_head(&ctx->post_rate_change.wq);
2297+
2298+
ctx->mux_ctx.parents_ctx[0].hw.init = CLK_HW_INIT_NO_PARENT("parent-0",
2299+
&clk_dummy_rate_ops,
2300+
0);
2301+
ctx->mux_ctx.parents_ctx[0].rate = DUMMY_CLOCK_RATE_1;
2302+
ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[0].hw);
2303+
if (ret)
2304+
return ret;
2305+
2306+
ctx->mux_ctx.parents_ctx[1].hw.init = CLK_HW_INIT_NO_PARENT("parent-1",
2307+
&clk_dummy_rate_ops,
2308+
0);
2309+
ctx->mux_ctx.parents_ctx[1].rate = DUMMY_CLOCK_RATE_2;
2310+
ret = clk_hw_register(NULL, &ctx->mux_ctx.parents_ctx[1].hw);
2311+
if (ret)
2312+
return ret;
2313+
2314+
ctx->mux_ctx.current_parent = 0;
2315+
ctx->mux_ctx.hw.init = CLK_HW_INIT_PARENTS("test-mux", top_parents,
2316+
&clk_multiple_parents_mux_ops,
2317+
0);
2318+
ret = clk_hw_register(NULL, &ctx->mux_ctx.hw);
2319+
if (ret)
2320+
return ret;
2321+
2322+
ctx->clk = clk_hw_get_clk(&ctx->mux_ctx.hw, NULL);
2323+
ret = clk_notifier_register(ctx->clk, &ctx->clk_nb);
2324+
if (ret)
2325+
return ret;
2326+
2327+
return 0;
2328+
}
2329+
2330+
static void clk_mux_notifier_test_exit(struct kunit *test)
2331+
{
2332+
struct clk_mux_notifier_ctx *ctx = test->priv;
2333+
struct clk *clk = ctx->clk;
2334+
2335+
clk_notifier_unregister(clk, &ctx->clk_nb);
2336+
clk_put(clk);
2337+
2338+
clk_hw_unregister(&ctx->mux_ctx.hw);
2339+
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[0].hw);
2340+
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[1].hw);
2341+
}
2342+
2343+
/*
2344+
* Test that if the we have a notifier registered on a mux, the core
2345+
* will notify us when we switch to another parent, and with the proper
2346+
* old and new rates.
2347+
*/
2348+
static void clk_mux_notifier_set_parent_test(struct kunit *test)
2349+
{
2350+
struct clk_mux_notifier_ctx *ctx = test->priv;
2351+
struct clk_hw *hw = &ctx->mux_ctx.hw;
2352+
struct clk *clk = clk_hw_get_clk(hw, NULL);
2353+
struct clk *new_parent = clk_hw_get_clk(&ctx->mux_ctx.parents_ctx[1].hw, NULL);
2354+
int ret;
2355+
2356+
ret = clk_set_parent(clk, new_parent);
2357+
KUNIT_ASSERT_EQ(test, ret, 0);
2358+
2359+
ret = wait_event_interruptible_timeout(ctx->pre_rate_change.wq,
2360+
ctx->pre_rate_change.done,
2361+
msecs_to_jiffies(NOTIFIER_TIMEOUT_MS));
2362+
KUNIT_ASSERT_GT(test, ret, 0);
2363+
2364+
KUNIT_EXPECT_EQ(test, ctx->pre_rate_change.old_rate, DUMMY_CLOCK_RATE_1);
2365+
KUNIT_EXPECT_EQ(test, ctx->pre_rate_change.new_rate, DUMMY_CLOCK_RATE_2);
2366+
2367+
ret = wait_event_interruptible_timeout(ctx->post_rate_change.wq,
2368+
ctx->post_rate_change.done,
2369+
msecs_to_jiffies(NOTIFIER_TIMEOUT_MS));
2370+
KUNIT_ASSERT_GT(test, ret, 0);
2371+
2372+
KUNIT_EXPECT_EQ(test, ctx->post_rate_change.old_rate, DUMMY_CLOCK_RATE_1);
2373+
KUNIT_EXPECT_EQ(test, ctx->post_rate_change.new_rate, DUMMY_CLOCK_RATE_2);
2374+
2375+
clk_put(new_parent);
2376+
clk_put(clk);
2377+
}
2378+
2379+
static struct kunit_case clk_mux_notifier_test_cases[] = {
2380+
KUNIT_CASE(clk_mux_notifier_set_parent_test),
2381+
{}
2382+
};
2383+
2384+
/*
2385+
* Test suite for a mux with multiple parents, and a notifier registered
2386+
* on the mux.
2387+
*
2388+
* These tests exercise the behaviour of notifiers.
2389+
*/
2390+
static struct kunit_suite clk_mux_notifier_test_suite = {
2391+
.name = "clk-mux-notifier",
2392+
.init = clk_mux_notifier_test_init,
2393+
.exit = clk_mux_notifier_test_exit,
2394+
.test_cases = clk_mux_notifier_test_cases,
2395+
};
2396+
22422397
kunit_test_suites(
22432398
&clk_leaf_mux_set_rate_parent_test_suite,
22442399
&clk_test_suite,
22452400
&clk_multiple_parents_mux_test_suite,
2401+
&clk_mux_notifier_test_suite,
22462402
&clk_orphan_transparent_multiple_parent_mux_test_suite,
22472403
&clk_orphan_transparent_single_parent_test_suite,
22482404
&clk_orphan_two_level_root_last_test_suite,

0 commit comments

Comments
 (0)