diff --git a/src/arch/xtensa/include/arch/atomic.h b/src/arch/xtensa/include/arch/atomic.h index e66fbab25cf6..195a87fa5810 100644 --- a/src/arch/xtensa/include/arch/atomic.h +++ b/src/arch/xtensa/include/arch/atomic.h @@ -11,6 +11,10 @@ #define __ARCH_ATOMIC_H__ #include +#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ +#include +#endif +#include typedef struct { volatile int32_t value; @@ -31,6 +35,42 @@ static inline void arch_atomic_init(atomic_t *a, int32_t value) arch_atomic_set(a, value); } +#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ + +/* Use exclusive instructions */ +static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) +{ + /*reference xtos : xipc_misc.h*/ + int32_t result = 0; + int32_t current; + + while (!result) { + current = XT_L32EX((int32_t *)a); + result = current + value; + XT_S32EX(result, (int32_t *)a); + XT_GETEX(result); + } + return current; +} + +static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) +{ + /*reference xtos : xipc_misc.h*/ + int32_t current; + int32_t result = 0; + + while (!result) { + current = XT_L32EX((int *)a); + result = current - value; + XT_S32EX(result, (int *)a); + XT_GETEX(result); + } + return current; +} + +#elif XCHAL_HAVE_S32C1I + +/* Use S32C1I instructions */ static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) { int32_t result, current; @@ -65,6 +105,42 @@ static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) return current; } +#else + +#if CONFIG_CORE_COUNT > 1 + +#error No atomic ISA for SMP configuration + +#endif + +/* + * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. + * This helps support GCC and qemu emulation of certain targets. + */ + +/* integer arithmetic methods */ +static inline int32_t arch_atomic_add(atomic_t *a, int32_t value) +{ + int32_t result, current; + + current = arch_atomic_read(a); + result = current + value; + arch_atomic_set(a, result); + return current; +} + +static inline int32_t arch_atomic_sub(atomic_t *a, int32_t value) +{ + int32_t result, current; + + current = arch_atomic_read(a); + result = current - value; + arch_atomic_set(a, result); + return current; +} + +#endif /* XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ */ + #endif /* __ARCH_ATOMIC_H__ */ #else diff --git a/src/arch/xtensa/include/arch/spinlock.h b/src/arch/xtensa/include/arch/spinlock.h index 6d5687b28649..afb23479f864 100644 --- a/src/arch/xtensa/include/arch/spinlock.h +++ b/src/arch/xtensa/include/arch/spinlock.h @@ -11,6 +11,7 @@ #define __ARCH_SPINLOCK_H__ #include +#include typedef struct { volatile uint32_t lock; @@ -24,6 +25,44 @@ static inline void arch_spinlock_init(spinlock_t *lock) lock->lock = 0; } +#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ + +static inline void arch_spin_lock(spinlock_t *lock) +{ + uint32_t result; + + __asm__ __volatile__( + " movi %0, 0\n" + " l32ex %0, %1\n" + "1: movi %0, 1\n" + " s32ex %0, %1\n" + " getex %0\n" + " bnez %0, 1b\n" + : "=&a" (result) + : "a" (&lock->lock) + : "memory"); +} + +static inline int arch_try_lock(spinlock_t *lock) +{ + uint32_t result; + + __asm__ __volatile__( + " movi %0, 0\n" + " l32ex %0, %1\n" + " movi %0, 1\n" + " s32ex %0, %1\n" + " getex %0\n" + : "=&a" (result) + : "a" (&lock->lock) + : "memory"); + + /* return 0 for failed lock, 1 otherwise */ + return result ? 0 : 1; +} + +#elif XCHAL_HAVE_S32C1I + static inline void arch_spin_lock(spinlock_t *lock) { uint32_t result; @@ -60,6 +99,47 @@ static inline int arch_try_lock(spinlock_t *lock) return result ? 0 : 1; } +#else + +#if CONFIG_CORE_COUNT > 1 + +#error No atomic ISA for SMP configuration + +#endif /* CONFIG_CORE_COUNT > 1 */ + +/* + * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. + * This helps support GCC and qemu emulation of certain targets. + */ +static inline void arch_spin_lock(spinlock_t *lock) +{ + uint32_t result; + + do { + if (lock->lock == 0) { + lock->lock = 1; + result = 1; + } + } while (!result); +} + +static inline int arch_try_lock(spinlock_t *lock) +{ + uint32_t result; + + if (lock->lock == 0) { + lock->lock = 1; + result = 1; + } + + /* return 0 for failed lock, 1 otherwise */ + return result ? 0 : 1; +} + +#endif /* XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__ */ + +#if XCHAL_HAVE_EXCLUSIVE || XCHAL_HAVE_S32C1I + static inline void arch_spin_unlock(spinlock_t *lock) { uint32_t result; @@ -72,6 +152,28 @@ static inline void arch_spin_unlock(spinlock_t *lock) : "memory"); } +#else + +#if CONFIG_CORE_COUNT > 1 + +#error No atomic ISA for SMP configuration + +#endif /* CONFIG_CORE_COUNT > 1 */ + +/* + * The ISA has no atomic operations so use integer arithmetic on uniprocessor systems. + * This helps support GCC and qemu emulation of certain targets. + */ +static inline void arch_spin_unlock(spinlock_t *lock) +{ + uint32_t result; + + lock->lock = 0; + result = 1; +} + +#endif /* XCHAL_HAVE_EXCLUSIVE || XCHAL_HAVE_S32C1I */ + #endif /* __ARCH_SPINLOCK_H__ */ #else diff --git a/src/platform/Kconfig b/src/platform/Kconfig index 7ed63698e555..412964e26eba 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -458,4 +458,11 @@ config AGENT_PANIC_ON_DELAY If scheduler timing verification fails, SA will call a DSP panic. +config XTENSA_EXCLUSIVE + bool + default n + help + This has to be selected for xtensa exclusive instructions. + There is a definition for EXCLUSIVE option in xtensa-config.h + endmenu