1 /* Copyright (c) 2021 Intel Corporation.
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <zephyr/kernel.h>
6 #include <zephyr/kernel/smp.h>
7 #include <zephyr/ztest.h>
8 
9 /* Experimentally 10ms is enough time to get the second CPU to run on
10  * all known platforms.
11  */
12 #define CPU_START_DELAY 10000
13 
14 /* IPIs happen  much faster than CPU startup */
15 #define CPU_IPI_DELAY 2500
16 
17 BUILD_ASSERT(CONFIG_SMP);
18 BUILD_ASSERT(CONFIG_SMP_BOOT_DELAY);
19 BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS > 1);
20 
21 #define STACKSZ 2048
22 char stack[STACKSZ];
23 
24 volatile bool mp_flag;
25 
26 struct k_thread cpu_thr;
27 K_THREAD_STACK_DEFINE(thr_stack, STACKSZ);
28 
thread_fn(void * a,void * b,void * c)29 static void thread_fn(void *a, void *b, void *c)
30 {
31 	mp_flag = true;
32 }
33 
ZTEST(smp_boot_delay,test_smp_boot_delay)34 ZTEST(smp_boot_delay, test_smp_boot_delay)
35 {
36 	k_tid_t thr;
37 
38 	/* Create a thread of lower priority.  This could run on
39 	 * another CPU if it was available, but will not preempt us
40 	 * unless we block (which we do not).
41 	 */
42 	thr = k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
43 			      thread_fn, NULL, NULL, NULL,
44 			      1, 0, K_FOREVER);
45 	(void)k_thread_cpu_pin(thr, 1);
46 	k_thread_start(thr);
47 
48 	/* Make sure that thread has not run (because the cpu is halted) */
49 	k_busy_wait(CPU_START_DELAY);
50 	zassert_false(mp_flag, "CPU1 must not be running yet");
51 
52 	/* Start the second CPU */
53 	k_smp_cpu_start(1, NULL, NULL);
54 
55 	/* Verify the thread ran */
56 	k_busy_wait(CPU_START_DELAY);
57 	zassert_true(mp_flag, "CPU1 did not start");
58 
59 	k_thread_abort(&cpu_thr);
60 	k_thread_join(&cpu_thr, K_FOREVER);
61 
62 	/* Spawn the same thread to do the same thing, but this time
63 	 * expect that the thread is going to run synchronously on the
64 	 * other CPU as soon as its created.  Intended to test whether
65 	 * IPIs were correctly set up on the runtime-launched CPU.
66 	 */
67 	mp_flag = false;
68 	thr = k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
69 			      thread_fn, NULL, NULL, NULL,
70 			      1, 0, K_FOREVER);
71 	(void)k_thread_cpu_pin(thr, 1);
72 	k_thread_start(thr);
73 
74 	k_busy_wait(CPU_IPI_DELAY);
75 
76 	k_thread_abort(&cpu_thr);
77 	k_thread_join(&cpu_thr, K_FOREVER);
78 
79 	zassert_true(mp_flag, "CPU1 did not start thread via IPI");
80 }
81 
82 volatile bool custom_init_flag;
83 
custom_init_fn(void * arg)84 void custom_init_fn(void *arg)
85 {
86 	volatile bool *flag = (void *)arg;
87 
88 	*flag = true;
89 }
90 
ZTEST(smp_boot_delay,test_smp_custom_start)91 ZTEST(smp_boot_delay, test_smp_custom_start)
92 {
93 	k_tid_t thr;
94 
95 	if (CONFIG_MP_MAX_NUM_CPUS <= 2) {
96 		/* CPU#1 has been started in test_smp_boot_delay
97 		 * so we need another CPU for this test.
98 		 */
99 		ztest_test_skip();
100 	}
101 
102 	mp_flag = false;
103 	custom_init_flag = false;
104 
105 	/* Create a thread pinned on CPU#2 so that it will not
106 	 * run on other CPUs.
107 	 */
108 	thr = k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
109 			      thread_fn, NULL, NULL, NULL,
110 			      1, 0, K_FOREVER);
111 	(void)k_thread_cpu_pin(thr, 2);
112 	k_thread_start(thr);
113 
114 	/* Make sure that thread has not run (because the cpu is halted) */
115 	k_busy_wait(CPU_START_DELAY);
116 	zassert_false(mp_flag, "CPU2 must not be running yet");
117 
118 	/* Start the third CPU */
119 	k_smp_cpu_start(2, custom_init_fn, (void *)&custom_init_flag);
120 
121 	/* Verify the thread ran */
122 	k_busy_wait(CPU_START_DELAY);
123 	zassert_true(mp_flag, "CPU2 did not start");
124 
125 	/* Verify that the custom init function has been called. */
126 	zassert_true(custom_init_flag, "Custom init function has not been called.");
127 
128 	k_thread_abort(&cpu_thr);
129 	k_thread_join(&cpu_thr, K_FOREVER);
130 }
131 
132 
133 ZTEST_SUITE(smp_boot_delay, NULL, NULL, NULL, NULL, NULL);
134