xtensa: add atomic and spinlock function with exclusive

In mp_asm.S, if XCHAL_HAVE_EXCLUSIVE is defined,
it will use exclusive instructions,
else it will use s32c1i instructions.

It supports S32C1I and exclusive instruction in xthal_compare_and_set() API.
Refer to xtos-simc-mutex.c, xtos_mutex_p structure is similar to spinlock_t.

For dsp design, we cannot use s32c1i intrcutions in mt8195.

In order to not affect other platform, add CONFIG_XTENSA_EXCLUSIVE and __XCC__
compile options.

Signed-off-by: YC Hung <yc.hung@mediatek.com>
Signed-off-by: Allen-KH Cheng <allen-kh.cheng@mediatek.com>
This commit is contained in:
Allen-kh Cheng 2021-09-10 13:41:49 +08:00 committed by Liam Girdwood
parent 1e8feb2cf3
commit 83093dadea
3 changed files with 185 additions and 0 deletions

View File

@ -11,6 +11,10 @@
#define __ARCH_ATOMIC_H__
#include <stdint.h>
#if XCHAL_HAVE_EXCLUSIVE && CONFIG_XTENSA_EXCLUSIVE && __XCC__
#include <xtensa/tie/xt_core.h>
#endif
#include <xtensa/config/core-isa.h>
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

View File

@ -11,6 +11,7 @@
#define __ARCH_SPINLOCK_H__
#include <stdint.h>
#include <xtensa/config/core-isa.h>
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

View File

@ -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