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

Reply via email to