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 <stdbool.h> 17e8a8e6e3SMarouene Boubakri #include <kernel/thread.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); 23e8a8e6e3SMarouene Boubakri static inline void __nostackcheck assert_have_no_spinlock(void) 24e8a8e6e3SMarouene Boubakri { 25e8a8e6e3SMarouene Boubakri assert(!have_spinlock()); 26e8a8e6e3SMarouene Boubakri } 27e8a8e6e3SMarouene Boubakri #else 28e8a8e6e3SMarouene Boubakri static inline void spinlock_count_incr(void) { } 29e8a8e6e3SMarouene Boubakri static inline void spinlock_count_decr(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 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 45*f6412fbdSEtienne Carriere static inline bool thread_spin_trylock(unsigned int *lock) 46*f6412fbdSEtienne Carriere { 47*f6412fbdSEtienne Carriere assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 48*f6412fbdSEtienne Carriere return !__cpu_spin_trylock(lock); 49*f6412fbdSEtienne Carriere } 50*f6412fbdSEtienne Carriere 51*f6412fbdSEtienne Carriere /* 52*f6412fbdSEtienne Carriere * To be used with lot of care: it is not recommended to spin in a thread 53*f6412fbdSEtienne Carriere * context without masking foreign interrupts 54*f6412fbdSEtienne Carriere */ 55*f6412fbdSEtienne Carriere static inline void thread_spin_lock(unsigned int *lock) 56*f6412fbdSEtienne Carriere { 57*f6412fbdSEtienne Carriere assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 58*f6412fbdSEtienne Carriere __cpu_spin_lock(lock); 59*f6412fbdSEtienne Carriere } 60*f6412fbdSEtienne Carriere 61*f6412fbdSEtienne Carriere static inline void thread_spin_unlock(unsigned int *lock) 62*f6412fbdSEtienne Carriere { 63*f6412fbdSEtienne Carriere assert(thread_get_id_may_fail() != THREAD_ID_INVALID); 64*f6412fbdSEtienne Carriere __cpu_spin_unlock(lock); 65*f6412fbdSEtienne Carriere } 66*f6412fbdSEtienne 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 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 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 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 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 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 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 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 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