All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sam Ravnborg <sam@ravnborg.org>
To: "David S. Miller" <davem@davemloft.net>,
	Arnd Bergmann <arnd@kernel.org>,
	Andreas Larsson <andreas@gaisler.com>,
	sparclinux@vger.kernel.org
Subject: [PATCH 3/4] sparc32: Add atomic bitops support using CAS
Date: Fri, 29 Dec 2023 21:08:25 +0100	[thread overview]
Message-ID: <20231229200825.GC4034411@ravnborg.org> (raw)
In-Reply-To: <20231229200604.GA4033529@ravnborg.org>

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


  parent reply	other threads:[~2023-12-29 20:08 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Sam Ravnborg [this message]
2023-12-29 20:08 ` [PATCH 4/4] sparc32: Add atomic " Sam Ravnborg

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=20231229200825.GC4034411@ravnborg.org \
    --to=sam@ravnborg.org \
    --cc=andreas@gaisler.com \
    --cc=arnd@kernel.org \
    --cc=davem@davemloft.net \
    --cc=sparclinux@vger.kernel.org \
    /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 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.