Linux v2.6.15-rc6
[pohmelfs.git] / include / asm-mips / futex.h
blob2454c44a8f54c11b99771784eb2f77974a4a3d9c
1 #ifndef _ASM_FUTEX_H
2 #define _ASM_FUTEX_H
4 #ifdef __KERNEL__
6 #include <linux/config.h>
7 #include <linux/futex.h>
8 #include <asm/errno.h>
9 #include <asm/uaccess.h>
11 #ifdef CONFIG_SMP
12 #define __FUTEX_SMP_SYNC " sync \n"
13 #else
14 #define __FUTEX_SMP_SYNC
15 #endif
17 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
18 { \
19 __asm__ __volatile__( \
20 " .set push \n" \
21 " .set noat \n" \
22 " .set mips3 \n" \
23 "1: ll %1, (%3) # __futex_atomic_op1 \n" \
24 " .set mips0 \n" \
25 " " insn " \n" \
26 " .set mips3 \n" \
27 "2: sc $1, (%3) \n" \
28 " beqzl $1, 1b \n" \
29 __FUTEX_SMP_SYNC \
30 "3: \n" \
31 " .set pop \n" \
32 " .set mips0 \n" \
33 " .section .fixup,\"ax\" \n" \
34 "4: li %0, %5 \n" \
35 " j 2b \n" \
36 " .previous \n" \
37 " .section __ex_table,\"a\" \n" \
38 " "__UA_ADDR "\t1b, 4b \n" \
39 " "__UA_ADDR "\t2b, 4b \n" \
40 " .previous \n" \
41 : "=r" (ret), "=r" (oldval) \
42 : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \
45 static inline int
46 futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
48 int op = (encoded_op >> 28) & 7;
49 int cmp = (encoded_op >> 24) & 15;
50 int oparg = (encoded_op << 8) >> 20;
51 int cmparg = (encoded_op << 20) >> 20;
52 int oldval = 0, ret;
53 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
54 oparg = 1 << oparg;
56 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
57 return -EFAULT;
59 inc_preempt_count();
61 switch (op) {
62 case FUTEX_OP_SET:
63 __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg);
64 break;
66 case FUTEX_OP_ADD:
67 __futex_atomic_op("addu $1, %1, %z4",
68 ret, oldval, uaddr, oparg);
69 break;
70 case FUTEX_OP_OR:
71 __futex_atomic_op("or $1, %1, %z4",
72 ret, oldval, uaddr, oparg);
73 break;
74 case FUTEX_OP_ANDN:
75 __futex_atomic_op("and $1, %1, %z4",
76 ret, oldval, uaddr, ~oparg);
77 break;
78 case FUTEX_OP_XOR:
79 __futex_atomic_op("xor $1, %1, %z4",
80 ret, oldval, uaddr, oparg);
81 break;
82 default:
83 ret = -ENOSYS;
86 dec_preempt_count();
88 if (!ret) {
89 switch (cmp) {
90 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
91 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
92 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
93 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
94 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
95 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
96 default: ret = -ENOSYS;
99 return ret;
102 #endif
103 #endif