From: Bradley Morgan <brads@mainlining.org>
To: Andrew Morton <akpm@linux-foundation.org>,
Vineet Gupta <vgupta@kernel.org>, Guo Ren <guoren@kernel.org>,
Yoshinori Sato <ysato@users.sourceforge.jp>,
Rich Felker <dalias@libc.org>, Chris Zankel <chris@zankel.net>,
Max Filippov <jcmvbkbc@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>,
"Paul E . McKenney" <paulmck@kernel.org>,
David Laight <david.laight.linux@gmail.com>,
John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>,
linux-snps-arc@lists.infradead.org, linux-csky@vger.kernel.org,
linux-sh@vger.kernel.org, linux-kernel@vger.kernel.org,
Bradley Morgan <brads@mainlining.org>
Subject: [PATCH v2 1/5] lib: Add two-byte cmpxchg emulation function
Date: Wed, 16 Sep 2026 20:02:11 +0000 [thread overview]
Message-ID: <20260916200215.21774-2-brads@mainlining.org> (raw)
In-Reply-To: <20260916200215.21774-1-brads@mainlining.org>
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
next prev parent reply other threads:[~2026-09-16 20:04 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2026-09-16 20:17 ` [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 ` [PATCH v2 3/5] csky: " Bradley Morgan
2026-09-17 9:04 ` David Laight
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260916200215.21774-2-brads@mainlining.org \
--to=brads@mainlining.org \
--cc=akpm@linux-foundation.org \
--cc=arnd@arndb.de \
--cc=chris@zankel.net \
--cc=dalias@libc.org \
--cc=david.laight.linux@gmail.com \
--cc=glaubitz@physik.fu-berlin.de \
--cc=guoren@kernel.org \
--cc=jcmvbkbc@gmail.com \
--cc=linux-csky@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
--cc=linux-snps-arc@lists.infradead.org \
--cc=paulmck@kernel.org \
--cc=vgupta@kernel.org \
--cc=ysato@users.sourceforge.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®