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