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