1 /*
2  * Copyright (c) 2018,2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/ztest_test.h>
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/spinlock.h>
10 
11 BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS > 1);
12 
13 static struct k_spinlock lock;
14 static struct k_spinlock mylock;
15 static k_spinlock_key_t key;
16 
17 /* Like all spin locks in Zephyr (and things that directly hold them), this must
18  * be placed globally in code paths that intel_adsp runs to be valid. Even if
19  * only used in a local function context as is the case here when SPIN_VALIDATE
20  * and KERNEL_COHERENCE are enabled.
21  *
22  * When both are enabled a check to verify that a spin lock is placed
23  * in coherent (uncached) memory is done and asserted on. Spin locks placed
24  * on a stack will fail on platforms where KERNEL_COHERENCE is needed such
25  * as intel_adsp.
26  *
27  * See kernel/Kconfig KERNEL_COHERENCE and subsys/debug/Kconfig SPIN_VALIDATE
28  * for more details.
29  */
30 #ifdef CONFIG_SPIN_LOCK_TIME_LIMIT
31 	static struct k_spinlock timeout_lock;
32 #endif
33 
34 
35 static ZTEST_DMEM volatile bool valid_assert;
36 static ZTEST_DMEM volatile bool unlock_after_assert;
37 
38 
set_assert_valid(bool valid,bool unlock)39 static inline void set_assert_valid(bool valid, bool unlock)
40 {
41 	valid_assert = valid;
42 	unlock_after_assert = unlock;
43 }
44 
action_after_assert_fail(void)45 static void action_after_assert_fail(void)
46 {
47 	if (unlock_after_assert) {
48 		k_spin_unlock(&lock, key);
49 	}
50 
51 	ztest_test_pass();
52 }
53 
54 #ifdef CONFIG_ASSERT_NO_FILE_INFO
assert_post_action(void)55 void assert_post_action(void)
56 #else
57 void assert_post_action(const char *file, unsigned int line)
58 #endif
59 {
60 #ifndef CONFIG_ASSERT_NO_FILE_INFO
61 	ARG_UNUSED(file);
62 	ARG_UNUSED(line);
63 #endif
64 
65 	printk("Caught an assert.\n");
66 
67 	if (valid_assert) {
68 		valid_assert = false; /* reset back to normal */
69 		printk("Assert error expected as part of test case.\n");
70 
71 		/* do some action after fatal error happened */
72 		action_after_assert_fail();
73 	} else {
74 		printk("Assert failed was unexpected, aborting...\n");
75 #ifdef CONFIG_USERSPACE
76 	/* User threads aren't allowed to induce kernel panics; generate
77 	 * an oops instead.
78 	 */
79 		if (k_is_user_context()) {
80 			k_oops();
81 		}
82 #endif
83 		k_panic();
84 	}
85 }
86 
87 
88 /**
89  * @brief Test spinlock cannot be recursive
90  *
91  * @details Validate using spinlock recursive will trigger assertion.
92  *
93  * @ingroup kernel_spinlock_tests
94  *
95  * @see k_spin_lock()
96  */
ZTEST(spinlock,test_spinlock_no_recursive)97 ZTEST(spinlock, test_spinlock_no_recursive)
98 {
99 	k_spinlock_key_t re;
100 
101 	key = k_spin_lock(&lock);
102 
103 	set_assert_valid(true, true);
104 	re = k_spin_lock(&lock);
105 
106 	ztest_test_fail();
107 }
108 
109 /**
110  * @brief Test unlocking incorrect spinlock
111  *
112  * @details Validate unlocking incorrect spinlock will trigger assertion.
113  *
114  * @ingroup kernel_spinlock_tests
115  *
116  * @see k_spin_unlock()
117  */
ZTEST(spinlock,test_spinlock_unlock_error)118 ZTEST(spinlock, test_spinlock_unlock_error)
119 {
120 	key = k_spin_lock(&lock);
121 
122 	set_assert_valid(true, true);
123 	k_spin_unlock(&mylock, key);
124 
125 	ztest_test_fail();
126 }
127 
128 /**
129  * @brief Test unlocking incorrect spinlock
130  *
131  * @details Validate unlocking incorrect spinlock will trigger assertion.
132  *
133  * @ingroup kernel_spinlock_tests
134  *
135  * @see k_spin_release()
136  */
ZTEST(spinlock,test_spinlock_release_error)137 ZTEST(spinlock, test_spinlock_release_error)
138 {
139 	key = k_spin_lock(&lock);
140 
141 	set_assert_valid(true, true);
142 	k_spin_release(&mylock);
143 
144 	ztest_test_fail();
145 }
146 
147 
148 /**
149  * @brief Test unlocking spinlock held over the time limit
150  *
151  * @details Validate unlocking spinlock held past the time limit will trigger
152  * assertion.
153  *
154  * @ingroup kernel_spinlock_tests
155  *
156  * @see k_spin_unlock()
157  */
ZTEST(spinlock,test_spinlock_lock_time_limit)158 ZTEST(spinlock, test_spinlock_lock_time_limit)
159 {
160 #ifndef CONFIG_SPIN_LOCK_TIME_LIMIT
161 	ztest_test_skip();
162 	return;
163 #else
164 	if (CONFIG_SPIN_LOCK_TIME_LIMIT == 0) {
165 		ztest_test_skip();
166 		return;
167 	}
168 
169 
170 
171 	TC_PRINT("testing lock time limit, limit is %d!\n", CONFIG_SPIN_LOCK_TIME_LIMIT);
172 
173 
174 	key = k_spin_lock(&timeout_lock);
175 
176 	/* spin here a while, the spin lock limit is in terms of system clock
177 	 * not core clock. So a multiplier is needed here to ensure things
178 	 * go well past the time limit.
179 	 */
180 	for (volatile int i = 0; i < CONFIG_SPIN_LOCK_TIME_LIMIT*10; i++) {
181 	}
182 
183 	set_assert_valid(true, false);
184 	k_spin_unlock(&timeout_lock, key);
185 
186 	ztest_test_fail();
187 #endif
188 }
189