]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - arch/mips/include/asm/futex.h
MIPS: Fix microMIPS LL/SC immediate offsets
[mirror_ubuntu-focal-kernel.git] / arch / mips / include / asm / futex.h
CommitLineData
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" \
a809d460 27 " .set arch=r4000 \n" \
0307e8d0 28 "1: ll %1, %4 # __futex_atomic_op \n" \
6ee1da94
RB
29 " .set mips0 \n" \
30 " " insn " \n" \
a809d460 31 " .set arch=r4000 \n" \
0307e8d0 32 "2: sc $1, %2 \n" \
6ee1da94 33 " beqzl $1, 1b \n" \
17099b11 34 __WEAK_LLSC_MB \
6ee1da94
RB
35 "3: \n" \
36 " .set pop \n" \
37 " .set mips0 \n" \
38 " .section .fixup,\"ax\" \n" \
0307e8d0 39 "4: li %0, %6 \n" \
0f67e90e 40 " j 3b \n" \
6ee1da94
RB
41 " .previous \n" \
42 " .section __ex_table,\"a\" \n" \
43 " "__UA_ADDR "\t1b, 4b \n" \
44 " "__UA_ADDR "\t2b, 4b \n" \
45 " .previous \n" \
b0984c43
MR
46 : "=r" (ret), "=&r" (oldval), \
47 "=" GCC_OFF12_ASM() (*uaddr) \
48 : "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \
49 "i" (-EFAULT) \
0307e8d0 50 : "memory"); \
6ee1da94
RB
51 } else if (cpu_has_llsc) { \
52 __asm__ __volatile__( \
53 " .set push \n" \
54 " .set noat \n" \
a809d460 55 " .set arch=r4000 \n" \
a6813fe5 56 "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
6ee1da94
RB
57 " .set mips0 \n" \
58 " " insn " \n" \
a809d460 59 " .set arch=r4000 \n" \
a6813fe5 60 "2: "user_sc("$1", "%2")" \n" \
6ee1da94 61 " beqz $1, 1b \n" \
17099b11 62 __WEAK_LLSC_MB \
6ee1da94
RB
63 "3: \n" \
64 " .set pop \n" \
65 " .set mips0 \n" \
66 " .section .fixup,\"ax\" \n" \
0307e8d0 67 "4: li %0, %6 \n" \
0f67e90e 68 " j 3b \n" \
6ee1da94
RB
69 " .previous \n" \
70 " .section __ex_table,\"a\" \n" \
71 " "__UA_ADDR "\t1b, 4b \n" \
72 " "__UA_ADDR "\t2b, 4b \n" \
73 " .previous \n" \
b0984c43
MR
74 : "=r" (ret), "=&r" (oldval), \
75 "=" GCC_OFF12_ASM() (*uaddr) \
76 : "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \
77 "i" (-EFAULT) \
0307e8d0 78 : "memory"); \
6ee1da94
RB
79 } else \
80 ret = -ENOSYS; \
ebfaebae
RB
81}
82
4732efbe 83static inline int
8d7718aa 84futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
4732efbe
JJ
85{
86 int op = (encoded_op >> 28) & 7;
87 int cmp = (encoded_op >> 24) & 15;
88 int oparg = (encoded_op << 8) >> 20;
89 int cmparg = (encoded_op << 20) >> 20;
90 int oldval = 0, ret;
91 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
92 oparg = 1 << oparg;
93
8d7718aa 94 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
4732efbe
JJ
95 return -EFAULT;
96
a866374a 97 pagefault_disable();
4732efbe
JJ
98
99 switch (op) {
100 case FUTEX_OP_SET:
70342287 101 __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg);
ebfaebae
RB
102 break;
103
4732efbe 104 case FUTEX_OP_ADD:
70342287
RB
105 __futex_atomic_op("addu $1, %1, %z5",
106 ret, oldval, uaddr, oparg);
ebfaebae 107 break;
4732efbe 108 case FUTEX_OP_OR:
0307e8d0 109 __futex_atomic_op("or $1, %1, %z5",
70342287 110 ret, oldval, uaddr, oparg);
ebfaebae 111 break;
4732efbe 112 case FUTEX_OP_ANDN:
0307e8d0 113 __futex_atomic_op("and $1, %1, %z5",
70342287 114 ret, oldval, uaddr, ~oparg);
ebfaebae 115 break;
4732efbe 116 case FUTEX_OP_XOR:
0307e8d0 117 __futex_atomic_op("xor $1, %1, %z5",
70342287 118 ret, oldval, uaddr, oparg);
ebfaebae 119 break;
4732efbe
JJ
120 default:
121 ret = -ENOSYS;
122 }
123
a866374a 124 pagefault_enable();
4732efbe
JJ
125
126 if (!ret) {
127 switch (cmp) {
128 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
129 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
130 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
131 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
132 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
133 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
134 default: ret = -ENOSYS;
135 }
136 }
137 return ret;
138}
139
e9056f13 140static inline int
8d7718aa
ML
141futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
142 u32 oldval, u32 newval)
e9056f13 143{
8d7718aa
ML
144 int ret = 0;
145 u32 val;
6ee1da94 146
8d7718aa 147 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
6ee1da94
RB
148 return -EFAULT;
149
150 if (cpu_has_llsc && R10000_LLSC_WAR) {
151 __asm__ __volatile__(
152 "# futex_atomic_cmpxchg_inatomic \n"
153 " .set push \n"
154 " .set noat \n"
a809d460 155 " .set arch=r4000 \n"
37a9d912
ML
156 "1: ll %1, %3 \n"
157 " bne %1, %z4, 3f \n"
6ee1da94 158 " .set mips0 \n"
37a9d912 159 " move $1, %z5 \n"
a809d460 160 " .set arch=r4000 \n"
37a9d912 161 "2: sc $1, %2 \n"
6ee1da94 162 " beqzl $1, 1b \n"
17099b11 163 __WEAK_LLSC_MB
6ee1da94
RB
164 "3: \n"
165 " .set pop \n"
166 " .section .fixup,\"ax\" \n"
37a9d912 167 "4: li %0, %6 \n"
6ee1da94
RB
168 " j 3b \n"
169 " .previous \n"
170 " .section __ex_table,\"a\" \n"
171 " "__UA_ADDR "\t1b, 4b \n"
172 " "__UA_ADDR "\t2b, 4b \n"
173 " .previous \n"
b0984c43
MR
174 : "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr)
175 : GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
176 "i" (-EFAULT)
6ee1da94
RB
177 : "memory");
178 } else if (cpu_has_llsc) {
179 __asm__ __volatile__(
180 "# futex_atomic_cmpxchg_inatomic \n"
181 " .set push \n"
182 " .set noat \n"
a809d460 183 " .set arch=r4000 \n"
a6813fe5 184 "1: "user_ll("%1", "%3")" \n"
37a9d912 185 " bne %1, %z4, 3f \n"
6ee1da94 186 " .set mips0 \n"
37a9d912 187 " move $1, %z5 \n"
a809d460 188 " .set arch=r4000 \n"
a6813fe5 189 "2: "user_sc("$1", "%2")" \n"
6ee1da94 190 " beqz $1, 1b \n"
17099b11 191 __WEAK_LLSC_MB
6ee1da94
RB
192 "3: \n"
193 " .set pop \n"
194 " .section .fixup,\"ax\" \n"
37a9d912 195 "4: li %0, %6 \n"
6ee1da94
RB
196 " j 3b \n"
197 " .previous \n"
198 " .section __ex_table,\"a\" \n"
199 " "__UA_ADDR "\t1b, 4b \n"
200 " "__UA_ADDR "\t2b, 4b \n"
201 " .previous \n"
b0984c43
MR
202 : "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr)
203 : GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
204 "i" (-EFAULT)
6ee1da94
RB
205 : "memory");
206 } else
207 return -ENOSYS;
208
37a9d912
ML
209 *uval = val;
210 return ret;
e9056f13
IM
211}
212
4732efbe 213#endif
0f67e90e 214#endif /* _ASM_FUTEX_H */