New patch.

I added more stuff to the commit log, unistd.h (which arch/xtensa use
for sort of the same thing), and a bounds check.

>From ccfe17892fde0e9032eee4de3519cdcb2f0282f5 Mon Sep 17 00:00:00 2001
From: Christian Svensson <b...@cmd.nu>
Date: Sat, 25 Jan 2014 15:42:36 +0000
Subject: [PATCH 1/2] openrisc: Add new atomic operations to or1k_atomic

OpenRISC does not offer any way to do atomic operations in user space.
In order to provide atomic operations we need to implement these
operations in kernel space.

These operations disables preemption by disabling interrupts while
executing their critical sections.

The following operations has been added:
 SWAP:     Atomically swap the values in pointers 1 and 2.
 CMPXCHG:  Writes new to *mem if *mem == old. Returns old *mem.
 XCHG:     Store NEW in *MEM and return the old value.
 ADD:      Add VAL to *MEM and return the old value of *MEM.
 DECPOS:   Decrement *MEM if it is > 0, and return the old value.
 AND:      Atomically *mem &= mask and return the old value of *mem.
 OR:       Atomically *mem |= mask and return the old value of *mem.
 UMAX:     If *mem < val, set *mem = max. Returns old value of *mem.
 UMIN:     If *mem > val, set *mem = min. Returns old value of *mem.

These operations have been chosen to satisfy the need of atomic.h in
glibc. While it is possible to only use CMPXCHG, the glibc
implementation of the others use a do-while loop to retry the operation
until it succeeds. In order to offer linear performance for these
operations they are therefore implemented in the syscall.

Signed-off-by: Christian Svensson <b...@cmd.nu>
---
 arch/openrisc/include/uapi/asm/unistd.h |   41 ++++++++++
 arch/openrisc/kernel/entry.S            |  136 ++++++++++++++++++++++++++++---
 2 files changed, 167 insertions(+), 10 deletions(-)

diff --git a/arch/openrisc/include/uapi/asm/unistd.h
b/arch/openrisc/include/uapi/asm/unistd.h
index ce40b71..13eb792 100644
--- a/arch/openrisc/include/uapi/asm/unistd.h
+++ b/arch/openrisc/include/uapi/asm/unistd.h
@@ -25,5 +25,46 @@

 #include <asm-generic/unistd.h>

+/*
+ * uint32 sys_or1k_atomic(uint32 op, ...)
+ *
+ * uint32 sys_or1k_atomic(SWAP, void *ptr1, void *ptr2)
+ *   Atomically swap the values in pointers 1 and 2.
+ *
+ * uint32 sys_or1k_atomic(CMPXCHG, uint32 *mem, uint32 old, uint32 new)
+ *   Writes new to *mem if *mem == old. Returns old *mem.
+ *
+ * uint32 sys_or1k_atomic(XCHG, uint32 *mem, uint32 new)
+ *   Store NEW in *MEM and return the old value.
+ *
+ * uint32 sys_or1k_atomic(ADD, uint32 *mem, uint32 val)
+ *   Add VAL to *MEM and return the old value of *MEM.
+ *
+ * uint32 sys_or1k_atomic(DECPOS, uint32 *mem)
+ *   Decrement *MEM if it is > 0, and return the old value.
+ *
+ * uint32 sys_or1k_atomic(AND, uint32 *mem, uint32 mask)
+ *   Atomically *mem &= mask and return the old value of *mem.
+ *
+ * uint32 sys_or1k_atomic(OR, uint32 *mem, uint32 mask)
+ *   Atomically *mem |= mask and return the old value of *mem.
+ *
+ * uint32 sys_or1k_atomic(UMAX, uint32 *mem, uint32 max)
+ *   If *mem < val, set *mem = max. Returns old value of *mem.
+ *
+ * uint32 sys_or1k_atomic(UMIN, uint32 *mem, uint32 min)
+ *   If *mem > val, set *mem = min. Returns old value of *mem.
+ */
+#define SYS_OR1K_ATOMIC_SWAP 1
+#define SYS_OR1K_ATOMIC_CMPXCHG 2
+#define SYS_OR1K_ATOMIC_XCHG 3
+#define SYS_OR1K_ATOMIC_ADD 4
+#define SYS_OR1K_ATOMIC_DECPOS 5
+#define SYS_OR1K_ATOMIC_AND 6
+#define SYS_OR1K_ATOMIC_OR 7
+#define SYS_OR1K_ATOMIC_UMAX 8
+#define SYS_OR1K_ATOMIC_UMIN 9
+#define SYS_OR1K_ATOMIC_COUNT 10
+
 #define __NR_or1k_atomic __NR_arch_specific_syscall
 __SYSCALL(__NR_or1k_atomic, sys_or1k_atomic)
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
index fec8bf9..7d16c0f2 100644
--- a/arch/openrisc/kernel/entry.S
+++ b/arch/openrisc/kernel/entry.S
@@ -1106,20 +1106,50 @@ ENTRY(sys_rt_sigreturn)

 /* This is a catch-all syscall for atomic instructions for the OpenRISC 1000.
  * The functions takes a variable number of parameters depending on which
- * particular flavour of atomic you want... parameter 1 is a flag identifying
- * the atomic in question.  Currently, this function implements the
- * following variants:
+ * particular flavour of atomic you want.
+ * Parameter 1 is a flag identifying the atomic in question.
  *
- * XCHG:
- *  @flag: 1
- *  @ptr1:
- *  @ptr2:
- * Atomically exchange the values in pointers 1 and 2.
+ * TODO: Flag value 0 can be used, and it is recommended that the next
+ * atomic instruction to be implemented uses it. Currently it is a no-op.
  *
+ * See arch/openrisc/include/uapi/asm/unistd.h for usage.
  */
