diff options
Diffstat (limited to 'include/asm-mips/futex.h')
| -rw-r--r-- | include/asm-mips/futex.h | 141 |
1 files changed, 116 insertions, 25 deletions
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index a554089991f2..12d118f1bc9c 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <linux/futex.h> | 7 | #include <linux/futex.h> |
| 8 | #include <asm/errno.h> | 8 | #include <asm/errno.h> |
| 9 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
| 10 | #include <asm/war.h> | ||
| 10 | 11 | ||
| 11 | #ifdef CONFIG_SMP | 12 | #ifdef CONFIG_SMP |
| 12 | #define __FUTEX_SMP_SYNC " sync \n" | 13 | #define __FUTEX_SMP_SYNC " sync \n" |
| @@ -16,30 +17,58 @@ | |||
| 16 | 17 | ||
| 17 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ | 18 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ |
| 18 | { \ | 19 | { \ |
| 19 | __asm__ __volatile__( \ | 20 | if (cpu_has_llsc && R10000_LLSC_WAR) { \ |
| 20 | " .set push \n" \ | 21 | __asm__ __volatile__( \ |
| 21 | " .set noat \n" \ | 22 | " .set push \n" \ |
| 22 | " .set mips3 \n" \ | 23 | " .set noat \n" \ |
| 23 | "1: ll %1, (%3) # __futex_atomic_op1 \n" \ | 24 | " .set mips3 \n" \ |
| 24 | " .set mips0 \n" \ | 25 | "1: ll %1, (%3) # __futex_atomic_op \n" \ |
| 25 | " " insn " \n" \ | 26 | " .set mips0 \n" \ |
| 26 | " .set mips3 \n" \ | 27 | " " insn " \n" \ |
| 27 | "2: sc $1, (%3) \n" \ | 28 | " .set mips3 \n" \ |
| 28 | " beqzl $1, 1b \n" \ | 29 | "2: sc $1, (%3) \n" \ |
| 29 | __FUTEX_SMP_SYNC \ | 30 | " beqzl $1, 1b \n" \ |
| 30 | "3: \n" \ | 31 | __FUTEX_SMP_SYNC \ |
| 31 | " .set pop \n" \ | 32 | "3: \n" \ |
| 32 | " .set mips0 \n" \ | 33 | " .set pop \n" \ |
| 33 | " .section .fixup,\"ax\" \n" \ | 34 | " .set mips0 \n" \ |
| 34 | "4: li %0, %5 \n" \ | 35 | " .section .fixup,\"ax\" \n" \ |
| 35 | " j 2b \n" \ | 36 | "4: li %0, %5 \n" \ |
| 36 | " .previous \n" \ | 37 | " j 2b \n" \ |
| 37 | " .section __ex_table,\"a\" \n" \ | 38 | " .previous \n" \ |
| 38 | " "__UA_ADDR "\t1b, 4b \n" \ | 39 | " .section __ex_table,\"a\" \n" \ |
| 39 | " "__UA_ADDR "\t2b, 4b \n" \ | 40 | " "__UA_ADDR "\t1b, 4b \n" \ |
| 40 | " .previous \n" \ | 41 | " "__UA_ADDR "\t2b, 4b \n" \ |
| 41 | : "=r" (ret), "=r" (oldval) \ | 42 | " .previous \n" \ |
| 42 | : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \ | 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; \ | ||
| 43 | } | 72 | } |
| 44 | 73 | ||
| 45 | static inline int | 74 | static inline int |
| @@ -102,7 +131,69 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
| 102 | static inline int | 131 | static inline int |
| 103 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | 132 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) |
| 104 | { | 133 | { |
| 105 | return -ENOSYS; | 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; | ||
| 106 | } | 197 | } |
| 107 | 198 | ||
| 108 | #endif | 199 | #endif |
