Ping!
On Fri, Feb 7, 2014 at 10:26 PM, Christian Svensson <christ...@cmd.nu> wrote: > 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