]>
Commit | Line | Data |
---|---|---|
0004a9df RB |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org) | |
7 | */ | |
4732efbe JJ |
8 | #ifndef _ASM_FUTEX_H |
9 | #define _ASM_FUTEX_H | |
10 | ||
11 | #ifdef __KERNEL__ | |
12 | ||
13 | #include <linux/futex.h> | |
730f412c | 14 | #include <linux/uaccess.h> |
a6813fe5 | 15 | #include <asm/asm-eva.h> |
0004a9df | 16 | #include <asm/barrier.h> |
b0984c43 | 17 | #include <asm/compiler.h> |
4732efbe | 18 | #include <asm/errno.h> |
6ee1da94 | 19 | #include <asm/war.h> |
4732efbe | 20 | |
ebfaebae RB |
21 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ |
22 | { \ | |
6ee1da94 RB |
23 | if (cpu_has_llsc && R10000_LLSC_WAR) { \ |
24 | __asm__ __volatile__( \ | |
25 | " .set push \n" \ | |
26 | " .set noat \n" \ | |
378ed6f0 | 27 | " .set push \n" \ |
a809d460 | 28 | " .set arch=r4000 \n" \ |
0307e8d0 | 29 | "1: ll %1, %4 # __futex_atomic_op \n" \ |
378ed6f0 | 30 | " .set pop \n" \ |
6ee1da94 | 31 | " " insn " \n" \ |
a809d460 | 32 | " .set arch=r4000 \n" \ |
0307e8d0 | 33 | "2: sc $1, %2 \n" \ |
6ee1da94 | 34 | " beqzl $1, 1b \n" \ |
17099b11 | 35 | __WEAK_LLSC_MB \ |
6ee1da94 | 36 | "3: \n" \ |
0e525e48 | 37 | " .insn \n" \ |
6ee1da94 | 38 | " .set pop \n" \ |
6ee1da94 | 39 | " .section .fixup,\"ax\" \n" \ |
0307e8d0 | 40 | "4: li %0, %6 \n" \ |
0f67e90e | 41 | " j 3b \n" \ |
6ee1da94 RB |
42 | " .previous \n" \ |
43 | " .section __ex_table,\"a\" \n" \ | |
44 | " "__UA_ADDR "\t1b, 4b \n" \ | |
45 | " "__UA_ADDR "\t2b, 4b \n" \ | |
46 | " .previous \n" \ | |
b0984c43 | 47 | : "=r" (ret), "=&r" (oldval), \ |
94bfb75a MC |
48 | "=" GCC_OFF_SMALL_ASM() (*uaddr) \ |
49 | : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ | |
b0984c43 | 50 | "i" (-EFAULT) \ |
0307e8d0 | 51 | : "memory"); \ |
6ee1da94 RB |
52 | } else if (cpu_has_llsc) { \ |
53 | __asm__ __volatile__( \ | |
54 | " .set push \n" \ | |
55 | " .set noat \n" \ | |
378ed6f0 | 56 | " .set push \n" \ |
1922c356 | 57 | " .set "MIPS_ISA_ARCH_LEVEL" \n" \ |
a6813fe5 | 58 | "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \ |
378ed6f0 | 59 | " .set pop \n" \ |
6ee1da94 | 60 | " " insn " \n" \ |
1922c356 | 61 | " .set "MIPS_ISA_ARCH_LEVEL" \n" \ |
a6813fe5 | 62 | "2: "user_sc("$1", "%2")" \n" \ |
6ee1da94 | 63 | " beqz $1, 1b \n" \ |
17099b11 | 64 | __WEAK_LLSC_MB \ |
6ee1da94 | 65 | "3: \n" \ |
0e525e48 | 66 | " .insn \n" \ |
6ee1da94 | 67 | " .set pop \n" \ |
6ee1da94 | 68 | " .section .fixup,\"ax\" \n" \ |
0307e8d0 | 69 | "4: li %0, %6 \n" \ |
0f67e90e | 70 | " j 3b \n" \ |
6ee1da94 RB |
71 | " .previous \n" \ |
72 | " .section __ex_table,\"a\" \n" \ | |
73 | " "__UA_ADDR "\t1b, 4b \n" \ | |
74 | " "__UA_ADDR "\t2b, 4b \n" \ | |
75 | " .previous \n" \ | |
b0984c43 | 76 | : "=r" (ret), "=&r" (oldval), \ |
94bfb75a MC |
77 | "=" GCC_OFF_SMALL_ASM() (*uaddr) \ |
78 | : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ | |
b0984c43 | 79 | "i" (-EFAULT) \ |
0307e8d0 | 80 | : "memory"); \ |
6ee1da94 RB |
81 | } else \ |
82 | ret = -ENOSYS; \ | |
ebfaebae RB |
83 | } |
84 | ||
4732efbe | 85 | static inline int |
30d6e0a4 | 86 | arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) |
4732efbe | 87 | { |
4732efbe | 88 | int oldval = 0, ret; |
4732efbe | 89 | |
a866374a | 90 | pagefault_disable(); |
4732efbe JJ |
91 | |
92 | switch (op) { | |
93 | case FUTEX_OP_SET: | |
70342287 | 94 | __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); |
ebfaebae RB |
95 | break; |
96 | ||
4732efbe | 97 | case FUTEX_OP_ADD: |
70342287 RB |
98 | __futex_atomic_op("addu $1, %1, %z5", |
99 | ret, oldval, uaddr, oparg); | |
ebfaebae | 100 | break; |
4732efbe | 101 | case FUTEX_OP_OR: |
0307e8d0 | 102 | __futex_atomic_op("or $1, %1, %z5", |
70342287 | 103 | ret, oldval, uaddr, oparg); |
ebfaebae | 104 | break; |
4732efbe | 105 | case FUTEX_OP_ANDN: |
0307e8d0 | 106 | __futex_atomic_op("and $1, %1, %z5", |
70342287 | 107 | ret, oldval, uaddr, ~oparg); |
ebfaebae | 108 | break; |
4732efbe | 109 | case FUTEX_OP_XOR: |
0307e8d0 | 110 | __futex_atomic_op("xor $1, %1, %z5", |
70342287 | 111 | ret, oldval, uaddr, oparg); |
ebfaebae | 112 | break; |
4732efbe JJ |
113 | default: |
114 | ret = -ENOSYS; | |
115 | } | |
116 | ||
a866374a | 117 | pagefault_enable(); |
4732efbe | 118 | |
30d6e0a4 JS |
119 | if (!ret) |
120 | *oval = oldval; | |
121 | ||
4732efbe JJ |
122 | return ret; |
123 | } | |
124 | ||
e9056f13 | 125 | static inline int |
8d7718aa ML |
126 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
127 | u32 oldval, u32 newval) | |
e9056f13 | 128 | { |
8d7718aa ML |
129 | int ret = 0; |
130 | u32 val; | |
6ee1da94 | 131 | |
96d4f267 | 132 | if (!access_ok(uaddr, sizeof(u32))) |
6ee1da94 RB |
133 | return -EFAULT; |
134 | ||
135 | if (cpu_has_llsc && R10000_LLSC_WAR) { | |
136 | __asm__ __volatile__( | |
137 | "# futex_atomic_cmpxchg_inatomic \n" | |
138 | " .set push \n" | |
139 | " .set noat \n" | |
378ed6f0 | 140 | " .set push \n" |
a809d460 | 141 | " .set arch=r4000 \n" |
37a9d912 ML |
142 | "1: ll %1, %3 \n" |
143 | " bne %1, %z4, 3f \n" | |
378ed6f0 | 144 | " .set pop \n" |
37a9d912 | 145 | " move $1, %z5 \n" |
a809d460 | 146 | " .set arch=r4000 \n" |
37a9d912 | 147 | "2: sc $1, %2 \n" |
6ee1da94 | 148 | " beqzl $1, 1b \n" |
17099b11 | 149 | __WEAK_LLSC_MB |
6ee1da94 | 150 | "3: \n" |
0e525e48 | 151 | " .insn \n" |
6ee1da94 RB |
152 | " .set pop \n" |
153 | " .section .fixup,\"ax\" \n" | |
37a9d912 | 154 | "4: li %0, %6 \n" |
6ee1da94 RB |
155 | " j 3b \n" |
156 | " .previous \n" | |
157 | " .section __ex_table,\"a\" \n" | |
158 | " "__UA_ADDR "\t1b, 4b \n" | |
159 | " "__UA_ADDR "\t2b, 4b \n" | |
160 | " .previous \n" | |
94bfb75a MC |
161 | : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) |
162 | : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), | |
b0984c43 | 163 | "i" (-EFAULT) |
6ee1da94 RB |
164 | : "memory"); |
165 | } else if (cpu_has_llsc) { | |
166 | __asm__ __volatile__( | |
167 | "# futex_atomic_cmpxchg_inatomic \n" | |
168 | " .set push \n" | |
169 | " .set noat \n" | |
378ed6f0 | 170 | " .set push \n" |
1922c356 | 171 | " .set "MIPS_ISA_ARCH_LEVEL" \n" |
a6813fe5 | 172 | "1: "user_ll("%1", "%3")" \n" |
37a9d912 | 173 | " bne %1, %z4, 3f \n" |
378ed6f0 | 174 | " .set pop \n" |
37a9d912 | 175 | " move $1, %z5 \n" |
1922c356 | 176 | " .set "MIPS_ISA_ARCH_LEVEL" \n" |
a6813fe5 | 177 | "2: "user_sc("$1", "%2")" \n" |
6ee1da94 | 178 | " beqz $1, 1b \n" |
17099b11 | 179 | __WEAK_LLSC_MB |
6ee1da94 | 180 | "3: \n" |
0e525e48 | 181 | " .insn \n" |
6ee1da94 RB |
182 | " .set pop \n" |
183 | " .section .fixup,\"ax\" \n" | |
37a9d912 | 184 | "4: li %0, %6 \n" |
6ee1da94 RB |
185 | " j 3b \n" |
186 | " .previous \n" | |
187 | " .section __ex_table,\"a\" \n" | |
188 | " "__UA_ADDR "\t1b, 4b \n" | |
189 | " "__UA_ADDR "\t2b, 4b \n" | |
190 | " .previous \n" | |
94bfb75a MC |
191 | : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) |
192 | : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), | |
b0984c43 | 193 | "i" (-EFAULT) |
6ee1da94 RB |
194 | : "memory"); |
195 | } else | |
196 | return -ENOSYS; | |
197 | ||
37a9d912 ML |
198 | *uval = val; |
199 | return ret; | |
e9056f13 IM |
200 | } |
201 | ||
4732efbe | 202 | #endif |
0f67e90e | 203 | #endif /* _ASM_FUTEX_H */ |