This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / include / asm-mips / futex.h
1 #ifndef _ASM_FUTEX_H
2 #define _ASM_FUTEX_H
3
4 #ifdef __KERNEL__
5
6 #include <linux/config.h>
7 #include <linux/futex.h>
8 #include <asm/errno.h>
9 #include <asm/uaccess.h>
10 #include <asm/war.h>
11
12 #ifdef CONFIG_SMP
13 #define __FUTEX_SMP_SYNC "      sync                                    \n"
14 #else
15 #define __FUTEX_SMP_SYNC
16 #endif
17
18 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)              \
19 {                                                                       \
20         if (cpu_has_llsc && R10000_LLSC_WAR) {                          \
21                 __asm__ __volatile__(                                   \
22                 "       .set    push                            \n"     \
23                 "       .set    noat                            \n"     \
24                 "       .set    mips3                           \n"     \
25                 "1:     ll      %1, (%3)        # __futex_atomic_op     \n" \
26                 "       .set    mips0                           \n"     \
27                 "       " insn  "                               \n"     \
28                 "       .set    mips3                           \n"     \
29                 "2:     sc      $1, (%3)                        \n"     \
30                 "       beqzl   $1, 1b                          \n"     \
31                 __FUTEX_SMP_SYNC                                        \
32                 "3:                                             \n"     \
33                 "       .set    pop                             \n"     \
34                 "       .set    mips0                           \n"     \
35                 "       .section .fixup,\"ax\"                  \n"     \
36                 "4:     li      %0, %5                          \n"     \
37                 "       j       2b                              \n"     \
38                 "       .previous                               \n"     \
39                 "       .section __ex_table,\"a\"               \n"     \
40                 "       "__UA_ADDR "\t1b, 4b                    \n"     \
41                 "       "__UA_ADDR "\t2b, 4b                    \n"     \
42                 "       .previous                               \n"     \
43                 : "=r" (ret), "=r" (oldval)                             \
44                 : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT));   \
45         } else if (cpu_has_llsc) {                                      \
46                 __asm__ __volatile__(                                   \
47                 "       .set    push                            \n"     \
48                 "       .set    noat                            \n"     \
49                 "       .set    mips3                           \n"     \
50                 "1:     ll      %1, (%3)        # __futex_atomic_op     \n" \
51                 "       .set    mips0                           \n"     \
52                 "       " insn  "                               \n"     \
53                 "       .set    mips3                           \n"     \
54                 "2:     sc      $1, (%3)                        \n"     \
55                 "       beqz    $1, 1b                          \n"     \
56                 __FUTEX_SMP_SYNC                                        \
57                 "3:                                             \n"     \
58                 "       .set    pop                             \n"     \
59                 "       .set    mips0                           \n"     \
60                 "       .section .fixup,\"ax\"                  \n"     \
61                 "4:     li      %0, %5                          \n"     \
62                 "       j       2b                              \n"     \
63                 "       .previous                               \n"     \
64                 "       .section __ex_table,\"a\"               \n"     \
65                 "       "__UA_ADDR "\t1b, 4b                    \n"     \
66                 "       "__UA_ADDR "\t2b, 4b                    \n"     \
67                 "       .previous                               \n"     \
68                 : "=r" (ret), "=r" (oldval)                             \
69                 : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT));   \
70         } else                                                          \
71                 ret = -ENOSYS;                                          \
72 }
73
74 static inline int
75 futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
76 {
77         int op = (encoded_op >> 28) & 7;
78         int cmp = (encoded_op >> 24) & 15;
79         int oparg = (encoded_op << 8) >> 20;
80         int cmparg = (encoded_op << 20) >> 20;
81         int oldval = 0, ret;
82         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
83                 oparg = 1 << oparg;
84
85         if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
86                 return -EFAULT;
87
88         inc_preempt_count();
89
90         switch (op) {
91         case FUTEX_OP_SET:
92                 __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg);
93                 break;
94
95         case FUTEX_OP_ADD:
96                 __futex_atomic_op("addu $1, %1, %z4",
97                                   ret, oldval, uaddr, oparg);
98                 break;
99         case FUTEX_OP_OR:
100                 __futex_atomic_op("or   $1, %1, %z4",
101                                   ret, oldval, uaddr, oparg);
102                 break;
103         case FUTEX_OP_ANDN:
104                 __futex_atomic_op("and  $1, %1, %z4",
105                                   ret, oldval, uaddr, ~oparg);
106                 break;
107         case FUTEX_OP_XOR:
108                 __futex_atomic_op("xor  $1, %1, %z4",
109                                   ret, oldval, uaddr, oparg);
110                 break;
111         default:
112                 ret = -ENOSYS;
113         }
114
115         dec_preempt_count();
116
117         if (!ret) {
118                 switch (cmp) {
119                 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
120                 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
121                 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
122                 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
123                 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
124                 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
125                 default: ret = -ENOSYS;
126                 }
127         }
128         return ret;
129 }
130
131 static inline int
132 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
133 {
134         int retval;
135
136         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
137                 return -EFAULT;
138
139         if (cpu_has_llsc && R10000_LLSC_WAR) {
140                 __asm__ __volatile__(
141                 "# futex_atomic_cmpxchg_inatomic                        \n"
142                 "       .set    push                                    \n"
143                 "       .set    noat                                    \n"
144                 "       .set    mips3                                   \n"
145                 "1:     ll      %0, %2                                  \n"
146                 "       bne     %0, %z3, 3f                             \n"
147                 "       .set    mips0                                   \n"
148                 "       move    $1, %z4                                 \n"
149                 "       .set    mips3                                   \n"
150                 "2:     sc      $1, %1                                  \n"
151                 "       beqzl   $1, 1b                                  \n"
152                 __FUTEX_SMP_SYNC
153                 "3:                                                     \n"
154                 "       .set    pop                                     \n"
155                 "       .section .fixup,\"ax\"                          \n"
156                 "4:     li      %0, %5                                  \n"
157                 "       j       3b                                      \n"
158                 "       .previous                                       \n"
159                 "       .section __ex_table,\"a\"                       \n"
160                 "       "__UA_ADDR "\t1b, 4b                            \n"
161                 "       "__UA_ADDR "\t2b, 4b                            \n"
162                 "       .previous                                       \n"
163                 : "=&r" (retval), "=R" (*uaddr)
164                 : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
165                 : "memory");
166         } else if (cpu_has_llsc) {
167                 __asm__ __volatile__(
168                 "# futex_atomic_cmpxchg_inatomic                        \n"
169                 "       .set    push                                    \n"
170                 "       .set    noat                                    \n"
171                 "       .set    mips3                                   \n"
172                 "1:     ll      %0, %2                                  \n"
173                 "       bne     %0, %z3, 3f                             \n"
174                 "       .set    mips0                                   \n"
175                 "       move    $1, %z4                                 \n"
176                 "       .set    mips3                                   \n"
177                 "2:     sc      $1, %1                                  \n"
178                 "       beqz    $1, 1b                                  \n"
179                 __FUTEX_SMP_SYNC
180                 "3:                                                     \n"
181                 "       .set    pop                                     \n"
182                 "       .section .fixup,\"ax\"                          \n"
183                 "4:     li      %0, %5                                  \n"
184                 "       j       3b                                      \n"
185                 "       .previous                                       \n"
186                 "       .section __ex_table,\"a\"                       \n"
187                 "       "__UA_ADDR "\t1b, 4b                            \n"
188                 "       "__UA_ADDR "\t2b, 4b                            \n"
189                 "       .previous                                       \n"
190                 : "=&r" (retval), "=R" (*uaddr)
191                 : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
192                 : "memory");
193         } else
194                 return -ENOSYS;
195
196         return retval;
197 }
198
199 #endif
200 #endif