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 45e8a8e6e3SMarouene Boubakri #ifdef CFG_TEE_CORE_DEBUG 46e8a8e6e3SMarouene Boubakri #define cpu_spin_lock(lock) \ 47e8a8e6e3SMarouene Boubakri cpu_spin_lock_dldetect(__func__, __LINE__, lock) 48e8a8e6e3SMarouene Boubakri 49e8a8e6e3SMarouene Boubakri static inline void cpu_spin_lock_dldetect(const char *func, const int line, 50e8a8e6e3SMarouene Boubakri unsigned int *lock) 51e8a8e6e3SMarouene Boubakri { 52e8a8e6e3SMarouene Boubakri unsigned int retries = 0; 53e8a8e6e3SMarouene Boubakri unsigned int reminder = 0; 54e8a8e6e3SMarouene Boubakri 55e8a8e6e3SMarouene Boubakri assert(thread_foreign_intr_disabled()); 56e8a8e6e3SMarouene Boubakri 57e8a8e6e3SMarouene Boubakri while (__cpu_spin_trylock(lock)) { 58e8a8e6e3SMarouene Boubakri retries++; 59e8a8e6e3SMarouene Boubakri if (!retries) { 60e8a8e6e3SMarouene Boubakri /* wrapped, time to report */ 61e8a8e6e3SMarouene Boubakri trace_printf(func, line, TRACE_ERROR, true, 62e8a8e6e3SMarouene Boubakri "possible spinlock deadlock reminder %u", 63e8a8e6e3SMarouene Boubakri reminder); 64e8a8e6e3SMarouene Boubakri if (reminder < UINT_MAX) 65e8a8e6e3SMarouene Boubakri reminder++; 66e8a8e6e3SMarouene Boubakri } 67e8a8e6e3SMarouene Boubakri } 68e8a8e6e3SMarouene Boubakri 69e8a8e6e3SMarouene Boubakri spinlock_count_incr(); 70e8a8e6e3SMarouene Boubakri } 71e8a8e6e3SMarouene Boubakri #else 72e8a8e6e3SMarouene Boubakri static inline void cpu_spin_lock(unsigned int *lock) 73e8a8e6e3SMarouene Boubakri { 74e8a8e6e3SMarouene Boubakri cpu_spin_lock_no_dldetect(lock); 75e8a8e6e3SMarouene Boubakri } 76e8a8e6e3SMarouene Boubakri #endif 77e8a8e6e3SMarouene Boubakri 78e8a8e6e3SMarouene Boubakri static inline bool cpu_spin_trylock(unsigned int *lock) 79e8a8e6e3SMarouene Boubakri { 80e8a8e6e3SMarouene Boubakri unsigned int rc; 81e8a8e6e3SMarouene Boubakri 82e8a8e6e3SMarouene Boubakri assert(thread_foreign_intr_disabled()); 83e8a8e6e3SMarouene Boubakri rc = __cpu_spin_trylock(lock); 84e8a8e6e3SMarouene Boubakri if (!rc) 85e8a8e6e3SMarouene Boubakri spinlock_count_incr(); 86e8a8e6e3SMarouene Boubakri return !rc; 87e8a8e6e3SMarouene Boubakri } 88e8a8e6e3SMarouene Boubakri 89e8a8e6e3SMarouene Boubakri static inline void cpu_spin_unlock(unsigned int *lock) 90e8a8e6e3SMarouene Boubakri { 91e8a8e6e3SMarouene Boubakri assert(thread_foreign_intr_disabled()); 92e8a8e6e3SMarouene Boubakri __cpu_spin_unlock(lock); 93e8a8e6e3SMarouene Boubakri spinlock_count_decr(); 94e8a8e6e3SMarouene Boubakri } 95e8a8e6e3SMarouene Boubakri 96*c4cdfb70SJens Wiklander static inline uint32_t __must_check 97*c4cdfb70SJens Wiklander cpu_spin_lock_xsave_no_dldetect(unsigned int *lock) 98e8a8e6e3SMarouene Boubakri { 99e8a8e6e3SMarouene Boubakri uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 100e8a8e6e3SMarouene Boubakri 101e8a8e6e3SMarouene Boubakri cpu_spin_lock(lock); 102e8a8e6e3SMarouene Boubakri return exceptions; 103e8a8e6e3SMarouene Boubakri } 104e8a8e6e3SMarouene Boubakri 105e8a8e6e3SMarouene Boubakri #ifdef CFG_TEE_CORE_DEBUG 106e8a8e6e3SMarouene Boubakri #define cpu_spin_lock_xsave(lock) \ 107e8a8e6e3SMarouene Boubakri cpu_spin_lock_xsave_dldetect(__func__, __LINE__, lock) 108e8a8e6e3SMarouene Boubakri 109*c4cdfb70SJens Wiklander static inline uint32_t __must_check 110*c4cdfb70SJens Wiklander cpu_spin_lock_xsave_dldetect(const char *func, const int line, 111e8a8e6e3SMarouene Boubakri unsigned int *lock) 112e8a8e6e3SMarouene Boubakri { 113e8a8e6e3SMarouene Boubakri uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 114e8a8e6e3SMarouene Boubakri 115e8a8e6e3SMarouene Boubakri cpu_spin_lock_dldetect(func, line, lock); 116e8a8e6e3SMarouene Boubakri return exceptions; 117e8a8e6e3SMarouene Boubakri } 118e8a8e6e3SMarouene Boubakri #else 119*c4cdfb70SJens Wiklander static inline uint32_t __must_check cpu_spin_lock_xsave(unsigned int *lock) 120e8a8e6e3SMarouene Boubakri { 121e8a8e6e3SMarouene Boubakri return cpu_spin_lock_xsave_no_dldetect(lock); 122e8a8e6e3SMarouene Boubakri } 123e8a8e6e3SMarouene Boubakri #endif 124e8a8e6e3SMarouene Boubakri 125e8a8e6e3SMarouene Boubakri static inline void cpu_spin_unlock_xrestore(unsigned int *lock, 126e8a8e6e3SMarouene Boubakri uint32_t exceptions) 127e8a8e6e3SMarouene Boubakri { 128e8a8e6e3SMarouene Boubakri cpu_spin_unlock(lock); 129e8a8e6e3SMarouene Boubakri thread_unmask_exceptions(exceptions); 130e8a8e6e3SMarouene Boubakri } 131e8a8e6e3SMarouene Boubakri #endif /* __ASSEMBLER__ */ 132e8a8e6e3SMarouene Boubakri 133d50fee03SEtienne Carriere #endif /* __KERNEL_SPINLOCK_H */ 134