* [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo
@ 2026-10-26 9:20 Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 1/2] riscv: build kernel atomics from LR/SC when Zaamo is disabled Vladimir Kondratiev
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Vladimir Kondratiev @ 2026-10-26 9:20 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Will Deacon, Peter Zijlstra, Mark Rutland, Gary Guo, Yury Norov,
Rasmus Villemoes, cfu, torvalds, olof, aleksa.paunovic, arikalo,
Boqun Feng, Boqun Feng
Cc: linux-riscv, linux-kernel, Vladimir.Kondratiev, Vladimir Kondratiev
RISC-V split the A extension into Zaamo (AMO*.w/AMO*.d) and Zalrsc
(LR/SC). Linux has so far required the whole A extension.
MIPS P8700 [1] implements only Zalrsc. AMO instructions are emulated by a
trap into SBI. I measured typical userspace atomics on this CPU: an
LR/SC atomic takes about 40 cycles, an AMO atomic about 600. The same
ratio applies to kernel refcounts, bitops, xchg and futexes, so the
kernel needs to emit LR/SC when Zaamo is not implemented.
Mobileye is going to use the "eyeq7h" platform, built on this CPU, for
ADAS and autonomous driving. Kernel atomics are on the scheduling,
memory-management and driver paths of that product, so the emulated
AMO cost is not acceptable there.
This series keeps today's default: both extensions on, -march still
contains "a", generated code is unchanged. Turning Zaamo off is a
NONPORTABLE choice. The resulting kernel matches one -march, which
userspace has to use as well, so a runtime alternative would not
produce a portable image.
Zalrsc stays mandatory. cmpxchg, conditional atomics and futex CAS are
already LR/SC sequences; Zaamo cannot replace them. BPF atomic ops
still emit AMO and remain unsupported on a Zalrsc-only kernel.
[1] https://mips.com/products/hardware/p8700/
Changes in v3:
- Make Zalrsc mandatory. cmpxchg and the conditional atomics already
use LR/SC, so RISCV_ISA_ZALRSC can no longer be turned off.
- Check AMO and LR/SC support independently. A kernel that emits both
requires "a", or both "zaamo" and "zalrsc".
- Put the LR/SC bitop sequence in its own block so two inlined
set_bit or clear_bit calls compile.
- Remove the LR/SC loop that ran after the hart lottery and accessed
address 1. Build the lottery increment with add so RV32 assembles.
- Add an exception-table entry for sc as well as lr in the futex
LR/SC helper.
Changes in v2:
- Switch from a runtime choice of atomic implementation to a
compile-time one, gated by NONPORTABLE.
Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
---
Vladimir Kondratiev (2):
riscv: build kernel atomics from LR/SC when Zaamo is disabled
riscv: accept the atomic extensions this kernel was built with
arch/riscv/Kconfig | 23 +++++++++++++++++
arch/riscv/Makefile | 15 ++++++++---
arch/riscv/include/asm/atomic.h | 56 +++++++++++++++++++++++++++++++++++++++-
arch/riscv/include/asm/bitops.h | 51 ++++++++++++++++++++++++++++++++++++
arch/riscv/include/asm/cmpxchg.h | 18 +++++++++++++
arch/riscv/include/asm/futex.h | 53 +++++++++++++++++++++++++++++++++++++
arch/riscv/kernel/cpu.c | 28 +++++++++++++++++---
arch/riscv/kernel/entry.S | 9 +++++++
arch/riscv/kernel/head.S | 14 ++++++++++
9 files changed, 258 insertions(+), 9 deletions(-)
---
base-commit: c03c1a14507dfaf8b856c2608f9ac216021fc222
change-id: 20260120-lrsc-only-cc06422f5bb1
Best regards,
--
Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/2] riscv: build kernel atomics from LR/SC when Zaamo is disabled
2026-10-26 9:20 [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Vladimir Kondratiev
@ 2026-10-26 9:20 ` Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 2/2] riscv: accept the atomic extensions this kernel was built with Vladimir Kondratiev
2026-10-26 10:30 ` [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Peter Zijlstra
2 siblings, 0 replies; 5+ messages in thread
From: Vladimir Kondratiev @ 2026-10-26 9:20 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Will Deacon, Peter Zijlstra, Mark Rutland, Gary Guo, Yury Norov,
Rasmus Villemoes, cfu, torvalds, olof, aleksa.paunovic, arikalo,
Boqun Feng, Boqun Feng
Cc: linux-riscv, linux-kernel, Vladimir.Kondratiev, Vladimir Kondratiev
The A extension is Zaamo plus Zalrsc. MIPS P8700 implements only
Zalrsc, and its AMO instructions trap to SBI. A typical atomic is
about 40 cycles with LR/SC and about 600 cycles with an emulated AMO,
so keep the existing AMO sequences when the toolchain defines
__riscv_zaamo or __riscv_atomic, and use an LR/SC loop otherwise.
Add RISCV_ISA_ZAAMO and RISCV_ISA_ZALRSC. Both default on, and that
selection still passes "a" in -march. Zaamo can be turned off only
with CONFIG_NONPORTABLE; Zalrsc remains required because cmpxchg and
the conditional atomics are LR/SC sequences. An LR/SC-only build
passes _zalrsc instead of "a".
Suggested-by: Chao-ying Fu <cfu@wavecomp.com>
Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
---
arch/riscv/Kconfig | 23 +++++++++++++++++
arch/riscv/Makefile | 15 ++++++++---
arch/riscv/include/asm/atomic.h | 56 +++++++++++++++++++++++++++++++++++++++-
arch/riscv/include/asm/bitops.h | 51 ++++++++++++++++++++++++++++++++++++
arch/riscv/include/asm/cmpxchg.h | 18 +++++++++++++
arch/riscv/include/asm/futex.h | 53 +++++++++++++++++++++++++++++++++++++
arch/riscv/kernel/entry.S | 9 +++++++
arch/riscv/kernel/head.S | 14 ++++++++++
8 files changed, 234 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 5874ca30f4f6..1403445482b9 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -730,6 +730,29 @@ config RISCV_ISA_ZACAS
If you don't know what to do here, say Y.
+config RISCV_ISA_ZAAMO
+ bool "Zaamo extension support for AMO atomics" if NONPORTABLE
+ default y
+ help
+ Use AMO instructions for kernel atomic memory operations. When
+ disabled, those operations are built from LR/SC and the kernel
+ is compiled with zalrsc instead of the A extension.
+
+ Disable this only for a hart that implements Zalrsc but not
+ Zaamo, such as the MIPS P8700. The resulting kernel cannot run
+ on a hart without LR/SC.
+
+ If you don't know what to do here, say Y.
+
+config RISCV_ISA_ZALRSC
+ def_bool y
+ help
+ Zalrsc provides LR/SC. cmpxchg and the conditional atomics
+ require it, so it is always enabled.
+
+config RISCV_ISA_A
+ def_bool RISCV_ISA_ZAAMO && RISCV_ISA_ZALRSC
+
config TOOLCHAIN_HAS_ZBB
bool
default y
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 44f5a439741a..23ecf68a761d 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -58,8 +58,9 @@ ifeq ($(CONFIG_SHADOW_CALL_STACK),y)
endif
# ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I) := rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I) := rv64ima
+riscv-march-$(CONFIG_ARCH_RV32I) := rv32im
+riscv-march-$(CONFIG_ARCH_RV64I) := rv64im
+riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a
riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd
riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c
riscv-march-$(CONFIG_RISCV_ISA_V) := $(riscv-march-y)v
@@ -75,9 +76,15 @@ else
riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei
endif
-KBUILD_BASE_ISA = -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)fd([^v_]*)v?/\1\2/')
+KBUILD_BASE_ISA = -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima?|rv64ima?)fd([^v_]*)v?/\1\2/')
export KBUILD_BASE_ISA
+# if "A" not supported, toolchain shall support zaamo/zalrsc
+ifneq ($(CONFIG_RISCV_ISA_A),y)
+riscv-march-$(CONFIG_RISCV_ISA_ZAAMO) := $(riscv-march-y)_zaamo
+riscv-march-$(CONFIG_RISCV_ISA_ZALRSC) := $(riscv-march-y)_zalrsc
+endif
+
# Remove F,D,V from isa string for all. Keep extensions between "fd" and "v" by
# matching non-v and non-multi-letter extensions out with the filter ([^v_]*)
KBUILD_CFLAGS += $(KBUILD_BASE_ISA)
@@ -85,7 +92,7 @@ KBUILD_CFLAGS += $(KBUILD_BASE_ISA)
KBUILD_AFLAGS += -march=$(riscv-march-y)
# For C code built with floating-point support, exclude V but keep F and D.
-CC_FLAGS_FPU := -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)([^v_]*)v?/\1\2/')
+CC_FLAGS_FPU := -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima?|rv64ima?)([^v_]*)v?/\1\2/')
KBUILD_CFLAGS += -mno-save-restore
diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h
index 616b8b332ac5..dc6a8c95c975 100644
--- a/arch/riscv/include/asm/atomic.h
+++ b/arch/riscv/include/asm/atomic.h
@@ -50,6 +50,7 @@ static __always_inline void arch_atomic64_set(atomic64_t *v, s64 i)
* have the AQ or RL bits set. These don't return anything, so there's only
* one version to worry about.
*/
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \
static __always_inline \
void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
@@ -59,7 +60,25 @@ void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
: "+A" (v->counter) \
: "r" (I) \
: "memory"); \
-} \
+}
+#elif defined(__riscv_zalrsc)
+#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \
+static __always_inline \
+void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
+{ \
+ register c_type ret, temp; \
+ __asm__ __volatile__ ( \
+ "1: lr." #asm_type " %1, %0\n" \
+ " " #asm_op " %2, %1, %3\n" \
+ " sc." #asm_type " %2, %2, %0\n" \
+ " bnez %2, 1b\n" \
+ : "+A" (v->counter), "=&r" (ret), "=&r" (temp) \
+ : "r" (I) \
+ : "memory"); \
+}
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
#ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, I) \
@@ -84,6 +103,7 @@ ATOMIC_OPS(xor, xor, i)
* There's two flavors of these: the arithmetic ops have both fetch and return
* versions, while the logical ops only have fetch versions.
*/
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
#define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix) \
static __always_inline \
c_type arch_atomic##prefix##_fetch_##op##_relaxed(c_type i, \
@@ -108,6 +128,40 @@ c_type arch_atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v) \
: "memory"); \
return ret; \
}
+#elif defined(__riscv_zalrsc)
+#define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix) \
+static __always_inline \
+c_type arch_atomic##prefix##_fetch_##op##_relaxed(c_type i, \
+ atomic##prefix##_t *v) \
+{ \
+ register c_type ret, temp; \
+ __asm__ __volatile__ ( \
+ "1: lr." #asm_type " %1, %0\n" \
+ " " #asm_op " %2, %1, %3\n" \
+ " sc." #asm_type " %2, %2, %0\n" \
+ " bnez %2, 1b\n" \
+ : "+A" (v->counter), "=&r" (ret), "=&r" (temp) \
+ : "r" (I) \
+ : "memory"); \
+ return ret; \
+} \
+static __always_inline \
+c_type arch_atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v) \
+{ \
+ register c_type ret, temp; \
+ __asm__ __volatile__ ( \
+ "1: lr." #asm_type ".aqrl %1, %0\n" \
+ " " #asm_op " %2, %1, %3\n" \
+ " sc." #asm_type ".aqrl %2, %2, %0\n" \
+ " bnez %2, 1b\n" \
+ : "+A" (v->counter), "=&r" (ret), "=&r" (temp) \
+ : "r" (I) \
+ : "memory"); \
+ return ret; \
+}
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_type, c_type, prefix) \
static __always_inline \
diff --git a/arch/riscv/include/asm/bitops.h b/arch/riscv/include/asm/bitops.h
index 3c1a15be54d8..311547558ff5 100644
--- a/arch/riscv/include/asm/bitops.h
+++ b/arch/riscv/include/asm/bitops.h
@@ -170,12 +170,17 @@ static __always_inline int variable_fls(unsigned int x)
#if (BITS_PER_LONG == 64)
#define __AMO(op) "amo" #op ".d"
+#define __LR "lr.d"
+#define __SC "sc.d"
#elif (BITS_PER_LONG == 32)
#define __AMO(op) "amo" #op ".w"
+#define __LR "lr.w"
+#define __SC "sc.w"
#else
#error "Unexpected BITS_PER_LONG"
#endif
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
#define __test_and_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
@@ -194,6 +199,37 @@ static __always_inline int variable_fls(unsigned int x)
: "+A" (addr[BIT_WORD(nr)]) \
: "r" (mod(BIT_MASK(nr))) \
: "memory");
+#elif defined(__riscv_zalrsc)
+#define __test_and_op_bit_ord(op, mod, nr, addr, ord) \
+({ \
+ unsigned long __res, __mask, __temp; \
+ __mask = BIT_MASK(nr); \
+ __asm__ __volatile__ ( \
+ "1: " __LR #ord " %0, %1\n" \
+ #op " %2, %0, %3\n" \
+ __SC #ord " %2, %2, %1\n" \
+ "bnez %2, 1b\n" \
+ : "=&r" (__res), "+A" (addr[BIT_WORD(nr)]), "=&r" (__temp) \
+ : "r" (mod(__mask)) \
+ : "memory"); \
+ ((__res & __mask) != 0); \
+})
+
+#define __op_bit_ord(op, mod, nr, addr, ord) \
+do { \
+ unsigned long __res, __temp; \
+ __asm__ __volatile__ ( \
+ "1: " __LR #ord " %0, %1\n" \
+ #op " %2, %0, %3\n" \
+ __SC #ord " %2, %2, %1\n" \
+ "bnez %2, 1b\n" \
+ : "=&r" (__res), "+A" (addr[BIT_WORD(nr)]), "=&r" (__temp) \
+ : "r" (mod(BIT_MASK(nr))) \
+ : "memory"); \
+} while (0)
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
#define __test_and_op_bit(op, mod, nr, addr) \
__test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
@@ -337,12 +373,27 @@ static __always_inline void arch___clear_bit_unlock(
static __always_inline bool arch_xor_unlock_is_negative_byte(unsigned long mask,
volatile unsigned long *addr)
{
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
unsigned long res;
__asm__ __volatile__ (
__AMO(xor) ".rl %0, %2, %1"
: "=r" (res), "+A" (*addr)
: "r" (__NOP(mask))
: "memory");
+#elif defined(__riscv_zalrsc)
+ unsigned long res, temp;
+
+ __asm__ __volatile__ (
+ "1: " __LR ".rl %0, %1\n"
+ "xor %2, %0, %3\n"
+ __SC ".rl %2, %2, %1\n"
+ "bnez %2, 1b\n"
+ : "=&r" (res), "+A" (*addr), "=&r" (temp)
+ : "r" (__NOP(mask))
+ : "memory");
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
return (res & BIT(7)) != 0;
}
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
index 662e160b0522..0399c5b4ef35 100644
--- a/arch/riscv/include/asm/cmpxchg.h
+++ b/arch/riscv/include/asm/cmpxchg.h
@@ -57,6 +57,7 @@
} \
})
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
#define __arch_xchg(sfx, prepend, append, r, p, n) \
({ \
__asm__ __volatile__ ( \
@@ -67,6 +68,23 @@
: "r" (n) \
: "memory"); \
})
+#elif defined(__riscv_zalrsc)
+#define __arch_xchg(sfx, prepend, append, r, p, n) \
+({ \
+ __typeof__(*(__ptr)) temp; \
+ __asm__ __volatile__ ( \
+ prepend \
+ "1: lr" sfx " %0, %1\n" \
+ " sc" sfx " %2, %3, %1\n" \
+ " bnez %2, 1b\n" \
+ append \
+ : "=&r" (r), "+A" (*(p)), "=&r" (temp) \
+ : "r" (n) \
+ : "memory"); \
+})
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
#define _arch_xchg(ptr, new, sc_sfx, swap_sfx, prepend, \
sc_append, swap_append) \
diff --git a/arch/riscv/include/asm/futex.h b/arch/riscv/include/asm/futex.h
index 6f3bc9bdb85e..06fe227197d9 100644
--- a/arch/riscv/include/asm/futex.h
+++ b/arch/riscv/include/asm/futex.h
@@ -19,6 +19,7 @@
#define __disable_user_access() do { } while (0)
#endif
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
{ \
__enable_user_access(); \
@@ -32,17 +33,45 @@
: "memory"); \
__disable_user_access(); \
}
+#elif defined(__riscv_zalrsc)
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+{ \
+ __enable_user_access(); \
+ __asm__ __volatile__ ( \
+ "1: lr.w.aqrl %[ov], %[u] \n" \
+ " " insn " \n" \
+ "2: sc.w.aqrl %[t], %[t], %[u] \n" \
+ " bnez %[t], 1b \n" \
+ "3: \n" \
+ _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %[r]) \
+ _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %[r]) \
+ : [r] "+r" (ret), [ov] "=&r" (oldval), \
+ [t] "=&r" (temp), [u] "+m" (*(uaddr)) \
+ : [op] "Jr" (oparg) \
+ : "memory"); \
+ __disable_user_access(); \
+}
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
static inline int
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
{
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
int oldval = 0, ret = 0;
+#elif defined(__riscv_zalrsc)
+ int oldval = 0, ret = 0, temp = 0;
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;
uaddr = untagged_addr(uaddr);
switch (op) {
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
case FUTEX_OP_SET:
__futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]",
ret, oldval, uaddr, oparg);
@@ -63,6 +92,30 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
__futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]",
ret, oldval, uaddr, oparg);
break;
+#elif defined(__riscv_zalrsc)
+ case FUTEX_OP_SET:
+ __futex_atomic_op("mv %[t], %z[op]",
+ ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("add %[t], %[ov], %z[op]",
+ ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("or %[t], %[ov], %z[op]",
+ ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("and %[t], %[ov], %z[op]",
+ ret, oldval, uaddr, ~oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("xor %[t], %[ov], %z[op]",
+ ret, oldval, uaddr, oparg);
+ break;
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
default:
ret = -ENOSYS;
}
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 61b7a7716697..1c7bbd7fbff8 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -73,7 +73,16 @@
beq a2, zero, .Lnew_valid_map_cpus_restore_context
/* Atomically reset the current cpu bit in new_valid_map_cpus */
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
amoxor.d a0, a1, (a0)
+#elif defined(__riscv_zalrsc)
+1: lr.d a2, (a0)
+ xor a2, a1, a2
+ sc.d a2, a2, (a0)
+ bnez a2, 1b
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
/*
* A sfence.vma is required here. Even if we had Svvptc, there's no
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index f6a8ca49e627..515669bbbc96 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -265,7 +265,21 @@ SYM_CODE_START(_start_kernel)
/* Pick one hart to run the main boot sequence */
la a3, hart_lottery
li a2, 1
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
amoadd.w a3, a2, (a3)
+#elif defined(__riscv_zalrsc)
+ /*
+ * hart_lottery is a small 32-bit counter. add is valid on RV32
+ * and RV64; sc.w stores the low 32 bits.
+ */
+1: lr.w t0, (a3)
+ add t1, t0, a2
+ sc.w t1, t1, (a3)
+ bnez t1, 1b
+ mv a3, t0
+#else
+#error "Need AMO or LR/SC atomics"
+#endif
bnez a3, .Lsecondary_start
#endif /* CONFIG_RISCV_BOOT_SPINWAIT */
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 2/2] riscv: accept the atomic extensions this kernel was built with
2026-10-26 9:20 [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 1/2] riscv: build kernel atomics from LR/SC when Zaamo is disabled Vladimir Kondratiev
@ 2026-10-26 9:20 ` Vladimir Kondratiev
2026-10-26 10:30 ` [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Peter Zijlstra
2 siblings, 0 replies; 5+ messages in thread
From: Vladimir Kondratiev @ 2026-10-26 9:20 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Will Deacon, Peter Zijlstra, Mark Rutland, Gary Guo, Yury Norov,
Rasmus Villemoes, cfu, torvalds, olof, aleksa.paunovic, arikalo,
Boqun Feng, Boqun Feng
Cc: linux-riscv, linux-kernel, Vladimir.Kondratiev, Vladimir Kondratiev
riscv_early_of_processor_hartid() rejects a hart unless its
riscv,isa-extensions property contains "a". That rejects a Zalrsc-only
hart even when the kernel was built to use only LR/SC.
Require "a" or "zaamo" when the kernel emits AMO, and "a" or "zalrsc"
when it emits LR/SC. A normal build defines both toolchain macros and
still requires the full A extension. The legacy "riscv,isa" fallback
keeps its rv{32,64}ima check.
Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
---
arch/riscv/kernel/cpu.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 3dbc8cc557dd..5d1e39d16e59 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -82,12 +82,32 @@ int __init riscv_early_of_processor_hartid(struct device_node *node, unsigned lo
return -ENODEV;
if (of_property_match_string(node, "riscv,isa-extensions", "i") < 0 ||
- of_property_match_string(node, "riscv,isa-extensions", "m") < 0 ||
- of_property_match_string(node, "riscv,isa-extensions", "a") < 0) {
- pr_warn("CPU with hartid=%lu does not support ima", *hart);
+ of_property_match_string(node, "riscv,isa-extensions", "m") < 0) {
+ pr_warn("CPU with hartid=%lu does not support im", *hart);
return -ENODEV;
}
-
+#if !defined(__riscv_atomic) && !defined(__riscv_zaamo) && !defined(__riscv_zalrsc)
+#error "Need AMO or LR/SC atomics"
+#endif
+ /*
+ * Require each atomic form this kernel emits. The single-letter
+ * "a" extension satisfies either check. A Zalrsc-only build defines
+ * __riscv_zalrsc and checks that extension only.
+ */
+#if defined(__riscv_atomic) || defined(__riscv_zaamo)
+ if (of_property_match_string(node, "riscv,isa-extensions", "a") < 0 &&
+ of_property_match_string(node, "riscv,isa-extensions", "zaamo") < 0) {
+ pr_warn("CPU with hartid=%lu does not support AMO atomics", *hart);
+ return -ENODEV;
+ }
+#endif
+#if defined(__riscv_atomic) || defined(__riscv_zalrsc)
+ if (of_property_match_string(node, "riscv,isa-extensions", "a") < 0 &&
+ of_property_match_string(node, "riscv,isa-extensions", "zalrsc") < 0) {
+ pr_warn("CPU with hartid=%lu does not support LR/SC atomics", *hart);
+ return -ENODEV;
+ }
+#endif
return 0;
old_interface:
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo
2026-10-26 9:20 [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 1/2] riscv: build kernel atomics from LR/SC when Zaamo is disabled Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 2/2] riscv: accept the atomic extensions this kernel was built with Vladimir Kondratiev
@ 2026-10-26 10:30 ` Peter Zijlstra
2026-10-26 11:06 ` Vladimir Kondratiev
2 siblings, 1 reply; 5+ messages in thread
From: Peter Zijlstra @ 2026-10-26 10:30 UTC (permalink / raw)
To: Vladimir Kondratiev
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Will Deacon, Mark Rutland, Gary Guo, Yury Norov,
Rasmus Villemoes, cfu, torvalds, olof, aleksa.paunovic, arikalo,
Boqun Feng, linux-riscv, linux-kernel
On Mon, Oct 26, 2026 at 11:20:01AM +0200, Vladimir Kondratiev wrote:
> RISC-V split the A extension into Zaamo (AMO*.w/AMO*.d) and Zalrsc
> (LR/SC). Linux has so far required the whole A extension.
>
> MIPS P8700 [1] implements only Zalrsc. AMO instructions are emulated by a
> trap into SBI. I measured typical userspace atomics on this CPU: an
> LR/SC atomic takes about 40 cycles, an AMO atomic about 600. The same
> ratio applies to kernel refcounts, bitops, xchg and futexes, so the
> kernel needs to emit LR/SC when Zaamo is not implemented.
>
> Mobileye is going to use the "eyeq7h" platform, built on this CPU, for
> ADAS and autonomous driving. Kernel atomics are on the scheduling,
> memory-management and driver paths of that product, so the emulated
> AMO cost is not acceptable there.
>
> This series keeps today's default: both extensions on, -march still
> contains "a", generated code is unchanged. Turning Zaamo off is a
> NONPORTABLE choice. The resulting kernel matches one -march, which
> userspace has to use as well, so a runtime alternative would not
> produce a portable image.
>
> Zalrsc stays mandatory. cmpxchg, conditional atomics and futex CAS are
> already LR/SC sequences; Zaamo cannot replace them. BPF atomic ops
> still emit AMO and remain unsupported on a Zalrsc-only kernel.
The comment with RISCV_QUEUED_SPINLOCKS state that Zalrsc requires that
cmpxchg() loops have forward progress; which is much stronger than the
typical LL/SC implementation.
Does this MIPS thing indeed provide this?
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo
2026-10-26 10:30 ` [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Peter Zijlstra
@ 2026-10-26 11:06 ` Vladimir Kondratiev
0 siblings, 0 replies; 5+ messages in thread
From: Vladimir Kondratiev @ 2026-10-26 11:06 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Will Deacon, Mark Rutland, Gary Guo, Yury Norov,
Rasmus Villemoes, cfu, torvalds, olof, aleksa.paunovic, arikalo,
Boqun Feng, linux-riscv, linux-kernel
On 10/26/26 12:30, Peter Zijlstra wrote:
> The comment with RISCV_QUEUED_SPINLOCKS state that Zalrsc requires that
> cmpxchg() loops have forward progress; which is much stronger than the
> typical LL/SC implementation.
>
> Does this MIPS thing indeed provide this?
You mean Ziccrse extension? Yes, p8700 does provide it. I explicitly
confirmed it with hardware designers.
In fact, I use RISCV_QUEUED_SPINLOCKS on this platform
Thanks, Vladimir
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-26 11:06 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 9:20 [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 1/2] riscv: build kernel atomics from LR/SC when Zaamo is disabled Vladimir Kondratiev
2026-10-26 9:20 ` [PATCH v3 2/2] riscv: accept the atomic extensions this kernel was built with Vladimir Kondratiev
2026-10-26 10:30 ` [PATCH v3 0/2] riscv: support CPUs with Zalrsc but not Zaamo Peter Zijlstra
2026-10-26 11:06 ` Vladimir Kondratiev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®