* [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* 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
* [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