All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] sparc32: Use CAS for atomic support
@ 2023-12-29 20:06 Sam Ravnborg
  2023-12-29 20:07 ` [PATCH 1/4] sparc32: Add support for specifying -mcpu Sam Ravnborg
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Sam Ravnborg @ 2023-12-29 20:06 UTC (permalink / raw)
  To: David S. Miller, Arnd Bergmann, Andreas Larsson, sparclinux; +Cc: Sam Ravnborg

With sparc limited to leon3 the next step was to address the atomic
support which this patch set does.

Gaisler already had an implementation in their kernel patch stack, that
co-existed with sparc v8 without CAS support.

As the sparc v8 without CAS is no longer supported this patch set takes
a different approach. Using the current best practices the atomic support
is implemented in three steps.

The cmpxchg is updated to use casa/swap.
The atomic bitops are implemented in their own file and uses a minimal of
inline assembly.
The atomic operations are implemented based on the template found in
asm-generic.

Some notes:
- The code uses __always_inlin almost everywhere, where inline could be
  enough. Not sure what is best here.
- The new (and replaced) files uses the SPDX tag: GPL-2.0
  No sure if this is best practice today, I am happy to change the
  license.
- Build tested and booted using qemu.

The patches are on top of the sun4m and sun4d sunset patches.

Review feedback appreciated!

	Sam

---
Sam Ravnborg (4):
      sparc32: Add support for specifying -mcpu
      sparc32: Add cmpxchg support using CAS
      sparc32: Add atomic bitops support using CAS
      sparc32: Add atomic support using CAS
 
 arch/sparc/Kconfig                        |  24 +++++++++++
 arch/sparc/Makefile                       |  13 +++---
 arch/sparc/include/asm/atomic_32.h        | 151 ++++++++++++++++++++++++++++++++++++++++++++-----------------------
 arch/sparc/include/asm/bitops/atomic_32.h | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 arch/sparc/include/asm/bitops_32.h        |  71 +-------------------------------
 arch/sparc/include/asm/cmpxchg_32.h       |  72 ++++++++++++++++++--------------
 arch/sparc/lib/Makefile                   |   2 +-
 arch/sparc/lib/atomic32.c                 | 202 ------------------------------------------------------------------------------------------
 8 files changed, 296 insertions(+), 363 deletions(-)



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] sparc32: Add support for specifying -mcpu
  2023-12-29 20:06 [PATCH 0/4] sparc32: Use CAS for atomic support Sam Ravnborg
@ 2023-12-29 20:07 ` Sam Ravnborg
  2024-04-26 16:52   ` Andreas Larsson
  2023-12-29 20:07 ` [PATCH 2/4] sparc32: Add cmpxchg support using CAS Sam Ravnborg
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Sam Ravnborg @ 2023-12-29 20:07 UTC (permalink / raw)
  To: David S. Miller, Arnd Bergmann, Andreas Larsson, sparclinux

Add support for selecting the CPU architecture.
The default is leon3 - which is the minimum required as the kernel uses
CAS instructions.

Inspired by (from gaisler-buildroot-2023.02-1.0):
    0001-sparc32-leon-Build-with-mcpu-leon3-for-SPARC_LEON.patch
    0028-sparc32-leon-Make-what-mcpu-to-be-used-configurable-.patch

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Arnd Bergmann <arnd@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
---
 arch/sparc/Kconfig  | 24 ++++++++++++++++++++++++
 arch/sparc/Makefile | 13 +++++--------
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 1b9cf7f3c500..e94783ceb409 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -161,6 +161,30 @@ config ARCH_SUPPORTS_UPROBES
 
 menu "Processor type and features"
 
+choice
+	prompt "LEON architecture"
+	default SPARC_CPU_LEON3
+	help
+	  Select the architecture the kernel shall be built for
+
+config SPARC_CPU_LEON3
+	prompt "LEON 3"
+	help
+	  Build the kernel for the LEON 3 architecture
+
+config SPARC_CPU_LEON5
+	prompt "LEON 5"
+	help
+	  Build the kernel for the LEON 5 architecture
+
+config SPARC_CPU_DEFAULT
+	bool "Toolchain default"
+	help
+	  Build the kernel with no -mcpu option, getting the default
+	  for the toolchain that is being used.
+
+endchoice
+
 config SMP
 	bool "Symmetric multi-processing support"
 	help
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 5f6035936131..3c3a1fd8c873 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -25,14 +25,11 @@ KBUILD_LDFLAGS := -m elf32_sparc
 export BITS    := 32
 UTS_MACHINE    := sparc
 
