xref: /optee_os/core/include/kernel/spinlock.h (revision 23f867d38149c501891c441213b4d9f5ee9ee94e)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2016, Linaro Limited
5  */
6 
7 #ifndef __KERNEL_SPINLOCK_H
8 #define __KERNEL_SPINLOCK_H
9 
10 #define SPINLOCK_LOCK       1
11 #define SPINLOCK_UNLOCK     0
12 
13 #ifndef __ASSEMBLER__
14 #include <assert.h>
15 #include <compiler.h>
16 #include <stdbool.h>
17 #include <kernel/thread.h>
18 
19 #ifdef CFG_TEE_CORE_DEBUG
20 void spinlock_count_incr(void);
21 void spinlock_count_decr(void);
22 bool have_spinlock(void);
23 static inline void __nostackcheck assert_have_no_spinlock(void)
24 {
25 	assert(!have_spinlock());
26 }
27 #else
28 static inline void spinlock_count_incr(void) { }
29 static inline void spinlock_count_decr(void) { }
30 static inline void __nostackcheck assert_have_no_spinlock(void) { }
31 #endif
32 
33 void __cpu_spin_lock(unsigned int *lock);
34 void __cpu_spin_unlock(unsigned int *lock);
35 /* returns 0 on locking success, non zero on failure */
36 unsigned int __cpu_spin_trylock(unsigned int *lock);
37 
38 static inline void cpu_spin_lock_no_dldetect(unsigned int *lock)
39 {
40 	assert(thread_foreign_intr_disabled());
41 	__cpu_spin_lock(lock);
42 	spinlock_count_incr();
43 }
44 
45 #ifdef CFG_TEE_CORE_DEBUG
46 #define cpu_spin_lock(lock) \
47 	cpu_spin_lock_dldetect(__func__, __LINE__, lock)
48 
49 static inline void cpu_spin_lock_dldetect(const char *func, const int line,
50 					  unsigned int *lock)
51 {
52 	unsigned int retries = 0;
53 	unsigned int reminder = 0;
54 
55 	assert(thread_foreign_intr_disabled());
56 
57 	while (__cpu_spin_trylock(lock)) {
58 		retries++;
59 		if (!retries) {
60 			/* wrapped, time to report */
61 			trace_printf(func, line, TRACE_ERROR, true,
62 				     "possible spinlock deadlock reminder %u",
63 				      reminder);
64 			if (reminder < UINT_MAX)
65 				reminder++;
66 		}
67 	}
68 
69 	spinlock_count_incr();
70 }
71 #else
72 static inline void cpu_spin_lock(unsigned int *lock)
73 {
74 	cpu_spin_lock_no_dldetect(lock);
75 }
76 #endif
77 
78 static inline bool cpu_spin_trylock(unsigned int *lock)
79 {
80 	unsigned int rc;
81 
82 	assert(thread_foreign_intr_disabled());
83 	rc = __cpu_spin_trylock(lock);
84 	if (!rc)
85 		spinlock_count_incr();
86 	return !rc;
87 }
88 
89 static inline void cpu_spin_unlock(unsigned int *lock)
90 {
91 	assert(thread_foreign_intr_disabled());
92 	__cpu_spin_unlock(lock);
93 	spinlock_count_decr();
94 }
95 
96 static inline uint32_t __must_check
97 cpu_spin_lock_xsave_no_dldetect(unsigned int *lock)
98 {
99 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
100 
101 	cpu_spin_lock(lock);
102 	return exceptions;
103 }
104 
105 #ifdef CFG_TEE_CORE_DEBUG
106 #define cpu_spin_lock_xsave(lock) \
107 	cpu_spin_lock_xsave_dldetect(__func__, __LINE__, lock)
108 
109 static inline uint32_t __must_check
110 cpu_spin_lock_xsave_dldetect(const char *func, const int line,
111 			     unsigned int *lock)
112 {
113 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
114 
115 	cpu_spin_lock_dldetect(func, line, lock);
116 	return exceptions;
117 }
118 #else
119 static inline uint32_t __must_check cpu_spin_lock_xsave(unsigned int *lock)
120 {
121 	return cpu_spin_lock_xsave_no_dldetect(lock);
122 }
123 #endif
124 
125 static inline void cpu_spin_unlock_xrestore(unsigned int *lock,
126 					    uint32_t exceptions)
127 {
128 	cpu_spin_unlock(lock);
129 	thread_unmask_exceptions(exceptions);
130 }
131 #endif /* __ASSEMBLER__ */
132 
133 #endif /* __KERNEL_SPINLOCK_H */
134