* [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures
@ 2026-09-16 20:02 Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function Bradley Morgan
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
This adds cmpxchg_emu_u16() next to cmpxchg_emu_u8() and wires it into
the architectures that use the one byte emulation, arc, csky, sh and
xtensa.
David Laight noted that uintptr_t was an odd choice for the API and
suggested u16 as the natural type, so v2 takes u16 arguments and the
cast work moves to the architectures. The arc and csky call sites
cast to u16 instead of uintptr_t, and sh and xtensa pass the values
through unchanged, letting the narrowing happen at the function
boundary.
The experiment answers David's question about what the 32 bit word
compare does with an API typed u16. It compares only the 16 bits that
make up the halfword being emulated, because the union splice packs
the caller's old value into the selected halfword of the compare word
before the word wide cmpxchg runs, and the union layout puts every
h[i] at byte offset 2*i on both endian layouts. A value wider than 16
bits can never reach the compare, so the return value is the old
halfword contents, exactly what cmpxchg() returns on architectures
with a native two byte variant.
The ARMv6 wiring is dropped. Arnd Bergmann's platform removal series
makes the ARMv6 path unreachable once it lands, and he offered to take
the INTEGRATOR_CM1136JFS cleanup as part of it, so the wiring here
would be churn against his tree. I will forward port this part once
the mach-versatile removal actually happens, if the path still exists
then.
Patch 1 adds the function, the prototype, and renames the Kconfig
symbol to ARCH_NEED_CMPXCHG_1_2_EMU since it now gates both
emulations. Patches 2 through 5 add case 2 beside each existing case
1, following each file's current style. The function body follows the
two byte implementation in Paul's April 2024 RFC series, of which only
the one byte part landed as commit a88d970c8bb5 ("lib: Add one-byte
emulation function").
Verification. A host test ran 972 cases across both halfword offsets,
matching and mismatching compares, against a byte level reference
model, all passing. The remaining checkpatch warnings are the volatile
and long line ones that the merged cmpxchg_emu_u8() lines already
carry.
Changes since v1:
- u16 arguments instead of uintptr_t, per David Laight
- ARMv6 wiring dropped, per Arnd Bergmann's offer and the discussion
with Paul McKenney
- copyright lines now carry both authors, Paul's 2024 line and mine
Thank you, Paul McKenney, for suggesting this, and thank you David
Laight and Arnd Bergmann for the review.
Bradley Morgan (5):
lib: Add two-byte cmpxchg emulation function
ARC: Emulate two-byte cmpxchg
csky: Emulate two-byte cmpxchg
sh: Emulate two-byte cmpxchg
xtensa: Emulate two-byte cmpxchg
arch/Kconfig | 2 +-
arch/arc/Kconfig | 2 +-
arch/arc/include/asm/cmpxchg.h | 3 +++
arch/csky/Kconfig | 2 +-
arch/csky/include/asm/cmpxchg.h | 9 +++++++++
arch/sh/Kconfig | 2 +-
arch/sh/include/asm/cmpxchg.h | 2 ++
arch/xtensa/Kconfig | 2 +-
arch/xtensa/include/asm/cmpxchg.h | 1 +
include/linux/cmpxchg-emu.h | 4 +++-
lib/Makefile | 2 +-
lib/cmpxchg-emu.c | 38 ++++++++++++++++++++++------------
12 files changed, 58 insertions(+), 11 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
@ 2026-09-16 20:02 ` Bradley Morgan
2026-09-16 20:17 ` Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 2/5] ARC: Emulate two-byte cmpxchg Bradley Morgan
` (3 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
cmpxchg_emu_u8() emulates one-byte cmpxchg() in terms of four-byte
cmpxchg() for the architectures lacking native one-byte atomics.
The same architectures also lack native two-byte cmpxchg(), where
such an operation is not supported and either fails to compile via
BUILD_BUG() or fails to link, because the bad pointer sentinels
these architectures declare are never defined.
Add cmpxchg_emu_u16(), the two-byte sibling. It reads the enclosing
word with READ_ONCE(), splices the two target bytes through a union
and loops on cmpxchg() of the full word until the compare succeeds.
Like cmpxchg_emu_u8() it is fully ordered.
Unlike cmpxchg_emu_u8() it takes and returns the natural u16 type
instead of uintptr_t, per the suggestion from David Laight. The
macros and inline wrappers at the call sites pass their old and
new values through (uintptr_t) casts today, so with u16 parameters
the narrowing happens at the function boundary and the function
compares and returns exactly the 16 bits the caller asked for,
which matches the hardware cmpxchg r16 behaviour where a 16-bit
compare only looks at the low 16 bits of the register.
The Kconfig symbol gating this file is renamed from
ARCH_NEED_CMPXCHG_1_EMU to ARCH_NEED_CMPXCHG_1_2_EMU, as it now
selects both the one-byte and the two-byte emulation.
Suggested-by: Paul E. McKenney <paulmck@kernel.org>
Suggested-by: David Laight <david.laight.linux@gmail.com>
Signed-off-by: Bradley Morgan <brads@mainlining.org>
---
arch/Kconfig | 2 +-
arch/arc/Kconfig | 2 +-
arch/csky/Kconfig | 2 +-
arch/sh/Kconfig | 2 +-
arch/xtensa/Kconfig | 2 +-
include/linux/cmpxchg-emu.h | 4 +++-
lib/Makefile | 2 +-
lib/cmpxchg-emu.c | 38 +++++++++++++++++++++++++++++++++----
8 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 3bb2e568f5b1..d56064797e09 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1817,7 +1817,7 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT
# strict alignment always, even with -falign-functions.
def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG
-config ARCH_NEED_CMPXCHG_1_EMU
+config ARCH_NEED_CMPXCHG_1_2_EMU
bool
config ARCH_WANTS_PRE_LINK_VMLINUX
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 80e61175bf52..0e91d254eccb 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -14,7 +14,7 @@ config ARC
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
- select ARCH_NEED_CMPXCHG_1_EMU
+ select ARCH_NEED_CMPXCHG_1_2_EMU
select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
select ARCH_32BIT_OFF_T
select BUILDTIME_TABLE_SORT
diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
index 4331313a42ff..5f26e8615d7d 100644
--- a/arch/csky/Kconfig
+++ b/arch/csky/Kconfig
@@ -37,7 +37,7 @@ config CSKY
select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPTION
select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPTION
select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION
- select ARCH_NEED_CMPXCHG_1_EMU
+ select ARCH_NEED_CMPXCHG_1_2_EMU
select ARCH_WANT_FRAME_POINTERS if !CPU_CK610 && $(cc-option,-mbacktrace)
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
select COMMON_CLK
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d60f1d5a94c0..09e556fced01 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -14,7 +14,7 @@ config SUPERH
select ARCH_HIBERNATION_POSSIBLE if MMU
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_WANT_IPC_PARSE_VERSION
- select ARCH_NEED_CMPXCHG_1_EMU
+ select ARCH_NEED_CMPXCHG_1_2_EMU
select CPU_NO_EFFICIENT_FFS
select DMA_DECLARE_COHERENT
select GENERIC_ATOMIC64
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index f2f9cd9cde50..62019fd444d4 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -14,7 +14,7 @@ config XTENSA
select ARCH_HAS_DMA_SET_UNCACHED if MMU
select ARCH_HAS_STRNCPY_FROM_USER if !KASAN
select ARCH_HAS_STRNLEN_USER
- select ARCH_NEED_CMPXCHG_1_EMU
+ select ARCH_NEED_CMPXCHG_1_2_EMU
select ARCH_USE_MEMTEST
select ARCH_USE_QUEUED_RWLOCKS
select ARCH_USE_QUEUED_SPINLOCKS
diff --git a/include/linux/cmpxchg-emu.h b/include/linux/cmpxchg-emu.h
index 998deec67740..d7eb96a15f85 100644
--- a/include/linux/cmpxchg-emu.h
+++ b/include/linux/cmpxchg-emu.h
@@ -4,12 +4,14 @@
* lacking direct support for these sizes. These are implemented in terms
* of 4-byte cmpxchg operations.
*
- * Copyright (C) 2024 Paul E. McKenney.
+ * Copyright (C) 2024 Paul E. McKenney <paulmck@kernel.org>
+ * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org>
*/
#ifndef __LINUX_CMPXCHG_EMU_H
#define __LINUX_CMPXCHG_EMU_H
uintptr_t cmpxchg_emu_u8(volatile u8 *p, uintptr_t old, uintptr_t new);
+u16 cmpxchg_emu_u16(volatile u16 *p, u16 old, u16 new);
#endif /* __LINUX_CMPXCHG_EMU_H */
diff --git a/lib/Makefile b/lib/Makefile
index 43421c39d21b..d0e69312176a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -202,7 +202,7 @@ obj-$(CONFIG_CODE_TAGGING) += codetag.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
-obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
+obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_2_EMU) += cmpxchg-emu.o
obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
#ensure exported functions have prototypes
diff --git a/lib/cmpxchg-emu.c b/lib/cmpxchg-emu.c
index 27f6f97cb60d..6586f1a88178 100644
--- a/lib/cmpxchg-emu.c
+++ b/lib/cmpxchg-emu.c
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Emulated 1-byte cmpxchg operation for architectures lacking direct
- * support for this size. This is implemented in terms of 4-byte cmpxchg
- * operations.
+ * Emulated 1-byte and 2-byte cmpxchg operations for architectures lacking
+ * direct support for these sizes. These are implemented in terms of
+ * 4-byte cmpxchg operations.
*
- * Copyright (C) 2024 Paul E. McKenney.
+ * Copyright (C) 2024 Paul E. McKenney <paulmck@kernel.org>
+ * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org>
*/
#include <linux/types.h>
@@ -43,3 +44,32 @@ uintptr_t cmpxchg_emu_u8(volatile u8 *p, uintptr_t old, uintptr_t new)
return old;
}
EXPORT_SYMBOL_GPL(cmpxchg_emu_u8);
+
+union u16_32 {
+ u16 h[2];
+ u32 w;
+};
+
+/* Emulate two-byte cmpxchg() in terms of 4-byte cmpxchg. */
+u16 cmpxchg_emu_u16(volatile u16 *p, u16 old, u16 new)
+{
+ u32 *p32 = (u32 *)(((uintptr_t)p) & ~0x3);
+ int i = (((uintptr_t)p) & 0x2) / 2;
+ union u16_32 old32;
+ union u16_32 new32;
+ u32 ret;
+
+ WARN_ON_ONCE(((uintptr_t)p) & 0x1);
+ ret = READ_ONCE(*p32);
+ do {
+ old32.w = ret;
+ if (old32.h[i] != old)
+ return old32.h[i];
+ new32.w = old32.w;
+ new32.h[i] = new;
+ instrument_atomic_read_write(p, 2);
+ ret = data_race(cmpxchg(p32, old32.w, new32.w)); // Overridden above.
+ } while (ret != old32.w);
+ return old;
+}
+EXPORT_SYMBOL_GPL(cmpxchg_emu_u16);
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/5] ARC: Emulate two-byte cmpxchg
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function Bradley Morgan
@ 2026-09-16 20:02 ` Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 3/5] csky: " Bradley Morgan
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
ARC has no two-byte atomic compare and swap, so the __cmpxchg() macro
switch lets case 2 fall through to BUILD_BUG() via default. Route case
2 through the new cmpxchg_emu_u16(), which now takes natural u16
arguments, so the (uintptr_t) casts on _o_ and _n_ become (u16) casts.
Signed-off-by: Bradley Morgan <brads@mainlining.org>
---
arch/arc/include/asm/cmpxchg.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h
index 76f43db0890f..4451c2011ee3 100644
--- a/arch/arc/include/asm/cmpxchg.h
+++ b/arch/arc/include/asm/cmpxchg.h
@@ -50,6 +50,9 @@
case 1: \
_prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \
break; \
+ case 2: \
+ _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u16((volatile u16 *__force)_p_, (u16)_o_, (u16)_n_); \
+ break; \
case 4: \
_prev_ = __cmpxchg(_p_, _o_, _n_); \
break; \
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/5] csky: Emulate two-byte cmpxchg
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 2/5] ARC: Emulate two-byte cmpxchg Bradley Morgan
@ 2026-09-16 20:02 ` Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 4/5] sh: " Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 5/5] xtensa: " Bradley Morgan
4 siblings, 0 replies; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
CSKY has no two-byte atomic compare and swap, so the __cmpxchg()
switches in cmpxchg.h let case 2 fall through to the undefined
__cmpxchg_called_with_bad_pointer(), failing at link time. Route case
2 through the new cmpxchg_emu_u16(), which now takes natural u16
arguments, so the (uintptr_t) casts on __old and __new become (u16)
casts in all three switch instances.
Signed-off-by: Bradley Morgan <brads@mainlining.org>
---
arch/csky/include/asm/cmpxchg.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/csky/include/asm/cmpxchg.h b/arch/csky/include/asm/cmpxchg.h
index db6dda47184e..e53628268e8c 100644
--- a/arch/csky/include/asm/cmpxchg.h
+++ b/arch/csky/include/asm/cmpxchg.h
@@ -65,6 +65,9 @@
case 1: \
__ret = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *)__ptr, (uintptr_t)__old, (uintptr_t)__new); \
break; \
+ case 2: \
+ __ret = (__typeof__(*(ptr)))cmpxchg_emu_u16((volatile u16 *)__ptr, (u16)__old, (u16)__new); \
+ break; \
case 4: \
asm volatile ( \
"1: ldex.w %0, (%3) \n" \
@@ -98,6 +101,9 @@
case 1: \
__ret = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *)__ptr, (uintptr_t)__old, (uintptr_t)__new); \
break; \
+ case 2: \
+ __ret = (__typeof__(*(ptr)))cmpxchg_emu_u16((volatile u16 *)__ptr, (u16)__old, (u16)__new); \
+ break; \
case 4: \
asm volatile ( \
"1: ldex.w %0, (%3) \n" \
@@ -132,6 +138,9 @@
case 1: \
__ret = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *)__ptr, (uintptr_t)__old, (uintptr_t)__new); \
break; \
+ case 2: \
+ __ret = (__typeof__(*(ptr)))cmpxchg_emu_u16((volatile u16 *)__ptr, (u16)__old, (u16)__new); \
+ break; \
case 4: \
asm volatile ( \
RELEASE_FENCE \
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 4/5] sh: Emulate two-byte cmpxchg
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
` (2 preceding siblings ...)
2026-09-16 20:02 ` [PATCH v2 3/5] csky: " Bradley Morgan
@ 2026-09-16 20:02 ` Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 5/5] xtensa: " Bradley Morgan
4 siblings, 0 replies; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
SH has no byte or halfword atomic memory operations, so the __cmpxchg()
switch routes case 1 through cmpxchg_emu_u8() and lets case 2 fall
through to __cmpxchg_called_with_bad_pointer(), which is declared but
never defined, so a two-byte cmpxchg() fails at link time. Route case
2 through the new cmpxchg_emu_u16(), which takes natural u16
arguments, so the unsigned long old and new narrow at the function
boundary.
Acked-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Signed-off-by: Bradley Morgan <brads@mainlining.org>
---
arch/sh/include/asm/cmpxchg.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h
index 1e5dc5ccf7bf..477d3025a441 100644
--- a/arch/sh/include/asm/cmpxchg.h
+++ b/arch/sh/include/asm/cmpxchg.h
@@ -59,6 +59,8 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
switch (size) {
case 1:
return cmpxchg_emu_u8(ptr, old, new);
+ case 2:
+ return cmpxchg_emu_u16(ptr, old, new);
case 4:
return __cmpxchg_u32(ptr, old, new);
}
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 5/5] xtensa: Emulate two-byte cmpxchg
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
` (3 preceding siblings ...)
2026-09-16 20:02 ` [PATCH v2 4/5] sh: " Bradley Morgan
@ 2026-09-16 20:02 ` Bradley Morgan
2026-09-17 1:32 ` Max Filippov
4 siblings, 1 reply; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:02 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel, Bradley Morgan
Xtensa has no two-byte atomic compare and swap, so the __cmpxchg()
switch lets case 2 fall through to __cmpxchg_called_with_bad_pointer(),
which is declared but never defined, so a two-byte cmpxchg() fails at
link time. Route case 2 through the new cmpxchg_emu_u16(), which takes
natural u16 arguments, so the unsigned long old and new narrow at the
function boundary.
Signed-off-by: Bradley Morgan <brads@mainlining.org>
---
arch/xtensa/include/asm/cmpxchg.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/xtensa/include/asm/cmpxchg.h b/arch/xtensa/include/asm/cmpxchg.h
index b6db4838b175..8dea8e357fc0 100644
--- a/arch/xtensa/include/asm/cmpxchg.h
+++ b/arch/xtensa/include/asm/cmpxchg.h
@@ -76,6 +76,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
{
switch (size) {
case 1: return cmpxchg_emu_u8(ptr, old, new);
+ case 2: return cmpxchg_emu_u16(ptr, old, new);
case 4: return __cmpxchg_u32(ptr, old, new);
default: __cmpxchg_called_with_bad_pointer();
return old;
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function
2026-09-16 20:02 ` [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function Bradley Morgan
@ 2026-09-16 20:17 ` Bradley Morgan
0 siblings, 0 replies; 8+ messages in thread
From: Bradley Morgan @ 2026-09-16 20:17 UTC (permalink / raw)
To: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Max Filippov
Cc: Arnd Bergmann, Paul E . McKenney, David Laight,
John Paul Adrian Glaubitz, linux-snps-arc, linux-csky, linux-sh,
linux-kernel
On 16 September 2026 21:02:11 BST, Bradley Morgan <brads@mainlining.org>
wrote:
>cmpxchg_emu_u8() emulates one-byte cmpxchg() in terms of four-byte
>cmpxchg() for the architectures lacking native one-byte atomics.
>The same architectures also lack native two-byte cmpxchg(), where
>such an operation is not supported and either fails to compile via
>BUILD_BUG() or fails to link, because the bad pointer sentinels
>these architectures declare are never defined.
>
>Add cmpxchg_emu_u16(), the two-byte sibling. It reads the enclosing
>word with READ_ONCE(), splices the two target bytes through a union
>and loops on cmpxchg() of the full word until the compare succeeds.
>Like cmpxchg_emu_u8() it is fully ordered.
>
>Unlike cmpxchg_emu_u8() it takes and returns the natural u16 type
>instead of uintptr_t, per the suggestion from David Laight. The
>macros and inline wrappers at the call sites pass their old and
>new values through (uintptr_t) casts today, so with u16 parameters
>the narrowing happens at the function boundary and the function
>compares and returns exactly the 16 bits the caller asked for,
>which matches the hardware cmpxchg r16 behaviour where a 16-bit
>compare only looks at the low 16 bits of the register.
>
>The Kconfig symbol gating this file is renamed from
>ARCH_NEED_CMPXCHG_1_EMU to ARCH_NEED_CMPXCHG_1_2_EMU, as it now
>selects both the one-byte and the two-byte emulation.
>
>Suggested-by: Paul E. McKenney <paulmck@kernel.org>
>Suggested-by: David Laight <david.laight.linux@gmail.com>
>Signed-off-by: Bradley Morgan <brads@mainlining.org>
>---
> arch/Kconfig | 2 +-
> arch/arc/Kconfig | 2 +-
> arch/csky/Kconfig | 2 +-
> arch/sh/Kconfig | 2 +-
> arch/xtensa/Kconfig | 2 +-
> include/linux/cmpxchg-emu.h | 4 +++-
> lib/Makefile | 2 +-
> lib/cmpxchg-emu.c | 38 +++++++++++++++++++++++++++++++++----
> 8 files changed, 43 insertions(+), 11 deletions(-)
>
>diff --git a/arch/Kconfig b/arch/Kconfig
>index 3bb2e568f5b1..d56064797e09 100644
>--- a/arch/Kconfig
>+++ b/arch/Kconfig
>@@ -1817,7 +1817,7 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT
> # strict alignment always, even with -falign-functions.
> def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG
>
>-config ARCH_NEED_CMPXCHG_1_EMU
>+config ARCH_NEED_CMPXCHG_1_2_EMU
> bool
>
> config ARCH_WANTS_PRE_LINK_VMLINUX
>diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
>index 80e61175bf52..0e91d254eccb 100644
>--- a/arch/arc/Kconfig
>+++ b/arch/arc/Kconfig
>@@ -14,7 +14,7 @@ config ARC
> select ARCH_HAS_SETUP_DMA_OPS
> select ARCH_HAS_SYNC_DMA_FOR_CPU
> select ARCH_HAS_SYNC_DMA_FOR_DEVICE
>- select ARCH_NEED_CMPXCHG_1_EMU
>+ select ARCH_NEED_CMPXCHG_1_2_EMU
> select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
> select ARCH_32BIT_OFF_T
> select BUILDTIME_TABLE_SORT
>diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
>index 4331313a42ff..5f26e8615d7d 100644
>--- a/arch/csky/Kconfig
>+++ b/arch/csky/Kconfig
>@@ -37,7 +37,7 @@ config CSKY
> select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPTION
> select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPTION
> select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION
>- select ARCH_NEED_CMPXCHG_1_EMU
>+ select ARCH_NEED_CMPXCHG_1_2_EMU
> select ARCH_WANT_FRAME_POINTERS if !CPU_CK610 && $(cc-option,-mbacktrace)
> select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
> select COMMON_CLK
>diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
>index d60f1d5a94c0..09e556fced01 100644
>--- a/arch/sh/Kconfig
>+++ b/arch/sh/Kconfig
>@@ -14,7 +14,7 @@ config SUPERH
> select ARCH_HIBERNATION_POSSIBLE if MMU
> select ARCH_MIGHT_HAVE_PC_PARPORT
> select ARCH_WANT_IPC_PARSE_VERSION
>- select ARCH_NEED_CMPXCHG_1_EMU
>+ select ARCH_NEED_CMPXCHG_1_2_EMU
> select CPU_NO_EFFICIENT_FFS
> select DMA_DECLARE_COHERENT
> select GENERIC_ATOMIC64
>diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
>index f2f9cd9cde50..62019fd444d4 100644
>--- a/arch/xtensa/Kconfig
>+++ b/arch/xtensa/Kconfig
>@@ -14,7 +14,7 @@ config XTENSA
> select ARCH_HAS_DMA_SET_UNCACHED if MMU
> select ARCH_HAS_STRNCPY_FROM_USER if !KASAN
> select ARCH_HAS_STRNLEN_USER
>- select ARCH_NEED_CMPXCHG_1_EMU
>+ select ARCH_NEED_CMPXCHG_1_2_EMU
> select ARCH_USE_MEMTEST
> select ARCH_USE_QUEUED_RWLOCKS
> select ARCH_USE_QUEUED_SPINLOCKS
>diff --git a/include/linux/cmpxchg-emu.h b/include/linux/cmpxchg-emu.h
>index 998deec67740..d7eb96a15f85 100644
>--- a/include/linux/cmpxchg-emu.h
>+++ b/include/linux/cmpxchg-emu.h
>@@ -4,12 +4,14 @@
> * lacking direct support for these sizes. These are implemented in terms
> * of 4-byte cmpxchg operations.
> *
>- * Copyright (C) 2024 Paul E. McKenney.
>+ * Copyright (C) 2024 Paul E. McKenney <paulmck@kernel.org>
>+ * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org>
> */
>
> #ifndef __LINUX_CMPXCHG_EMU_H
> #define __LINUX_CMPXCHG_EMU_H
>
> uintptr_t cmpxchg_emu_u8(volatile u8 *p, uintptr_t old, uintptr_t new);
>+u16 cmpxchg_emu_u16(volatile u16 *p, u16 old, u16 new);
>
> #endif /* __LINUX_CMPXCHG_EMU_H */
>diff --git a/lib/Makefile b/lib/Makefile
>index 43421c39d21b..d0e69312176a 100644
>--- a/lib/Makefile
>+++ b/lib/Makefile
>@@ -202,7 +202,7 @@ obj-$(CONFIG_CODE_TAGGING) += codetag.o
> lib-$(CONFIG_GENERIC_BUG) += bug.o
>
> obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
>-obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
>+obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_2_EMU) += cmpxchg-emu.o
>
> obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
> #ensure exported functions have prototypes
>diff --git a/lib/cmpxchg-emu.c b/lib/cmpxchg-emu.c
>index 27f6f97cb60d..6586f1a88178 100644
>--- a/lib/cmpxchg-emu.c
>+++ b/lib/cmpxchg-emu.c
>@@ -1,10 +1,11 @@
> // SPDX-License-Identifier: GPL-2.0+
> /*
>- * Emulated 1-byte cmpxchg operation for architectures lacking direct
>- * support for this size. This is implemented in terms of 4-byte cmpxchg
>- * operations.
>+ * Emulated 1-byte and 2-byte cmpxchg operations for architectures lacking
>+ * direct support for these sizes. These are implemented in terms of
>+ * 4-byte cmpxchg operations.
> *
>- * Copyright (C) 2024 Paul E. McKenney.
>+ * Copyright (C) 2024 Paul E. McKenney <paulmck@kernel.org>
>+ * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org>
> */
>
> #include <linux/types.h>
>@@ -43,3 +44,32 @@ uintptr_t cmpxchg_emu_u8(volatile u8 *p, uintptr_t old, uintptr_t new)
> return old;
> }
> EXPORT_SYMBOL_GPL(cmpxchg_emu_u8);
>+
>+union u16_32 {
>+ u16 h[2];
>+ u32 w;
>+};
>+
>+/* Emulate two-byte cmpxchg() in terms of 4-byte cmpxchg. */
>+u16 cmpxchg_emu_u16(volatile u16 *p, u16 old, u16 new)
>+{
>+ u32 *p32 = (u32 *)(((uintptr_t)p) & ~0x3);
>+ int i = (((uintptr_t)p) & 0x2) / 2;
>+ union u16_32 old32;
>+ union u16_32 new32;
>+ u32 ret;
>+
>+ WARN_ON_ONCE(((uintptr_t)p) & 0x1);
>+ ret = READ_ONCE(*p32);
>+ do {
>+ old32.w = ret;
>+ if (old32.h[i] != old)
>+ return old32.h[i];
>+ new32.w = old32.w;
>+ new32.h[i] = new;
>+ instrument_atomic_read_write(p, 2);
>+ ret = data_race(cmpxchg(p32, old32.w, new32.w)); // Overridden above.
>+ } while (ret != old32.w);
>+ return old;
>+}
>+EXPORT_SYMBOL_GPL(cmpxchg_emu_u16);
>
<Comment> Will this rename cause a build regression for ARM V6
architectures?
It appears that arch/arm/Kconfig was not updated alongside the others and
still attempts to select the old symbol:
select ARCH_NEED_CMPXCHG_1_EMU if CPU_V6
If ARM CPU_V6 code relies on __cmpxchg() calling cmpxchg_emu_u8(), could
this result in an undefined reference since the Kconfig dependency chain is
broken and the emulation library won't be compiled? <Comment>
Deliberate, will be dead code after ardbs series is merged.
--- Thanks!
https://lore.kernel.org/all/EE579805-42F2-4C58-B752-F28779EEB717@grrlz.net/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 5/5] xtensa: Emulate two-byte cmpxchg
2026-09-16 20:02 ` [PATCH v2 5/5] xtensa: " Bradley Morgan
@ 2026-09-17 1:32 ` Max Filippov
0 siblings, 0 replies; 8+ messages in thread
From: Max Filippov @ 2026-09-17 1:32 UTC (permalink / raw)
To: Bradley Morgan
Cc: Andrew Morton, Vineet Gupta, Guo Ren, Yoshinori Sato,
Rich Felker, Chris Zankel, Arnd Bergmann, Paul E . McKenney,
David Laight, John Paul Adrian Glaubitz, linux-snps-arc,
linux-csky, linux-sh, linux-kernel
On Wed, Sep 16, 2026 at 1:02 PM Bradley Morgan <brads@mainlining.org> wrote:
>
> Xtensa has no two-byte atomic compare and swap, so the __cmpxchg()
> switch lets case 2 fall through to __cmpxchg_called_with_bad_pointer(),
> which is declared but never defined, so a two-byte cmpxchg() fails at
> link time. Route case 2 through the new cmpxchg_emu_u16(), which takes
> natural u16 arguments, so the unsigned long old and new narrow at the
> function boundary.
>
> Signed-off-by: Bradley Morgan <brads@mainlining.org>
> ---
> arch/xtensa/include/asm/cmpxchg.h | 1 +
> 1 file changed, 1 insertion(+)
Reviewed-by: Max Filippov <jcmvbkbc@gmail.com>
--
Thanks.
-- Max
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-17 1:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 20:02 [PATCH v2 0/5] Add two-byte cmpxchg emulation and wire it into the architectures Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function Bradley Morgan
2026-09-16 20:17 ` Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 2/5] ARC: Emulate two-byte cmpxchg Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 3/5] csky: " Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 4/5] sh: " Bradley Morgan
2026-09-16 20:02 ` [PATCH v2 5/5] xtensa: " Bradley Morgan
2026-09-17 1:32 ` Max Filippov
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®