-# We are adding -Wa,-Av8 to KBUILD_CFLAGS to deal with a specs bug in some
-# versions of gcc.  Some gcc versions won't pass -Av8 to binutils when you
-# give -mcpu=v8.  This silently worked with older bintutils versions but
-# does not any more.
-KBUILD_CFLAGS  += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
-KBUILD_CFLAGS  += -Wa,-Av8
-
-KBUILD_AFLAGS  += -m32 -Wa,-Av8
+cpuflags-$(CONFIG_SPARC_CPU_LEON3)	:= -mcpu=leon3
+cpuflags-$(CONFIG_SPARC_CPU_LEON5)	:= -mcpu=leon5
+
+KBUILD_CFLAGS  += -m32 $(cpuflags-y) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+KBUILD_AFLAGS  += -m32 $(cpuflags-y)
 
 else
 #####
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] sparc32: Add cmpxchg support using CAS
  2023-12-29 20:06 [PATCH 0/4] sparc32: Use CAS for atomic support Sam Ravnborg
  2023-12-29 20:07 ` [PATCH 1/4] sparc32: Add support for specifying -mcpu Sam Ravnborg
@ 2023-12-29 20:07 ` Sam Ravnborg
  2023-12-29 20:08 ` [PATCH 3/4] sparc32: Add atomic bitops " Sam Ravnborg
  2023-12-29 20:08 ` [PATCH 4/4] sparc32: Add atomic " Sam Ravnborg
  3 siblings, 0 replies; 6+ messages in thread
From: Sam Ravnborg @ 2023-12-29 20:07 UTC (permalink / raw)
  To: David S. Miller, Arnd Bergmann, Andreas Larsson, sparclinux

Utilize the casa instruction to implement cmpxchg support.

The implementation is based on the patch:

    0002-sparc32-leon-Add-support-for-atomic-operations-with-.patch
    included in gaisler-buildroot-2023.02-1.0

Drop the emulated version as the minimum supported CPU is leon3, and
leon3 has CAS support.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Arnd Bergmann <arnd@kernel.org>
---
 arch/sparc/include/asm/cmpxchg_32.h | 72 +++++++++++++++++------------
 arch/sparc/lib/atomic32.c           | 42 -----------------
 2 files changed, 42 insertions(+), 72 deletions(-)

diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h
index d0af82c240b7..a35f2aa5d2ce 100644
--- a/arch/sparc/include/asm/cmpxchg_32.h
+++ b/arch/sparc/include/asm/cmpxchg_32.h
@@ -12,10 +12,21 @@
 #ifndef __ARCH_SPARC_CMPXCHG__
 #define __ARCH_SPARC_CMPXCHG__
 
-unsigned long __xchg_u32(volatile u32 *m, u32 new);
-void __xchg_called_with_bad_pointer(void);
+void __xchg_called_with_bad_pointer(void)
+	__compiletime_error("Bad argument size for xchg");
 
-static __always_inline unsigned long __arch_xchg(unsigned long x, __volatile__ void * ptr, int size)
+static __always_inline
+unsigned long __xchg_u32(volatile unsigned long *m, unsigned long val)
+{
+	asm volatile("swap [%2], %0"
+		     : "=&r" (val)
+		     : "0" (val), "r" (m)
+		     : "memory");
+	return val;
+}
+
+static __always_inline
+unsigned long __arch_xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
 	case 4:
@@ -25,25 +36,31 @@ static __always_inline unsigned long __arch_xchg(unsigned long x, __volatile__ v
 	return x;
 }
 
-#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__arch_xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
+#define arch_xchg(ptr,x)						\
+({									\
+ 	(__typeof__(*(ptr))) __arch_xchg((unsigned long)(x),		\
+					 (ptr),				\
+					 sizeof(*(ptr)));		\
+})
 
