[PATCH v2 2/6] ARM: cmpxchg: support 2-byte xchg() on pre-ARMv6 CPUs
From: Karl Mehltretter
Date: Thu Oct 08 2026 - 01:39:27 EST
Pre-ARMv6 CPUs have no halfword swp, so __arch_xchg() only handles 1-
and 4-byte exchanges there and turns any other size into a link error
via __bad_xchg().
No C code needs a 16-bit xchg() on these CPUs, but the Rust atomic
helpers in rust/helpers/atomic_ext.c provide xchg() for Atomic<i16>
unconditionally, so building with CONFIG_RUST=y for ARMv5 fails:
ld.lld: error: undefined symbol: __bad_xchg
>>> referenced by helpers.c
>>> rust/helpers/helpers.o:(rust_helper_atomic_i16_xchg)
Implement the 2-byte case with interrupts disabled, as the pre-ARMv6
atomic_t operations already do. This is safe because a kernel built
for ARMv5 or older is never SMP.
ARMv6 before ARMv6K (ARM1136r0) has no 16-bit exclusive access either.
It is not handled here. Rust stays disabled for those kernels, and
they cannot be SMP since commit d70242427110 ("ARM: rework ARM11 CPU
selection logic").
Acked-by: Arnd Bergmann <arnd@xxxxxxxx>
Reviewed-by: Linus Walleij <linusw@xxxxxxxxxx>
Reviewed-by: Bradley Morgan <brads@xxxxxxxxxxxxxx>
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
arch/arm/include/asm/cmpxchg.h | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h
index 0ce5225af442..18555ae22893 100644
--- a/arch/arm/include/asm/cmpxchg.h
+++ b/arch/arm/include/asm/cmpxchg.h
@@ -31,11 +31,10 @@ __arch_xchg(unsigned long x, volatile void *ptr, int size)
{
extern void __bad_xchg(volatile void *, int);
unsigned long ret;
-#ifdef swp_is_buggy
- unsigned long flags;
-#endif
#if __LINUX_ARM_ARCH__ >= 6
unsigned int tmp;
+#else
+ unsigned long flags;
#endif
prefetchw((const void *)ptr);
@@ -106,6 +105,15 @@ __arch_xchg(unsigned long x, volatile void *ptr, int size)
: "r" (x), "r" (ptr)
: "memory", "cc");
break;
+#endif
+#if __LINUX_ARM_ARCH__ < 6
+ case 2:
+ /* swp has no halfword form. Pre-ARMv6 is never SMP. */
+ raw_local_irq_save(flags);
+ ret = *(volatile unsigned short *)ptr;
+ *(volatile unsigned short *)ptr = x;
+ raw_local_irq_restore(flags);
+ break;
#endif
default:
/* Cause a link-time error, the xchg() size is not supported */
--
2.39.5 (Apple Git-154)