@@ -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+
22422397kunit_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