risc-v/up_testset: Implement test-and-set with AMOSWAP

It should be a bit more efficient to do compared to the LR/SC pair.
This commit is contained in:
Ville Juven
2024-11-07 12:11:21 +02:00
committed by archer
parent edc410f26f
commit 3146ea04b8
+11 -18
View File
@@ -72,10 +72,12 @@
* *
* RISC-V architecture (in the standard atomic-instruction extension "A") * RISC-V architecture (in the standard atomic-instruction extension "A")
* supports exclusive accesses to memory locations in the form of the * supports exclusive accesses to memory locations in the form of the
* Load-Reserved (LR) and Store-Conditional (SC) instructions. RV64 supports * Load-Reserved (LR), Store-Conditional (SC) and Atomic Memory Operations
* doubleword aligned data only but others supports word aligned data. * (AMO) instructions. For LR and SC, RV64 supports doubleword aligned data
* only but others supports word aligned data. For AMO, word and doubleword
* alignments are accepted.
* *
* RISC-V architecture supports fence instruction to ensure memory ordering * RISC-V architecture supports fence instruction to ensure memory ordering.
*/ */
typedef uintptr_t spinlock_t; typedef uintptr_t spinlock_t;
@@ -107,27 +109,18 @@ typedef uintptr_t spinlock_t;
#if defined(CONFIG_ARCH_RV_ISA_A) #if defined(CONFIG_ARCH_RV_ISA_A)
static inline_function spinlock_t up_testset(volatile spinlock_t *lock) static inline_function spinlock_t up_testset(volatile spinlock_t *lock)
{ {
spinlock_t ret = SP_UNLOCKED; spinlock_t ret = SP_LOCKED;
__asm__ __volatile__ __asm__ __volatile__
( (
"1: \n"
#ifdef CONFIG_ARCH_RV32 #ifdef CONFIG_ARCH_RV32
"lr.w %0, (%2) \n" "amoswap.w %0, %0, %1\n"
#else #else
"lr.d %0, (%2) \n" "amoswap.d %0, %0, %1\n"
#endif #endif
"beq %0, %1, 2f \n" "fence\n"
#ifdef CONFIG_ARCH_RV32 : "+r" (ret), "+A" (*lock)
"sc.w %0, %1, (%2) \n" :
#else
"sc.d %0, %1, (%2) \n"
#endif
"bnez %0, 1b \n"
"fence \n"
"2: \n"
: "+r" (ret)
: "r" (SP_LOCKED), "r" (lock)
: "memory" : "memory"
); );