From: Imre Kaloz <kaloz@kernel.org>
To: Andreas Larsson <andreas@gaisler.com>, sparclinux@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
linux-kernel@vger.kernel.org, Magnus Lindholm <linmag7@gmail.com>
Subject: [PATCH 1/3] sparc32: support futexes on SMP
Date: Sun, 27 Sep 2026 02:58:19 +0200 [thread overview]
Message-ID: <20260927005821.8369-2-kaloz@kernel.org> (raw)
In-Reply-To: <20260927005821.8369-1-kaloz@kernel.org>
asm-generic/futex.h provides the futex atomic ops for UP only, so FUTEX
has depended on !(SPARC32 && SMP).
Implement them in atomic32.c for both. LEON parts that implement casa
run it on the user word, as user code updates the word with casa there
and takes no kernel lock. Other CPUs have no compare-and-swap; the ops
serialize on __atomic_hash, which lets a kernel emulation of user casa
share the lock.
casa is optional on LEON, so it is probed once at boot. On a part
without it the kernel-mode illegal_instruction is fixed up from the
exception table.
Signed-off-by: Imre Kaloz <kaloz@kernel.org>
---
arch/sparc/include/asm/futex_32.h | 6 +-
arch/sparc/kernel/traps_32.c | 13 +++-
arch/sparc/lib/atomic32.c | 122 ++++++++++++++++++++++++++++++
init/Kconfig | 1 -
4 files changed, 139 insertions(+), 3 deletions(-)
diff --git a/arch/sparc/include/asm/futex_32.h b/arch/sparc/include/asm/futex_32.h
index 6a332a9f099c..2271aad566f8 100644
--- a/arch/sparc/include/asm/futex_32.h
+++ b/arch/sparc/include/asm/futex_32.h
@@ -1,6 +1,10 @@
#ifndef _ASM_FUTEX_H
#define _ASM_FUTEX_H
-#include <asm-generic/futex.h>
+#include <linux/types.h>
+
+int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr);
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval);
#endif
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c
index bb149f6cc34b..e1d50820c376 100644
--- a/arch/sparc/kernel/traps_32.c
+++ b/arch/sparc/kernel/traps_32.c
@@ -11,6 +11,7 @@
*/
#include <linux/cpu.h>
+#include <linux/extable.h>
#include <linux/sched/mm.h>
#include <linux/sched/debug.h>
#include <linux/mm_types.h>
@@ -108,8 +109,18 @@ void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- if(psr & PSR_PS)
+ if (psr & PSR_PS) {
+ const struct exception_table_entry *entry;
+
+ /* The casa probe on a CPU without casa. */
+ entry = search_exception_tables(pc);
+ if (entry) {
+ regs->pc = entry->fixup;
+ regs->npc = regs->pc + 4;
+ return;
+ }
die_if_kernel("Kernel illegal instruction", regs);
+ }
#ifdef TRAP_DEBUG
printk("Ill instr. at pc=%08lx instruction is %08lx\n",
regs->pc, *(unsigned long *)regs->pc);
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index 8ae880ebf07a..be712c2917d5 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -9,8 +9,13 @@
*/
#include <linux/atomic.h>
+#include <linux/futex.h>
+#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/cpu_type.h>
+#include <asm/futex.h>
#ifdef CONFIG_SMP
#define ATOMIC_HASH_SIZE 4
@@ -195,3 +200,120 @@ unsigned long __xchg_u32(volatile u32 *ptr, u32 new)
return (unsigned long)prev;
}
EXPORT_SYMBOL(__xchg_u32);
+
+/* Only some LEON parts implement casa. */
+static bool sparc32_casa __ro_after_init;
+
+static int __casa_user(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
+{
+ /*
+ * casa [%o0] 0xb, %o1, %o2, as a word any assembler accepts. ASI
+ * 0x0b is the supervisor address space; the emulated casa in
+ * cas_emu_32.c instead accepts the user ASIs 0x0a and 0x80.
+ */
+ register u32 __user *uaddr_r asm("o0") = uaddr;
+ register u32 oldval_r asm("o1") = oldval;
+ register u32 newval_r asm("o2") = newval;
+ int ret = 0;
+
+ __asm__ __volatile__(
+ "1: .word 0xd5e20169\n"
+ "2:\n"
+ " .section .fixup,#alloc,#execinstr\n"
+ " .align 4\n"
+ "3: sethi %%hi(2b), %0\n"
+ " jmpl %0 + %%lo(2b), %%g0\n"
+ " mov %4, %0\n"
+ " .previous\n"
+ " .section __ex_table,#alloc\n"
+ " .align 4\n"
+ " .word 1b, 3b\n"
+ " .previous\n"
+ : "+r" (ret), "+r" (newval_r)
+ : "r" (uaddr_r), "r" (oldval_r), "i" (-EFAULT)
+ : "memory");
+
+ *uval = newval_r;
+ return ret;
+}
+
+/* Without casa the illegal_instruction trap takes the fixup above. */
+static int __init sparc32_casa_probe(void)
+{
+ u32 word = 0, val;
+
+ if (sparc_cpu_model == sparc_leon)
+ sparc32_casa = !__casa_user(&val, (u32 __force __user *)&word,
+ 0, 1);
+ return 0;
+}
+early_initcall(sparc32_casa_probe);
+
+/*
+ * Without casa, user CAS is emulated under the same lock. ATOMIC_HASH()
+ * uses page offset bits only, so every mapping of a word takes one lock.
+ */
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ if (!access_ok(uaddr, sizeof(u32)))
+ return -EFAULT;
+ if (sparc32_casa)
+ return __casa_user(uval, uaddr, oldval, newval);
+
+ /* Every caller already runs with page faults disabled. */
+ spin_lock_irqsave(ATOMIC_HASH(uaddr), flags);
+ ret = __get_user(val, uaddr);
+ if (!ret && val == oldval)
+ ret = __put_user(newval, uaddr);
+ spin_unlock_irqrestore(ATOMIC_HASH(uaddr), flags);
+
+ if (!ret)
+ *uval = val;
+ return ret;
+}
+
+int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
+{
+ u32 oldval, newval, val;
+ int ret;
+
+ if (get_user(oldval, uaddr))
+ return -EFAULT;
+
+ for (;;) {
+ switch (op) {
+ case FUTEX_OP_SET:
+ newval = oparg;
+ break;
+ case FUTEX_OP_ADD:
+ newval = oldval + oparg;
+ break;
+ case FUTEX_OP_OR:
+ newval = oldval | oparg;
+ break;
+ case FUTEX_OP_ANDN:
+ newval = oldval & ~oparg;
+ break;
+ case FUTEX_OP_XOR:
+ newval = oldval ^ oparg;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ ret = futex_atomic_cmpxchg_inatomic(&val, uaddr, oldval, newval);
+ if (ret)
+ return ret;
+ if (val == oldval)
+ break;
+ oldval = val;
+ }
+
+ *oval = oldval;
+ return 0;
+}
diff --git a/init/Kconfig b/init/Kconfig
index 8583d9f06c52..9eb8086af7db 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1875,7 +1875,6 @@ config BASE_SMALL
config FUTEX
bool "Enable futex support" if EXPERT
- depends on !(SPARC32 && SMP)
default y
imply RT_MUTEXES
help
--
2.47.3
next prev parent reply other threads:[~2026-09-27 0:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 0:58 [PATCH 0/3] sparc32: SMP futexes, casa and idiv emulation Imre Kaloz
2026-09-27 0:58 ` Imre Kaloz [this message]
2026-09-27 0:58 ` [PATCH 2/3] sparc32: emulate casa on V8 CPUs Imre Kaloz
2026-09-27 0:58 ` [PATCH 3/3] sparc32: emulate integer divide taken as illegal_instruction Imre Kaloz
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=20260927005821.8369-2-kaloz@kernel.org \
--to=kaloz@kernel.org \
--cc=andreas@gaisler.com \
--cc=davem@davemloft.net \
--cc=linmag7@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®