-/* Emulate cmpxchg() the same way we emulate atomics,
- * by hashing the object address and indexing into an array
- * of spinlocks to get a bit of performance...
- *
- * See arch/sparc/lib/atomic32.c for implementation.
- *
- * Cribbed from <asm-parisc/atomic.h>
- */
+void __cmpxchg_called_with_bad_pointer(void)
+	__compiletime_error("Bad argument size for cmpxchg");
 
-/* bug catcher for when unsupported size is used - won't link */
-void __cmpxchg_called_with_bad_pointer(void);
 /* we only need to support cmpxchg of a u32 on sparc */
-unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_);
+static __always_inline
+unsigned long __cmpxchg_u32(volatile int *m, int old, int new)
+{
+	asm volatile("casa [%2] 0xb, %3, %0"
+		     : "=&r" (new)
+		     : "0" (new), "r" (m), "r" (old)
+		     : "memory");
+
+	return new;
+}
 
 /* don't worry...optimizer will get rid of most of this */
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+static __always_inline
+unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
 {
 	switch (size) {
 	case 4:
@@ -52,6 +69,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
 		__cmpxchg_called_with_bad_pointer();
 		break;
 	}
+
 	return old;
 }
 
@@ -59,22 +77,16 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
 ({									\
 	__typeof__(*(ptr)) _o_ = (o);					\
 	__typeof__(*(ptr)) _n_ = (n);					\
-	(__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	\
-			(unsigned long)_n_, sizeof(*(ptr)));		\
+									\
+	(__typeof__(*(ptr))) __cmpxchg((ptr),				\
+				       (unsigned long)_o_,		\
+				       (unsigned long)_n_,		\
+				       sizeof(*(ptr)));			\
 })
 
-u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new);
-#define arch_cmpxchg64(ptr, old, new)	__cmpxchg_u64(ptr, old, new)
-
-#include <asm-generic/cmpxchg-local.h>
-
 /*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
+ * We can not support 64-bit cmpxchg using LEON CASA. Better fail to link than
+ * pretend we can support something that is not atomic towards 64-bit writes.
  */
-#define arch_cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 
 #endif /* __ARCH_SPARC_CMPXCHG__ */
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index cf80d1ae352b..f378471adeca 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -158,45 +158,3 @@ unsigned long sp32___change_bit(unsigned long *addr, unsigned long mask)
 	return old & mask;
 }
 EXPORT_SYMBOL(sp32___change_bit);
-
-unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new)
-{
-	unsigned long flags;
-	u32 prev;
-
-	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
-	if ((prev = *ptr) == old)
-		*ptr = new;
-	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
-
-	return (unsigned long)prev;
-}
-EXPORT_SYMBOL(__cmpxchg_u32);
-
-u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new)
-{
-	unsigned long flags;
-	u64 prev;
-
-	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
-	if ((prev = *ptr) == old)
-		*ptr = new;
-	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
-
-	return prev;
-}
-EXPORT_SYMBOL(__cmpxchg_u64);
-
-unsigned long __xchg_u32(volatile u32 *ptr, u32 new)
-{
-	unsigned long flags;
-	u32 prev;
-
-	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
-	prev = *ptr;
-	*ptr = new;
-	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
-
-	return (unsigned long)prev;
-}
-EXPORT_SYMBOL(__xchg_u32);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] sparc32: Add atomic bitops support using CAS
  2023-12-29 20:06 [PATCH 0/4] sparc32: Use CAS for atomic support Sam Ravnborg
  2023-12-29 20:07 ` [PATCH 1/4] sparc32: Add support for specifying -mcpu Sam Ravnborg
  2023-12-29 20:07 ` [PATCH 2/4] sparc32: Add cmpxchg support using CAS Sam Ravnborg
@ 2023-12-29 20:08 ` Sam Ravnborg
  2023-12-29 20:08 ` [PATCH 4/4] sparc32: Add atomic " Sam Ravnborg
  3 siblings, 0 replies; 6+ messages in thread
From: Sam Ravnborg @ 2023-12-29 20:08 UTC (permalink / raw)
  To: David S. Miller, Arnd Bergmann, Andreas Larsson, sparclinux

This implements the atomic bit operations using the CAS instruction
so they are atomic.

The implementation uses a single asm helper, to make the code as readable
as possible. The implementation is done inline in bitops/atomic.h to
mirror the structure used in asm-generic.
As an added benefit the bitops can be instrumented.

