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 cpu_spin_lock_xsave_no_dldetect(unsigned int *lock) 97 { 98 uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 99 100 cpu_spin_lock(lock); 101 return exceptions; 102 } 103 104 #ifdef CFG_TEE_CORE_DEBUG 105 #define cpu_spin_lock_xsave(lock) \ 106 cpu_spin_lock_xsave_dldetect(__func__, __LINE__, lock) 107 108 static inline uint32_t cpu_spin_lock_xsave_dldetect(const char *func, 109 const int line, 110 unsigned int *lock) 111 { 112 uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 113 114 cpu_spin_lock_dldetect(func, line, lock); 115 return exceptions; 116 } 117 #else 118 static inline uint32_t cpu_spin_lock_xsave(unsigned int *lock) 119 { 120 return cpu_spin_lock_xsave_no_dldetect(lock); 121 } 122 #endif 123 124 static inline void cpu_spin_unlock_xrestore(unsigned int *lock, 125 uint32_t exceptions) 126 { 127 cpu_spin_unlock(lock); 128 thread_unmask_exceptions(exceptions); 129 } 130 #endif /* __ASSEMBLER__ */ 131 132 #endif /* KERNEL_SPINLOCK_H */ 133