[MIPS] Update/fix futex assembly
authorRalf Baechle <ralf@linux-mips.org>
Wed, 3 May 2006 19:42:39 +0000 (20:42 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Wed, 31 May 2006 23:28:31 +0000 (00:28 +0100)
 o Implement futex_atomic_op_inuser() operation
 o Don't use the R10000-ll/sc bug workaround version for every processor.
   branch likely is deprecated and some historic ll/sc processors don't
   implement it.  In any case it's slow.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
include/asm-mips/futex.h

index a554089..12d118f 100644 (file)
@@ -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"
 
 #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, (%3)        # __futex_atomic_op     \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));   \
+       } else if (cpu_has_llsc) {                                      \
+               __asm__ __volatile__(                                   \
+               "       .set    push                            \n"     \
+               "       .set    noat                            \n"     \
+               "       .set    mips3                           \n"     \
+               "1:     ll      %1, (%3)        # __futex_atomic_op     \n" \
+               "       .set    mips0                           \n"     \
+               "       " insn  "                               \n"     \
+               "       .set    mips3                           \n"     \
+               "2:     sc      $1, (%3)                        \n"     \
+               "       beqz    $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));   \
+       } else                                                          \
+               ret = -ENOSYS;                                          \
 }
 
 static inline int
@@ -102,7 +131,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