[PATCH V9 11/15] riscv: Add qspinlock support

From: guoren
Date: Mon Aug 08 2022 - 03:16:05 EST


From: Guo Ren <guoren@xxxxxxxxxxxxxxxxx>

Enable qspinlock by the requirements mentioned in a8ad07e5240c9
("asm-generic: qspinlock: Indicate the use of mixed-size atomics").

- RISC-V atomic_*_release()/atomic_*_acquire() are implemented with
own relaxed version plus acquire/release_fence for RCsc
synchronization.

- RISC-V LR/SC pairs could provide a strong/weak forward guarantee
that depends on micro-architecture. And RISC-V ISA spec has given
out several limitations to let hardware support strict forward
guarantee (RISC-V User ISA - 8.3 Eventual Success of
Store-Conditional Instructions). Some riscv cores such as BOOMv3
& XiangShan could provide strict & strong forward guarantee (The
cache line would be kept in an exclusive state for Backoff cycles,
and only this core's interrupt could break the LR/SC pair).

- RISC-V provides cheap atomic_fetch_or_acquire() with RCsc.

- RISC-V only provides relaxed xchg16 to support qspinlock.

Signed-off-by: Guo Ren <guoren@xxxxxxxxxxxxxxxxx>
Signed-off-by: Guo Ren <guoren@xxxxxxxxxx>
---
arch/riscv/Kconfig | 16 ++++++++++++++++
arch/riscv/include/asm/Kbuild | 2 ++
arch/riscv/include/asm/cmpxchg.h | 24 ++++++++++++++++++++++++
3 files changed, 42 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c3ca23bc6352..8b36a4307d03 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -359,6 +359,22 @@ config NODES_SHIFT
Specify the maximum number of NUMA Nodes available on the target
system. Increases memory reserved to accommodate various tables.

+choice
+ prompt "RISC-V spinlock type"
+ default RISCV_TICKET_SPINLOCKS
+
+config RISCV_TICKET_SPINLOCKS
+ bool "Using ticket spinlock"
+
+config RISCV_QUEUED_SPINLOCKS
+ bool "Using queued spinlock"
+ depends on SMP && MMU
+ select ARCH_USE_QUEUED_SPINLOCKS
+ help
+ Make sure your micro arch LL/SC has a strong forward progress guarantee.
+ Otherwise, stay at ticket-lock.
+endchoice
+
config RISCV_ALTERNATIVE
bool
depends on !XIP_KERNEL
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index 504f8b7e72d4..2cce98c7b653 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -2,7 +2,9 @@
generic-y += early_ioremap.h
generic-y += flat.h
generic-y += kvm_para.h
+generic-y += mcs_spinlock.h
generic-y += parport.h
+generic-y += qspinlock.h
generic-y += spinlock.h
generic-y += spinlock_types.h
generic-y += qrwlock.h
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
index 4b5fa25f4336..2ba88057db52 100644
--- a/arch/riscv/include/asm/cmpxchg.h
+++ b/arch/riscv/include/asm/cmpxchg.h
@@ -11,12 +11,36 @@
#include <asm/barrier.h>
#include <asm/fence.h>

+static inline ulong __xchg16_relaxed(ulong new, void *ptr)
+{
+ ulong ret, tmp;
+ ulong shif = ((ulong)ptr & 2) ? 16 : 0;
+ ulong mask = 0xffff << shif;
+ ulong *__ptr = (ulong *)((ulong)ptr & ~2);
+
+ __asm__ __volatile__ (
+ "0: lr.w %0, %2\n"
+ " and %1, %0, %z3\n"
+ " or %1, %1, %z4\n"
+ " sc.w %1, %1, %2\n"
+ " bnez %1, 0b\n"
+ : "=&r" (ret), "=&r" (tmp), "+A" (*__ptr)
+ : "rJ" (~mask), "rJ" (new << shif)
+ : "memory");
+
+ return (ulong)((ret & mask) >> shif);
+}
+
#define __xchg_relaxed(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
__typeof__(*(ptr)) __ret; \
switch (size) { \
+ case 2: { \
+ __ret = (__typeof__(*(ptr))) \
+ __xchg16_relaxed((ulong)__new, __ptr); \
+ break;} \
case 4: \
__asm__ __volatile__ ( \
" amoswap.w %0, %2, %1\n" \
--
2.36.1