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 1000
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 /* Create a thread of lower priority. This could run on
37 * another CPU if it was available, but will not preempt us
38 * unless we block (which we do not).
39 */
40 k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
41 thread_fn, NULL, NULL, NULL,
42 1, 0, K_NO_WAIT);
43
44 /* Make sure that thread has not run (because the cpu is halted) */
45 k_busy_wait(CPU_START_DELAY);
46 zassert_false(mp_flag, "CPU1 must not be running yet");
47
48 /* Start the second CPU */
49 k_smp_cpu_start(1, NULL, NULL);
50
51 /* Verify the thread ran */
52 k_busy_wait(CPU_START_DELAY);
53 zassert_true(mp_flag, "CPU1 did not start");
54
55 k_thread_abort(&cpu_thr);
56 k_thread_join(&cpu_thr, K_FOREVER);
57
58 /* Spawn the same thread to do the same thing, but this time
59 * expect that the thread is going to run synchronously on the
60 * other CPU as soon as its created. Intended to test whether
61 * IPIs were correctly set up on the runtime-launched CPU.
62 */
63 mp_flag = false;
64 k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
65 thread_fn, NULL, NULL, NULL,
66 1, 0, K_NO_WAIT);
67
68 k_busy_wait(CPU_IPI_DELAY);
69
70 k_thread_abort(&cpu_thr);
71 k_thread_join(&cpu_thr, K_FOREVER);
72
73 zassert_true(mp_flag, "CPU1 did not start thread via IPI");
74 }
75
76 volatile bool custom_init_flag;
77
custom_init_fn(void * arg)78 void custom_init_fn(void *arg)
79 {
80 volatile bool *flag = (void *)arg;
81
82 *flag = true;
83 }
84
ZTEST(smp_boot_delay,test_smp_custom_start)85 ZTEST(smp_boot_delay, test_smp_custom_start)
86 {
87 k_tid_t thr;
88
89 if (CONFIG_MP_MAX_NUM_CPUS <= 2) {
90 /* CPU#1 has been started in test_smp_boot_delay
91 * so we need another CPU for this test.
92 */
93 ztest_test_skip();
94 }
95
96 mp_flag = false;
97 custom_init_flag = false;
98
99 /* Create a thread pinned on CPU#2 so that it will not
100 * run on other CPUs.
101 */
102 thr = k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack),
103 thread_fn, NULL, NULL, NULL,
104 1, 0, K_FOREVER);
105 (void)k_thread_cpu_pin(thr, 2);
106 k_thread_start(thr);
107
108 /* Make sure that thread has not run (because the cpu is halted) */
109 k_busy_wait(CPU_START_DELAY);
110 zassert_false(mp_flag, "CPU2 must not be running yet");
111
112 /* Start the third CPU */
113 k_smp_cpu_start(2, custom_init_fn, (void *)&custom_init_flag);
114
115 /* Verify the thread ran */
116 k_busy_wait(CPU_START_DELAY);
117 zassert_true(mp_flag, "CPU2 did not start");
118
119 /* Verify that the custom init function has been called. */
120 zassert_true(custom_init_flag, "Custom init function has not been called.");
121
122 k_thread_abort(&cpu_thr);
123 k_thread_join(&cpu_thr, K_FOREVER);
124 }
125
126
127 ZTEST_SUITE(smp_boot_delay, NULL, NULL, NULL, NULL, NULL);
128