The generated code is more compact with the majority implemented in C as
this allows the compiler to do optimizations especially when the
arguments passed are constant.

The old emulated bitops implementation is no longer used and deleted.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Arnd Bergmann <arnd@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
---
 arch/sparc/include/asm/bitops/atomic_32.h | 124 ++++++++++++++++++++++
 arch/sparc/include/asm/bitops_32.h        |  71 +------------
 arch/sparc/lib/atomic32.c                 |  39 -------
 3 files changed, 125 insertions(+), 109 deletions(-)
 create mode 100644 arch/sparc/include/asm/bitops/atomic_32.h

diff --git a/arch/sparc/include/asm/bitops/atomic_32.h b/arch/sparc/include/asm/bitops/atomic_32.h
new file mode 100644
index 000000000000..b9e33d21b58d
--- /dev/null
+++ b/arch/sparc/include/asm/bitops/atomic_32.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SPARC_BITOPS_ATOMIC_H_
+#define __ASM_SPARC_BITOPS_ATOMIC_H_
+
+#include <linux/atomic.h>
+#include <linux/compiler.h>
+
+#include <asm/asi.h>
+#include <asm/barrier.h>
+
+static __always_inline
+int __boa_casa(volatile unsigned long *p,
+	       unsigned long check,
+	       unsigned long swap)
+{
+	// casa [p], check, swap
+	// check == swap for success, otherwise try again
+	asm volatile("casa      [%2] 0xb, %3, %0"
+		     : "=&r" (swap)
+		     : "0" (swap), "r" (p), "r" (check)
+		     : "memory");
+
+	return swap;
+}
+
+static __always_inline void
+arch_set_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check | mask;
+	} while (__boa_casa(p, check, swap) != check);
+}
+
+static __always_inline void
+arch_clear_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check & ~mask;
+	} while (__boa_casa(p, check, swap) != check);
+}
+
+static __always_inline void
+arch_change_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check ^ mask;
+	} while (__boa_casa(p, check, swap) != check);
+}
+
+static __always_inline int
+arch_test_and_set_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check | mask;
+	} while (__boa_casa(p, check, swap) != check);
+
+	return !!(check & mask);
+}
+
+static __always_inline int
+arch_test_and_clear_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check & ~mask;
+	} while (__boa_casa(p, check, swap) != check);
+
+	return !!(check & mask);
+}
+
+static __always_inline int
+arch_test_and_change_bit(unsigned int nr, volatile unsigned long *p)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long check;
+	unsigned long swap;
+
+	p += BIT_WORD(nr);
+
+	do {
+		check = *p;
+		swap = check ^ mask;
+	} while (__boa_casa(p, check, swap) != check);
+
+	return !!(check & mask);
+}
+
+#include <asm-generic/bitops/instrumented-atomic.h>
+
+#endif /* __ASM_SPARC_BITOPS_ATOMIC_H_ */
diff --git a/arch/sparc/include/asm/bitops_32.h b/arch/sparc/include/asm/bitops_32.h
index 3448c191b484..34279e9572a4 100644
--- a/arch/sparc/include/asm/bitops_32.h
+++ b/arch/sparc/include/asm/bitops_32.h
@@ -19,76 +19,7 @@
 #error only <linux/bitops.h> can be included directly
 #endif
 
-unsigned long sp32___set_bit(unsigned long *addr, unsigned long mask);
-unsigned long sp32___clear_bit(unsigned long *addr, unsigned long mask);
-unsigned long sp32___change_bit(unsigned long *addr, unsigned long mask);
-
-/*
- * Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
- */
-static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	return sp32___set_bit(ADDR, mask) != 0;
-}
-
-static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	(void) sp32___set_bit(ADDR, mask);
-}
-
-static inline int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	return sp32___clear_bit(ADDR, mask) != 0;
-}
-
-static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	(void) sp32___clear_bit(ADDR, mask);
-}
-
-static inline int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	return sp32___change_bit(ADDR, mask) != 0;
-}
-
-static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
-{
-	unsigned long *ADDR, mask;
-
-	ADDR = ((unsigned long *) addr) + (nr >> 5);
-	mask = 1 << (nr & 31);
-
-	(void) sp32___change_bit(ADDR, mask);
-}
-
+#include <asm/bitops/atomic_32.h>
 #include <asm-generic/bitops/non-atomic.h>
 
 #include <asm-generic/bitops/ffz.h>
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index f378471adeca..ed778f7ebe97 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -119,42 +119,3 @@ void arch_atomic_set(atomic_t *v, int i)
 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
 }
 EXPORT_SYMBOL(arch_atomic_set);
