From 5222fefffa0270c2f2d50961a4b75ef7f5605c29 Mon Sep 17 00:00:00 2001
From: ramin <lordrasmus@gmail.com>
Date: Mon, 24 Aug 2026 13:06:02 +0200
Subject: [PATCH] m68k: use the kernel helper on every core without CAS, not
 just ColdFire

The atomic header split the world into ColdFire and "the rest", assuming the
rest was 68020 and up. That holds for the MMU port, but not for the 68000 and
68010, which have no atomic read-modify-write instruction either. Building for
one of them stops at the first cas:

  Error: invalid instruction for this architecture; needs 68020 or higher
         (68020 [68k, 68ec020], 68030 [68ec030], 68040 [68ec040],
          68060 [68ec060]) -- statement `cas.l %d0,%d1,(%a1)' ignored

Reported by Waldemar Brodkorb from a Buildroot autobuilder failure; Buildroot
supports m68000 and has at least one user on it.

Decide by the presence of CAS instead. The instruction came with the 68020, so
the test is the list of the 68020-and-up cores: gcc defines a separate macro
per core and does not imply __mc68020__ on the later ones, and __mc68000__ is
no help because it is defined on every m68k, the 68040 and ColdFire included.

Nothing else changes: the kernel's atomic_cmpxchg_32 is syscall 335 "common"
in arch/m68k/kernel/syscalls/syscall.tbl and has an implementation for the MMU
as well as the noMMU port, so the branch the old cores now take is the one
ColdFire has been using all along - including its documented limit that the
8- and 16-bit variants stay non-atomic, since the helper is 32-bit only.

Checked with a cross gcc over -m68000, -m68010, -m68020, -m68030, -m68040,
-m68060, -mcpu=5206 and -mcpu=5208: the three old cores and both ColdFires
select the helper, the four others select cas, and each branch assembles for
the cores that select it.

Upstream: https://gogs.waldemar-brodkorb.de/oss/uclibc-ng/commit/5222fefffa0270c2f2d50961a4b75ef7f5605c29
Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
---
 libc/sysdeps/linux/m68k/bits/atomic.h | 32 ++++++++++++++++++---------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/libc/sysdeps/linux/m68k/bits/atomic.h b/libc/sysdeps/linux/m68k/bits/atomic.h
index cf7fd5f65..6acec1ed8 100644
--- a/libc/sysdeps/linux/m68k/bits/atomic.h
+++ b/libc/sysdeps/linux/m68k/bits/atomic.h
@@ -3,13 +3,15 @@
 
    Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 
-   m68k (68020 and up, which is everything the MMU Linux port runs on) has
-   the CAS instruction.  We implement the compare-and-exchange primitive
-   with cas.b/cas.w/cas.l; include/atomic.h derives every higher-level
-   operation from it.
+   The CAS instruction arrived with the 68020.  Where it exists we implement
+   the compare-and-exchange primitive with cas.b/cas.w/cas.l and let
+   include/atomic.h derive every higher-level operation from it.
 
-   ColdFire has no CAS at all, so there we use the kernel's
-   atomic_cmpxchg_32 helper, which exists for exactly this reason.
+   ColdFire, 68000 and 68010 have no atomic read-modify-write instruction at
+   all.  There we use the kernel's atomic_cmpxchg_32 helper, which exists for
+   exactly this reason and is available on every m68k (syscall 335, "common"
+   in arch/m68k/kernel/syscalls/syscall.tbl, with an implementation for both
+   the MMU and the noMMU port).
 
    Without this file m68k fell back to the generic non-atomic
    bits/atomic.h, whose "atomic" compare-and-exchange is a plain
@@ -22,7 +24,17 @@
 #define _M68K_BITS_ATOMIC_H	1
 
 #include <stdint.h>
-#ifdef __mcoldfire__
+
+/* CAS came with the 68020.  gcc sets a separate macro per core and does not
+   imply __mc68020__ on the later ones, hence the list; __mc68000__ is no help
+   here, it is defined on every m68k, the 68040 and ColdFire included.
+   Everything without CAS - ColdFire, 68000, 68010 - uses the kernel helper.  */
+#if defined __mc68020__ || defined __mc68030__ \
+    || defined __mc68040__ || defined __mc68060__
+# define __M68K_HAVE_CAS	1
+#endif
+
+#ifndef __M68K_HAVE_CAS
 # include <sys/syscall.h>
 #endif
 
@@ -58,7 +70,7 @@ typedef uintmax_t uatomic_max_t;
 #define atomic_read_barrier()	atomic_full_barrier ()
 #define atomic_write_barrier()	atomic_full_barrier ()
 
-#ifndef __mcoldfire__
+#ifdef __M68K_HAVE_CAS
 
 /* cas Dc,Du,<ea>: compare <ea> with Dc; if equal store Du, else load <ea>
    into Dc.  Either way Dc ends up holding the original *MEM, which is the
@@ -87,7 +99,7 @@ typedef uintmax_t uatomic_max_t;
 		       : "memory");					\
      __ret; })
 
-#else /* __mcoldfire__ */
+#else /* !__M68K_HAVE_CAS */
 
 /* d0 = syscall number, d1 = newval, d2 = oldval, a0 = mem; the helper
    returns the previous value.  The swap happens inside the syscall, so
@@ -116,7 +128,7 @@ typedef uintmax_t uatomic_max_t;
 #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
   __arch_compare_and_exchange_val_8_acq (mem, newval, oldval)
 
-#endif /* __mcoldfire__ */
+#endif /* __M68K_HAVE_CAS */
 
 /* m68k has no 64-bit CAS; NPTL and include/atomic.h only use int- and
    pointer-sized objects, so the bysize dispatch never reaches this.  */
-- 
2.47.3

