Skip to content

Commit

Permalink
xtensa: add atomic and spinlock function with exclusive
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Allen-KH Cheng <[email protected]>
  • Loading branch information
Allen-kh Cheng authored and lgirdwood committed Sep 10, 2021
1 parent 1e8feb2 commit 83093da
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/arch/xtensa/include/arch/atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
102 changes: 102 additions & 0 deletions src/arch/xtensa/include/arch/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define __ARCH_SPINLOCK_H__

#include <stdint.h>
#include <xtensa/config/core-isa.h>

typedef struct {
volatile uint32_t lock;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions src/platform/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 83093da

Please sign in to comment.