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);
assert_have_no_spinlock(void)23 static inline void __nostackcheck assert_have_no_spinlock(void)
24 {
25 assert(!have_spinlock());
26 }
27 #else
spinlock_count_incr(void)28 static inline void spinlock_count_incr(void) { }
spinlock_count_decr(void)29 static inline void spinlock_count_decr(void) { }
assert_have_no_spinlock(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
cpu_spin_lock_no_dldetect(unsigned int * lock)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
cpu_spin_lock_dldetect(const char * func,const int line,unsigned int * lock)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
cpu_spin_lock(unsigned int * lock)72 static inline void cpu_spin_lock(unsigned int *lock)
73 {
74 cpu_spin_lock_no_dldetect(lock);
75 }
76 #endif
77
78
cpu_spin_trylock(unsigned int * lock)79 static inline bool cpu_spin_trylock(unsigned int *lock)
80 {
81 unsigned int rc;
82
83 assert(thread_foreign_intr_disabled());
84 rc = __cpu_spin_trylock(lock);
85 if (!rc)
86 spinlock_count_incr();
87 return !rc;
88 }
89
cpu_spin_unlock(unsigned int * lock)90 static inline void cpu_spin_unlock(unsigned int *lock)
91 {
92 assert(thread_foreign_intr_disabled());
93 __cpu_spin_unlock(lock);
94 spinlock_count_decr();
95 }
96
cpu_spin_lock_xsave_no_dldetect(unsigned int * lock)97 static inline uint32_t 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
106 #ifdef CFG_TEE_CORE_DEBUG
107 #define cpu_spin_lock_xsave(lock) \
108 cpu_spin_lock_xsave_dldetect(__func__, __LINE__, lock)
109
cpu_spin_lock_xsave_dldetect(const char * func,const int line,unsigned int * lock)110 static inline uint32_t cpu_spin_lock_xsave_dldetect(const char *func,
111 const int line,
112 unsigned int *lock)
113 {
114 uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
115
116 cpu_spin_lock_dldetect(func, line, lock);
117 return exceptions;
118 }
119 #else
cpu_spin_lock_xsave(unsigned int * lock)120 static inline uint32_t cpu_spin_lock_xsave(unsigned int *lock)
121 {
122 return cpu_spin_lock_xsave_no_dldetect(lock);
123 }
124 #endif
125
cpu_spin_unlock_xrestore(unsigned int * lock,uint32_t exceptions)126 static inline void cpu_spin_unlock_xrestore(unsigned int *lock,
127 uint32_t exceptions)
128 {
129 cpu_spin_unlock(lock);
130 thread_unmask_exceptions(exceptions);
131 }
132 #endif /* __ASSEMBLER__ */
133
134 #endif /* KERNEL_SPINLOCK_H */
135