diff options
Diffstat (limited to 'arch/mips/include/asm/futex.h')
| -rw-r--r-- | arch/mips/include/asm/futex.h | 138 |
1 files changed, 71 insertions, 67 deletions
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index 6ea15815d3ee..05832eb240fa 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -12,27 +12,34 @@ #include <linux/futex.h> #include <linux/uaccess.h> +#include <asm/asm-eva.h> #include <asm/barrier.h> +#include <asm/compiler.h> #include <asm/errno.h> -#include <asm/war.h> +#include <asm/sync.h> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include <asm-generic/futex.h> + +#define __futex_atomic_op(op, insn, ret, oldval, uaddr, oparg) \ { \ - if (cpu_has_llsc && R10000_LLSC_WAR) { \ + if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ - " .set mips3 \n" \ + " .set push \n" \ + " .set arch=r4000 \n" \ "1: ll %1, %4 # __futex_atomic_op \n" \ - " .set mips0 \n" \ + " .set pop \n" \ " " insn " \n" \ - " .set mips3 \n" \ + " .set arch=r4000 \n" \ "2: sc $1, %2 \n" \ " beqzl $1, 1b \n" \ - __WEAK_LLSC_MB \ + __stringify(__WEAK_LLSC_MB) " \n" \ "3: \n" \ + " .insn \n" \ " .set pop \n" \ - " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ "4: li %0, %6 \n" \ " j 3b \n" \ @@ -41,24 +48,28 @@ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ - : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "=r" (ret), "=&r" (oldval), \ + "=" GCC_OFF_SMALL_ASM() (*uaddr) \ + : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ + "i" (-EFAULT) \ : "memory"); \ } else if (cpu_has_llsc) { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ - " .set mips3 \n" \ - "1: ll %1, %4 # __futex_atomic_op \n" \ - " .set mips0 \n" \ + " .set push \n" \ + " .set "MIPS_ISA_ARCH_LEVEL" \n" \ + " " __SYNC(full, loongson3_war) " \n" \ + "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \ + " .set pop \n" \ " " insn " \n" \ - " .set mips3 \n" \ - "2: sc $1, %2 \n" \ + " .set "MIPS_ISA_ARCH_LEVEL" \n" \ + "2: "user_sc("$1", "%2")" \n" \ " beqz $1, 1b \n" \ - __WEAK_LLSC_MB \ + __stringify(__WEAK_LLSC_MB) " \n" \ "3: \n" \ + " .insn \n" \ " .set pop \n" \ - " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ "4: li %0, %6 \n" \ " j 3b \n" \ @@ -67,67 +78,53 @@ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ - : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "=r" (ret), "=&r" (oldval), \ + "=" GCC_OFF_SMALL_ASM() (*uaddr) \ + : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ + "i" (-EFAULT) \ : "memory"); \ - } else \ - ret = -ENOSYS; \ + } else { \ + /* fallback for non-SMP */ \ + ret = futex_atomic_op_inuser_local(op, oparg, oval, uaddr); \ + } \ } static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) + if (!access_ok(uaddr, sizeof(u32))) return -EFAULT; - pagefault_disable(); - switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); + __futex_atomic_op(op, "move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z5", + __futex_atomic_op(op, "addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z5", + __futex_atomic_op(op, "or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z5", + __futex_atomic_op(op, "and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z5", + __futex_atomic_op(op, "xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: ret = -ENOSYS; } - pagefault_enable(); + if (!ret) + *oval = oldval; - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } return ret; } @@ -138,24 +135,26 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, int ret = 0; u32 val; - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + if (!access_ok(uaddr, sizeof(u32))) return -EFAULT; - if (cpu_has_llsc && R10000_LLSC_WAR) { + if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) { __asm__ __volatile__( "# futex_atomic_cmpxchg_inatomic \n" " .set push \n" " .set noat \n" - " .set mips3 \n" + " .set push \n" + " .set arch=r4000 \n" "1: ll %1, %3 \n" " bne %1, %z4, 3f \n" - " .set mips0 \n" + " .set pop \n" " move $1, %z5 \n" - " .set mips3 \n" + " .set arch=r4000 \n" "2: sc $1, %2 \n" " beqzl $1, 1b \n" - __WEAK_LLSC_MB + __stringify(__WEAK_LLSC_MB) " \n" "3: \n" + " .insn \n" " .set pop \n" " .section .fixup,\"ax\" \n" "4: li %0, %6 \n" @@ -165,24 +164,27 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " "__UA_ADDR "\t1b, 4b \n" " "__UA_ADDR "\t2b, 4b \n" " .previous \n" - : "+r" (ret), "=&r" (val), "=R" (*uaddr) - : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) + : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), + "i" (-EFAULT) : "memory"); } else if (cpu_has_llsc) { __asm__ __volatile__( "# futex_atomic_cmpxchg_inatomic \n" " .set push \n" " .set noat \n" - " .set mips3 \n" - "1: ll %1, %3 \n" + " .set push \n" + " .set "MIPS_ISA_ARCH_LEVEL" \n" + " " __SYNC(full, loongson3_war) " \n" + "1: "user_ll("%1", "%3")" \n" " bne %1, %z4, 3f \n" - " .set mips0 \n" + " .set pop \n" " move $1, %z5 \n" - " .set mips3 \n" - "2: sc $1, %2 \n" + " .set "MIPS_ISA_ARCH_LEVEL" \n" + "2: "user_sc("$1", "%2")" \n" " beqz $1, 1b \n" - __WEAK_LLSC_MB - "3: \n" + "3: " __SYNC_ELSE(full, loongson3_war, __WEAK_LLSC_MB) "\n" + " .insn \n" " .set pop \n" " .section .fixup,\"ax\" \n" "4: li %0, %6 \n" @@ -192,11 +194,13 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " "__UA_ADDR "\t1b, 4b \n" " "__UA_ADDR "\t2b, 4b \n" " .previous \n" - : "+r" (ret), "=&r" (val), "=R" (*uaddr) - : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) + : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), + "i" (-EFAULT) : "memory"); - } else - return -ENOSYS; + } else { + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); + } *uval = val; return ret; |