-
-unsigned long sp32___set_bit(unsigned long *addr, unsigned long mask)
-{
-	unsigned long old, flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
-	old = *addr;
-	*addr = old | mask;
-	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
-
-	return old & mask;
-}
-EXPORT_SYMBOL(sp32___set_bit);
-
-unsigned long sp32___clear_bit(unsigned long *addr, unsigned long mask)
-{
-	unsigned long old, flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
-	old = *addr;
-	*addr = old & ~mask;
-	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
-
-	return old & mask;
-}
-EXPORT_SYMBOL(sp32___clear_bit);
-
-unsigned long sp32___change_bit(unsigned long *addr, unsigned long mask)
-{
-	unsigned long old, flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
-	old = *addr;
-	*addr = old ^ mask;
-	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
-
-	return old & mask;
-}
-EXPORT_SYMBOL(sp32___change_bit);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] sparc32: Add atomic support using CAS
  2023-12-29 20:06 [PATCH 0/4] sparc32: Use CAS for atomic support Sam Ravnborg
                   ` (2 preceding siblings ...)
  2023-12-29 20:08 ` [PATCH 3/4] sparc32: Add atomic bitops " Sam Ravnborg
@ 2023-12-29 20:08 ` Sam Ravnborg
  3 siblings, 0 replies; 6+ messages in thread
From: Sam Ravnborg @ 2023-12-29 20:08 UTC (permalink / raw)
  To: David S. Miller, Arnd Bergmann, Andreas Larsson, sparclinux

Implement the atomic operations using the leon casa
instruction.

The implmentation uses a single asm helper, to make the code as readable
as possible. The generated code is more compact with the majority
implemented in C as this allows the compiler to do optimizations
especially when the arguments passed are constant.

The old emulated atomic implementation is no longer used and deleted.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Arnd Bergmann <arnd@kernel.org>
---
 arch/sparc/include/asm/atomic_32.h | 151 +++++++++++++++++++----------
 arch/sparc/lib/Makefile            |   2 +-
 arch/sparc/lib/atomic32.c          | 121 -----------------------
 3 files changed, 100 insertions(+), 174 deletions(-)
 delete mode 100644 arch/sparc/lib/atomic32.c

diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h
index 60ce2fe57fcd..54f39148c492 100644
--- a/arch/sparc/include/asm/atomic_32.h
+++ b/arch/sparc/include/asm/atomic_32.h
@@ -1,61 +1,108 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* atomic.h: These still suck, but the I-cache hit rate is higher.
- *
- * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
- * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
- * Copyright (C) 2007 Kyle McMartin (kyle@parisc-linux.org)
- *
- * Additions by Keith M Wesolowski (wesolows@foobazco.org) based
- * on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>.
- */
-
 #ifndef __ARCH_SPARC_ATOMIC__
 #define __ARCH_SPARC_ATOMIC__
 
 #include <linux/types.h>
 
 #include <asm/cmpxchg.h>
-#include <asm/barrier.h>
-#include <asm-generic/atomic64.h>
-
-int arch_atomic_add_return(int, atomic_t *);
-#define arch_atomic_add_return arch_atomic_add_return
-
-int arch_atomic_fetch_add(int, atomic_t *);
-#define arch_atomic_fetch_add arch_atomic_fetch_add
-
-int arch_atomic_fetch_and(int, atomic_t *);
-#define arch_atomic_fetch_and arch_atomic_fetch_and
-
-int arch_atomic_fetch_or(int, atomic_t *);
-#define arch_atomic_fetch_or arch_atomic_fetch_or
-
-int arch_atomic_fetch_xor(int, atomic_t *);
-#define arch_atomic_fetch_xor arch_atomic_fetch_xor
-
-int arch_atomic_cmpxchg(atomic_t *, int, int);
-#define arch_atomic_cmpxchg arch_atomic_cmpxchg
-
-int arch_atomic_xchg(atomic_t *, int);
-#define arch_atomic_xchg arch_atomic_xchg
-
-int arch_atomic_fetch_add_unless(atomic_t *, int, int);
-#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
-
-void arch_atomic_set(atomic_t *, int);
-
-#define arch_atomic_set_release(v, i)	arch_atomic_set((v), (i))
-
-#define arch_atomic_read(v)		READ_ONCE((v)->counter)
-
-#define arch_atomic_add(i, v)	((void)arch_atomic_add_return( (int)(i), (v)))
-#define arch_atomic_sub(i, v)	((void)arch_atomic_add_return(-(int)(i), (v)))
-
-#define arch_atomic_and(i, v)	((void)arch_atomic_fetch_and((i), (v)))
-#define arch_atomic_or(i, v)	((void)arch_atomic_fetch_or((i), (v)))
-#define arch_atomic_xor(i, v)	((void)arch_atomic_fetch_xor((i), (v)))
-
-#define arch_atomic_sub_return(i, v)	(arch_atomic_add_return(-(int)(i), (v)))
-#define arch_atomic_fetch_sub(i, v)	(arch_atomic_fetch_add (-(int)(i), (v)))
+#include <asm/rwonce.h>
+
+static __always_inline int arch_atomic_read(const atomic_t *v)
+{
+	return READ_ONCE(v->counter);
+}
+
+static __always_inline void arch_atomic_set(atomic_t *v, int i)
+{
+	WRITE_ONCE(v->counter, i);
+}
+
+static __always_inline
+int __atomic_casa(volatile int *p, int check, int swap)
+{
+	// casa [p], check, swap
+	// check == swap for success, otherwise try again
+	asm volatile("casa      [%2] 0xb, %3, %0"
+		     : "=&r" (swap)
+		     : "0" (swap), "r" (p), "r" (check)
+		     : "memory");
+
+	return swap;
+}
+
+/* Do v->counter c_op i */
+#define ATOMIC_OP(op, c_op)						\
+static inline void arch_atomic_##op(int i, atomic_t *v)			\
+{									\
+	int check;							\
+	int swap;							\
+									\
+	do {								\
+		check = v->counter;					\
+		swap = check c_op i;					\
+	} while (__atomic_casa(&v->counter, check, swap) != check);	\
+}
+
+/* Do v->counter c_op i, and return the result */
+#define ATOMIC_OP_RETURN(op, c_op)					\
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)		\
+{									\
+	int check;							\
+	int swap;							\
+									\
+	do {								\
+		check = v->counter;					\
+		swap = check c_op i;					\
+	} while (__atomic_casa(&v->counter, check, swap) != check);	\
+									\
+	return swap;							\
+}
+
+/* Do v->counter c_op i, and return the original v->counter value */
+#define ATOMIC_FETCH_OP(op, c_op)					\
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)		\
+{									\
+	int check;							\
+	int swap;							\
+									\
+	do {								\
+		check = v->counter;					\
+		swap = check c_op i;					\
+	} while (__atomic_casa(&v->counter, check, swap) != check);	\
+									\
+	return check;							\
+}
+
+ATOMIC_OP_RETURN(add, +)
+ATOMIC_OP_RETURN(sub, -)
+
+ATOMIC_FETCH_OP(add, +)
+ATOMIC_FETCH_OP(sub, -)
+ATOMIC_FETCH_OP(and, &)
+ATOMIC_FETCH_OP(or,  |)
+ATOMIC_FETCH_OP(xor, ^)
+
+ATOMIC_OP(add, +)
+ATOMIC_OP(sub, -)
+ATOMIC_OP(and, &)
+ATOMIC_OP(or,  |)
+ATOMIC_OP(xor, ^)
+
+#undef ATOMIC_FETCH_OP
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
+#define arch_atomic_add_return	arch_atomic_add_return
+#define arch_atomic_sub_return	arch_atomic_sub_return
+#define arch_atomic_fetch_add	arch_atomic_fetch_add
+#define arch_atomic_fetch_sub	arch_atomic_fetch_sub
+#define arch_atomic_fetch_and	arch_atomic_fetch_and
+#define arch_atomic_fetch_or	arch_atomic_fetch_or
+#define arch_atomic_fetch_xor	arch_atomic_fetch_xor
+#define arch_atomic_add		arch_atomic_add
+#define arch_atomic_sub		arch_atomic_sub
+#define arch_atomic_and		arch_atomic_and
+#define arch_atomic_or		arch_atomic_or
+#define arch_atomic_xor		arch_atomic_xor
 
 #endif /* !(__ARCH_SPARC_ATOMIC__) */
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 063556fe2cb1..907f497bfcec 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -52,5 +52,5 @@ lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o
 lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
 
 obj-$(CONFIG_SPARC64) += iomap.o
-obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o
+obj-$(CONFIG_SPARC32) += ucmpdi2.o
 obj-$(CONFIG_SPARC64) += PeeCeeI.o
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
deleted file mode 100644
index ed778f7ebe97..000000000000
--- a/arch/sparc/lib/atomic32.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * atomic32.c: 32-bit atomic_t implementation
- *
- * Copyright (C) 2004 Keith M Wesolowski
- * Copyright (C) 2007 Kyle McMartin
- * 
- * Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf
- */
-
-#include <linux/atomic.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-
-#ifdef CONFIG_SMP
-#define ATOMIC_HASH_SIZE	4
-#define ATOMIC_HASH(a)	(&__atomic_hash[(((unsigned long)a)>>8) & (ATOMIC_HASH_SIZE-1)])
-
-spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
-	[0 ... (ATOMIC_HASH_SIZE-1)] = __SPIN_LOCK_UNLOCKED(__atomic_hash)
-};
-
-#else /* SMP */
-
-static DEFINE_SPINLOCK(dummy);
-#define ATOMIC_HASH_SIZE	1
-#define ATOMIC_HASH(a)		(&dummy)
-
-#endif /* SMP */
-
-#define ATOMIC_FETCH_OP(op, c_op)					\
-int arch_atomic_fetch_##op(int i, atomic_t *v)				\
-{									\
-	int ret;							\
-	unsigned long flags;						\
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);			\
-									\
-	ret = v->counter;						\
-	v->counter c_op i;						\
-									\
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);			\
-	return ret;							\
-}									\
-EXPORT_SYMBOL(arch_atomic_fetch_##op);
-
-#define ATOMIC_OP_RETURN(op, c_op)					\
-int arch_atomic_##op##_return(int i, atomic_t *v)			\
-{									\
-	int ret;							\
-	unsigned long flags;						\
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);			\
-									\
-	ret = (v->counter c_op i);					\
-									\
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);			\
-	return ret;							\
-}									\
-EXPORT_SYMBOL(arch_atomic_##op##_return);
-
-ATOMIC_OP_RETURN(add, +=)
-
-ATOMIC_FETCH_OP(add, +=)
-ATOMIC_FETCH_OP(and, &=)
-ATOMIC_FETCH_OP(or, |=)
-ATOMIC_FETCH_OP(xor, ^=)
-
-#undef ATOMIC_FETCH_OP
-#undef ATOMIC_OP_RETURN
-
-int arch_atomic_xchg(atomic_t *v, int new)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);
-	ret = v->counter;
-	v->counter = new;
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-	return ret;
-}
-EXPORT_SYMBOL(arch_atomic_xchg);
-
-int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);
-	ret = v->counter;
-	if (likely(ret == old))
-		v->counter = new;
-
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-	return ret;
-}
-EXPORT_SYMBOL(arch_atomic_cmpxchg);
-
-int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);
-	ret = v->counter;
-	if (ret != u)
-		v->counter += a;
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-	return ret;
-}
-EXPORT_SYMBOL(arch_atomic_fetch_add_unless);
-
-/* Atomic operations are already serializing */
-void arch_atomic_set(atomic_t *v, int i)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(ATOMIC_HASH(v), flags);
-	v->counter = i;
-	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-}
-EXPORT_SYMBOL(arch_atomic_set);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/4] sparc32: Add support for specifying -mcpu
  2023-12-29 20:07 ` [PATCH 1/4] sparc32: Add support for specifying -mcpu Sam Ravnborg
