diff options
author | Max Filippov | 2018-12-20 17:18:12 -0800 |
---|---|---|
committer | Max Filippov | 2019-05-07 10:36:31 -0700 |
commit | f7c34874f04a80d6c39a32f08da2529e59602d3c (patch) | |
tree | a225ab153205701d24bee7423fc950a9009cb533 /arch/xtensa/include/asm/futex.h | |
parent | d065fcf12c21348cbc125460f75332f467518fb1 (diff) |
xtensa: add exclusive atomics support
Implement atomic primitives using exclusive access opcodes available in
the recent xtensa cores.
Since l32ex/s32ex don't have any memory ordering guarantees don't define
__smp_mb__before_atomic/__smp_mb__after_atomic to make them use memw.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/include/asm/futex.h')
-rw-r--r-- | arch/xtensa/include/asm/futex.h | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index a67f801aa303..9538b0f7953c 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -19,6 +19,31 @@ #include <linux/uaccess.h> #include <linux/errno.h> +#if XCHAL_HAVE_EXCLUSIVE +#define __futex_atomic_op(insn, ret, old, uaddr, arg) \ + __asm__ __volatile( \ + "1: l32ex %[oldval], %[addr]\n" \ + insn "\n" \ + "2: s32ex %[newval], %[addr]\n" \ + " getex %[newval]\n" \ + " beqz %[newval], 1b\n" \ + " movi %[newval], 0\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 4\n" \ + " .literal_position\n" \ + "5: movi %[oldval], 3b\n" \ + " movi %[newval], %[fault]\n" \ + " jx %[oldval]\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .long 1b, 5b, 2b, 5b\n" \ + " .previous\n" \ + : [oldval] "=&r" (old), [newval] "=&r" (ret) \ + : [addr] "r" (uaddr), [oparg] "r" (arg), \ + [fault] "I" (-EFAULT) \ + : "memory") +#elif XCHAL_HAVE_S32C1I #define __futex_atomic_op(insn, ret, old, uaddr, arg) \ __asm__ __volatile( \ "1: l32i %[oldval], %[addr], 0\n" \ @@ -42,11 +67,12 @@ : [addr] "r" (uaddr), [oparg] "r" (arg), \ [fault] "I" (-EFAULT) \ : "memory") +#endif static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { -#if XCHAL_HAVE_S32C1I +#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE int oldval = 0, ret; pagefault_disable(); @@ -91,7 +117,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { -#if XCHAL_HAVE_S32C1I +#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE unsigned long tmp; int ret = 0; @@ -100,9 +126,19 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __asm__ __volatile__ ( " # futex_atomic_cmpxchg_inatomic\n" +#if XCHAL_HAVE_EXCLUSIVE + "1: l32ex %[tmp], %[addr]\n" + " s32i %[tmp], %[uval], 0\n" + " bne %[tmp], %[oldval], 2f\n" + " mov %[tmp], %[newval]\n" + "3: s32ex %[tmp], %[addr]\n" + " getex %[tmp]\n" + " beqz %[tmp], 1b\n" +#elif XCHAL_HAVE_S32C1I " wsr %[oldval], scompare1\n" "1: s32c1i %[newval], %[addr], 0\n" " s32i %[newval], %[uval], 0\n" +#endif "2:\n" " .section .fixup,\"ax\"\n" " .align 4\n" @@ -113,6 +149,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " .previous\n" " .section __ex_table,\"a\"\n" " .long 1b, 4b\n" +#if XCHAL_HAVE_EXCLUSIVE + " .long 3b, 4b\n" +#endif " .previous\n" : [ret] "+r" (ret), [newval] "+r" (newval), [tmp] "=&r" (tmp) : [addr] "r" (uaddr), [oldval] "r" (oldval), [uval] "r" (uval), |