This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / include / asm-mips / futex.h
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
new file mode 100644 (file)
index 0000000..12d118f
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#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"
+#else
+#define __FUTEX_SMP_SYNC
+#endif
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)             \
+{                                                                      \
+       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
+futex_atomic_op_inuser (int encoded_op, int __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(int)))
+               return -EFAULT;
+
+       inc_preempt_count();
+
+       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;
+       }
+
+       dec_preempt_count();
+
+       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;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+       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
+#endif