-
 ENTRY(sys_or1k_atomic)
- /* FIXME: This ignores r3 and always does an XCHG */
+ /* TODO: validate mem ptr(s) */
+ l.sfgeui r3,SYS_OR1K_ATOMIC_COUNT
+ l.bf _atomic_invalid
+ l.movhi r19,hi(atomic_table)
+ l.ori r19,r19,lo(atomic_table)
+ l.slli r3,r3,3
+ l.add r19,r19,r3
+ l.jr r19
+ l.nop
+_atomic_invalid:
+ l.jr r9
+ l.nop
+atomic_table:
+ l.jr r9
+ l.nop
+ l.j _atomic_swap
+ l.nop
+ l.j _atomic_cmpxchg
+ l.nop
+ l.j _atomic_xchg
+ l.nop
+ l.j _atomic_add
+ l.nop
+ l.j _atomic_decpos
+ l.nop
+ l.j _atomic_and
+ l.nop
+ l.j _atomic_or
+ l.nop
+ l.j _atomic_max
+ l.nop
+ l.j _atomic_min
+ l.nop
+
+_atomic_swap:
  DISABLE_INTERRUPTS(r17,r19)
  l.lwz r29,0(r4)
  l.lwz r27,0(r5)
@@ -1129,4 +1159,90 @@ ENTRY(sys_or1k_atomic)
  l.jr r9
  l.or r11,r0,r0

+_atomic_cmpxchg:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.sfeq r29,r5
+ l.bnf _atomic_cmpxchg_done
+ l.nop
+
+ l.sw 0(r4),r6
+_atomic_cmpxchg_done:
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_xchg:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.sw 0(r4),r5
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_add:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.add r27,r29,r5
+ l.sw 0(r4),r27
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_decpos:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.sfgtsi r29,0
+ l.bnf _atomic_decpos_done
+ l.addi r27,r29,-1
+
+ l.sw 0(r4),r27
+_atomic_decpos_done:
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_and:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.and r27,r29,r5
+ l.sw 0(r4),r27
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_or:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.or r27,r29,r5
+ l.sw 0(r4),r27
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_max:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.sfltu r29,r5
+ l.bnf _atomic_max_done
+ l.nop
+
+ l.sw 0(r4),r5
+_atomic_max_done:
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
+
+_atomic_min:
+ DISABLE_INTERRUPTS(r17,r19)
+ l.lwz r29,0(r4)
+ l.sfgtu r29,r5
+ l.bnf _atomic_min_done
+ l.nop
+
+ l.sw 0(r4),r5
+_atomic_min_done:
+ ENABLE_INTERRUPTS(r17)
+ l.jr r9
+ l.or r11,r29,r0
 /* ============================================================[ EOF ]=== */
-- 
1.7.10.4
_______________________________________________
Linux mailing list
Linux@lists.openrisc.net
http://lists.openrisc.net/listinfo/linux

Reply via email to