diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-09-15 08:52:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 19:32:21 +0100 |
commit | ebfaebae364c3631c70467bf89a63b341d0f0949 (patch) | |
tree | 837833970842137f0ca9a4992e30a30a12cde241 /include/asm-mips/futex.h | |
parent | 9dbdfce85c165faa45509ca3b18deaa5f9dfbc12 (diff) | |
download | op-kernel-dev-ebfaebae364c3631c70467bf89a63b341d0f0949.zip op-kernel-dev-ebfaebae364c3631c70467bf89a63b341d0f0949.tar.gz |
Futexes for MIPS, for the time being only the R10000_LLSC_WAR version.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'include/asm-mips/futex.h')
-rw-r--r-- | include/asm-mips/futex.h | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index 9feff4ce..2454c44 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -3,10 +3,45 @@ #ifdef __KERNEL__ +#include <linux/config.h> #include <linux/futex.h> #include <asm/errno.h> #include <asm/uaccess.h> +#ifdef CONFIG_SMP +#define __FUTEX_SMP_SYNC " sync \n" +#else +#define __FUTEX_SMP_SYNC +#endif + +#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)); \ +} + static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) { @@ -25,10 +60,25 @@ 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); + break; + case FUTEX_OP_ADD: + __futex_atomic_op("addu $1, %1, %z4", + ret, oldval, uaddr, oparg); + break; case FUTEX_OP_OR: + __futex_atomic_op("or $1, %1, %z4", + ret, oldval, uaddr, oparg); + break; case FUTEX_OP_ANDN: + __futex_atomic_op("and $1, %1, %z4", + ret, oldval, uaddr, ~oparg); + break; case FUTEX_OP_XOR: + __futex_atomic_op("xor $1, %1, %z4", + ret, oldval, uaddr, oparg); + break; default: ret = -ENOSYS; } |