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