Re: [PATCH v4 0/2] riscv: support CPUs with Zalrsc but not Zaamo
From: Palmer Dabbelt
Date: Tue Nov 03 2026 - 17:30:32 EST
On Sun, 01 Nov 2026 04:51:38 PST (-0800), vladimir.kondratiev@xxxxxxxxxxxx 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.
In RISC-V land, things that are implemented by M-mode traps are generally considered "implemented" in the context of supervisor mode, just implemented to have low performance. I don't agree with that decision, but that's really an ISA thing and not something we can do that much about it Linux.
So I think the first thing you need to decide here is how you're going to be treating the atomics: are they really unimplemented, or are they implemented but slow? Right now this is kind of a mixed bag: you're sort of treated them as unimplemented in the kernel (or at least parts of the kernel), but then implemented in userspace.
If you're going to treat the AMOs as "implemented but slow", then I think it's best to see some actual performance numbers for a real application. Sure 600 cycles is slow for an atomic, but I was recently playing around with some much larger systems with ~300 cycle AMOs and couldn't get any meaningful benchmarks to show up over there -- those were OOO cores blocked on bus resources, so a completely different problem, but just saying they're 600 cycles so we can't use them isn't really good enough -- particularly when the alternative is 40 cycles, which is also super slow, so it's not like you can be doing all that much with atomics on these cores even with the "fast" sequences. You're probably also going to need some way to tell userspace about this "implemented but slow" behavior, similar to how we describe misaligned accesses (which is all a bit of a messy retrofit, so maybe don't copy it exactly).
If you're going to treat the AMOs as "unimplemented", then we need some way to deal with userspace. Right now we have A as part of all the base behaviors we expose to userspace. We used to have the non-A userspace support, but we decided to drop it when upstreaming the port because it didn't seem useful to anyone. There was a design sketched out here with a VDSO call for cmpxchg() that looked similar to some of the non-A Arm systems, but as far as I know nobody's implemented that in the kernel or userspace so it'd need to be proved out.
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.
Is that announced anywhere? All I can find is an EyeQ 6 on the website.
Also: are you planning on continuing with these non-A systems? Those 40-cycle atomics are going to burn you at some point, if the plan for the next-generation systems is just to go implement A then maybe it's best to keep this out of tree. We already have way too much fragmentation in RISC-V land as it is, we don't need any more.
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.
It's really not non-portable, though: the Zalrsc code runs fine on systems that support Zaamo, it just may be a performance issue. I'm not sure anyone's actually measured that, but I think it's sane to just assume that native AMOs are going to out-performance LR/SC on _some_ systems. It's still just a performance thing, though...
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 v4:
- Require a compiler that accepts _zalrsc in -march before Zaamo can
be disabled. GCC 15.1 introduces that support. Older compilers keep
Zaamo enabled and -march keeps "a".
- Link to v3: https://patch.msgid.link/20261026-lrsc-only-v3-0-ec29c8190fb1@xxxxxxxxxxxx
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@xxxxxxxxxxxx>
---
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 | 32 +++++++++++++++++++++++
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, 267 insertions(+), 9 deletions(-)
---
base-commit: c03c1a14507dfaf8b856c2608f9ac216021fc222
change-id: 20260120-lrsc-only-cc06422f5bb1
Best regards,