]> err.no Git - linux-2.6/commitdiff
Futexes for MIPS, for the time being only the R10000_LLSC_WAR version.
authorRalf Baechle <ralf@linux-mips.org>
Thu, 15 Sep 2005 08:52:34 +0000 (08:52 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Sat, 29 Oct 2005 18:32:21 +0000 (19:32 +0100)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
include/asm-mips/futex.h

index 9feff4ce1424bc390608326240be369eb13aa648..2454c44a8f54c11b99771784eb2f77974a4a3d9c 100644 (file)
@@ -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;
        }