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