@ 2024-04-26 16:52   ` Andreas Larsson
  0 siblings, 0 replies; 6+ messages in thread
From: Andreas Larsson @ 2024-04-26 16:52 UTC (permalink / raw)
  To: Sam Ravnborg, David S. Miller, Arnd Bergmann, sparclinux

On 2023-12-29 21:07, Sam Ravnborg wrote:
> Add support for selecting the CPU architecture.
> The default is leon3 - which is the minimum required as the kernel uses
> CAS instructions.
> 
> Inspired by (from gaisler-buildroot-2023.02-1.0):
>     0001-sparc32-leon-Build-with-mcpu-leon3-for-SPARC_LEON.patch
>     0028-sparc32-leon-Make-what-mcpu-to-be-used-configurable-.patch
> 
> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> Cc: Andreas Larsson <andreas@gaisler.com>
> Cc: Arnd Bergmann <arnd@kernel.org>
> Cc: "David S. Miller" <davem@davemloft.net>
> ---
>  arch/sparc/Kconfig  | 24 ++++++++++++++++++++++++
>  arch/sparc/Makefile | 13 +++++--------
>  2 files changed, 29 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
> index 1b9cf7f3c500..e94783ceb409 100644
> --- a/arch/sparc/Kconfig
> +++ b/arch/sparc/Kconfig
> @@ -161,6 +161,30 @@ config ARCH_SUPPORTS_UPROBES
>  
>  menu "Processor type and features"
>  
> +choice
> +	prompt "LEON architecture"
> +	default SPARC_CPU_LEON3
> +	help
> +	  Select the architecture the kernel shall be built for
> +
> +config SPARC_CPU_LEON3
> +	prompt "LEON 3"

This should rather be bool than prompt...

> +	help
> +	  Build the kernel for the LEON 3 architecture
> +
> +config SPARC_CPU_LEON5
> +	prompt "LEON 5"

...and the same here.

> +	help
> +	  Build the kernel for the LEON 5 architecture
> +
> +config SPARC_CPU_DEFAULT
> +	bool "Toolchain default"
> +	help
> +	  Build the kernel with no -mcpu option, getting the default
> +	  for the toolchain that is being used.
> +
> +endchoice
> +
>  config SMP
>  	bool "Symmetric multi-processing support"
>  	help
> diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
> index 5f6035936131..3c3a1fd8c873 100644
> --- a/arch/sparc/Makefile
> +++ b/arch/sparc/Makefile
> @@ -25,14 +25,11 @@ KBUILD_LDFLAGS := -m elf32_sparc
>  export BITS    := 32
>  UTS_MACHINE    := sparc
>  
> -# We are adding -Wa,-Av8 to KBUILD_CFLAGS to deal with a specs bug in some
> -# versions of gcc.  Some gcc versions won't pass -Av8 to binutils when you
> -# give -mcpu=v8.  This silently worked with older bintutils versions but
> -# does not any more.
> -KBUILD_CFLAGS  += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
> -KBUILD_CFLAGS  += -Wa,-Av8
> -
> -KBUILD_AFLAGS  += -m32 -Wa,-Av8
> +cpuflags-$(CONFIG_SPARC_CPU_LEON3)	:= -mcpu=leon3
> +cpuflags-$(CONFIG_SPARC_CPU_LEON5)	:= -mcpu=leon5
> +
> +KBUILD_CFLAGS  += -m32 $(cpuflags-y) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
> +KBUILD_AFLAGS  += -m32 $(cpuflags-y)
>  
>  else
>  #####

As said in the sunset thread, more vetting is needed from my side, so no
need to respin this series yet.

Thanks,
Andreas

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-04-26 16:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-29 20:06 [PATCH 0/4] sparc32: Use CAS for atomic support Sam Ravnborg
2023-12-29 20:07 ` [PATCH 1/4] sparc32: Add support for specifying -mcpu Sam Ravnborg
2024-04-26 16:52   ` Andreas Larsson
2023-12-29 20:07 ` [PATCH 2/4] sparc32: Add cmpxchg support using CAS Sam Ravnborg
2023-12-29 20:08 ` [PATCH 3/4] sparc32: Add atomic bitops " Sam Ravnborg
2023-12-29 20:08 ` [PATCH 4/4] sparc32: Add atomic " Sam Ravnborg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.