diff options
Diffstat (limited to 'include/asm-mips/futex.h')
-rw-r--r-- | include/asm-mips/futex.h | 153 |
1 files changed, 123 insertions, 30 deletions
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index a554089991f..1f94640becc 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -7,6 +7,7 @@ #include <linux/futex.h> #include <asm/errno.h> #include <asm/uaccess.h> +#include <asm/war.h> #ifdef CONFIG_SMP #define __FUTEX_SMP_SYNC " sync \n" @@ -16,30 +17,60 @@ #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " .set mips3 \n" \ - "1: ll %1, (%3) # __futex_atomic_op1 \n" \ - " .set mips0 \n" \ - " " insn " \n" \ - " .set mips3 \n" \ - "2: sc $1, (%3) \n" \ - " beqzl $1, 1b \n" \ - __FUTEX_SMP_SYNC \ - "3: \n" \ - " .set pop \n" \ - " .set mips0 \n" \ - " .section .fixup,\"ax\" \n" \ - "4: li %0, %5 \n" \ - " j 2b \n" \ - " .previous \n" \ - " .section __ex_table,\"a\" \n" \ - " "__UA_ADDR "\t1b, 4b \n" \ - " "__UA_ADDR "\t2b, 4b \n" \ - " .previous \n" \ - : "=r" (ret), "=r" (oldval) \ - : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ + if (cpu_has_llsc && R10000_LLSC_WAR) { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips3 \n" \ + "1: ll %1, %4 # __futex_atomic_op \n" \ + " .set mips0 \n" \ + " " insn " \n" \ + " .set mips3 \n" \ + "2: sc $1, %2 \n" \ + " beqzl $1, 1b \n" \ + __FUTEX_SMP_SYNC \ + "3: \n" \ + " .set pop \n" \ + " .set mips0 \n" \ + " .section .fixup,\"ax\" \n" \ + "4: li %0, %6 \n" \ + " j 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__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) \ + : "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" \ + " " insn " \n" \ + " .set mips3 \n" \ + "2: sc $1, %2 \n" \ + " beqz $1, 1b \n" \ + __FUTEX_SMP_SYNC \ + "3: \n" \ + " .set pop \n" \ + " .set mips0 \n" \ + " .section .fixup,\"ax\" \n" \ + "4: li %0, %6 \n" \ + " j 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__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) \ + : "memory"); \ + } else \ + ret = -ENOSYS; \ } static inline int @@ -60,23 +91,23 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg); + __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z4", + __futex_atomic_op("addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z4", + __futex_atomic_op("or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z4", + __futex_atomic_op("and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z4", + __futex_atomic_op("xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: @@ -102,7 +133,69 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) { - return -ENOSYS; + int retval; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + if (cpu_has_llsc && R10000_LLSC_WAR) { + __asm__ __volatile__( + "# futex_atomic_cmpxchg_inatomic \n" + " .set push \n" + " .set noat \n" + " .set mips3 \n" + "1: ll %0, %2 \n" + " bne %0, %z3, 3f \n" + " .set mips0 \n" + " move $1, %z4 \n" + " .set mips3 \n" + "2: sc $1, %1 \n" + " beqzl $1, 1b \n" + __FUTEX_SMP_SYNC + "3: \n" + " .set pop \n" + " .section .fixup,\"ax\" \n" + "4: li %0, %5 \n" + " j 3b \n" + " .previous \n" + " .section __ex_table,\"a\" \n" + " "__UA_ADDR "\t1b, 4b \n" + " "__UA_ADDR "\t2b, 4b \n" + " .previous \n" + : "=&r" (retval), "=R" (*uaddr) + : "R" (*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 %0, %2 \n" + " bne %0, %z3, 3f \n" + " .set mips0 \n" + " move $1, %z4 \n" + " .set mips3 \n" + "2: sc $1, %1 \n" + " beqz $1, 1b \n" + __FUTEX_SMP_SYNC + "3: \n" + " .set pop \n" + " .section .fixup,\"ax\" \n" + "4: li %0, %5 \n" + " j 3b \n" + " .previous \n" + " .section __ex_table,\"a\" \n" + " "__UA_ADDR "\t1b, 4b \n" + " "__UA_ADDR "\t2b, 4b \n" + " .previous \n" + : "=&r" (retval), "=R" (*uaddr) + : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "memory"); + } else + return -ENOSYS; + + return retval; } #endif |