[Concept,19/19] asm-generic: atomic: Add xchg() and try_cmpxchg() macros

Message ID 20260117011448.3007171-20-sjg@u-boot.org
State New
Headers
Series ext4l: Reduce ext4_uboot.h size by moving code to include/linux |

Commit Message

Simon Glass Jan. 17, 2026, 1:14 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Move xchg and try_cmpxchg macros to asm-generic/atomic.h alongside
cmpxchg, as they are all atomic exchange operations.

Add:
- try_cmpxchg() - compare and exchange with boolean return and
  old value update on failure
- xchg() - atomic exchange, stores new value and returns old

These are single-threaded implementations for U-Boot.

Add #ifndef guards to all three macros (cmpxchg, try_cmpxchg, xchg)
to avoid redefinition warnings on architectures like MIPS that provide
their own implementations.

Signed-off-by: Simon Glass <simon.glass@canonical.com>
Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
---

 fs/ext4l/ext4_uboot.h        | 12 ++----------
 include/asm-generic/atomic.h | 37 ++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 10 deletions(-)
  

Patch

diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h
index a4d863b86e1..a4baac6fc86 100644
--- a/fs/ext4l/ext4_uboot.h
+++ b/fs/ext4l/ext4_uboot.h
@@ -949,14 +949,7 @@  typedef unsigned int projid_t;
  * Additional stubs for inode.c
  */
 
-/* try_cmpxchg - compare and exchange with return value */
-#define try_cmpxchg(ptr, old, new) ({		\
-	typeof(*(old)) __old = *(old);		\
-	typeof(*(ptr)) __ret = cmpxchg(ptr, __old, (new));	\
-	if (__ret != __old)			\
-		*(old) = __ret;			\
-	__ret == __old;				\
-})
+/* try_cmpxchg is now in asm-generic/atomic.h */
 
 /* hash_64 - simple 64-bit hash */
 #define hash_64(val, bits)	((unsigned long)((val) >> (64 - (bits))))
@@ -1743,8 +1736,7 @@  static inline unsigned long ext4_find_next_bit_le(const void *addr,
 
 /* refcount operations are now in linux/refcount.h */
 
-/* xchg - exchange value atomically */
-#define xchg(ptr, new)			({ typeof(*(ptr)) __old = *(ptr); *(ptr) = (new); __old; })
+/* xchg is now in asm-generic/atomic.h */
 
 /* printk_ratelimited is in linux/printk.h */
 
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 3fa749bf012..3f72ae39ee1 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -209,6 +209,7 @@  static inline void atomic64_dec(volatile atomic64_t *v)
  * Single-threaded version for U-Boot. Atomically compares *ptr with old
  * and if equal, stores new. Returns the original value of *ptr.
  */
+#ifndef cmpxchg
 #define cmpxchg(ptr, old, new) ({		\
 	typeof(*(ptr)) __cmpxchg_old = (old);	\
 	typeof(*(ptr)) __cmpxchg_new = (new);	\
@@ -217,5 +218,41 @@  static inline void atomic64_dec(volatile atomic64_t *v)
 		*(ptr) = __cmpxchg_new;		\
 	__cmpxchg_ret;				\
 })
+#endif
+
+/**
+ * try_cmpxchg - compare and exchange with boolean return
+ * @ptr: pointer to the value
+ * @oldp: pointer to expected old value (updated on failure)
+ * @new: new value to store if current equals old
+ *
+ * Returns true if exchange succeeded, false otherwise.
+ * On failure, *oldp is updated with the current value.
+ */
+#ifndef try_cmpxchg
+#define try_cmpxchg(ptr, oldp, new) ({		\
+	typeof(*(oldp)) __old = *(oldp);	\
+	typeof(*(ptr)) __ret = cmpxchg(ptr, __old, (new)); \
+	if (__ret != __old)			\
+		*(oldp) = __ret;		\
+	__ret == __old;				\
+})
+#endif
+
+/**
+ * xchg - exchange value atomically
+ * @ptr: pointer to the value
+ * @new: new value to store
+ *
+ * Atomically stores new value and returns the old value.
+ * Single-threaded version for U-Boot.
+ */
+#ifndef xchg
+#define xchg(ptr, new) ({			\
+	typeof(*(ptr)) __xchg_old = *(ptr);	\
+	*(ptr) = (new);				\
+	__xchg_old;				\
+})
+#endif
 
 #endif