MAINTAINERS: Add phy-miphy28lp.c and phy-miphy365x.c to ARCH/STI architecture
[deliverable/linux.git] / arch / arm64 / include / asm / cmpxchg.h
1 /*
2 * Based on arch/arm/include/asm/cmpxchg.h
3 *
4 * Copyright (C) 2012 ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #ifndef __ASM_CMPXCHG_H
19 #define __ASM_CMPXCHG_H
20
21 #include <linux/bug.h>
22 #include <linux/mmdebug.h>
23
24 #include <asm/barrier.h>
25
26 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
27 {
28 unsigned long ret, tmp;
29
30 switch (size) {
31 case 1:
32 asm volatile("// __xchg1\n"
33 "1: ldxrb %w0, %2\n"
34 " stlxrb %w1, %w3, %2\n"
35 " cbnz %w1, 1b\n"
36 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)
37 : "r" (x)
38 : "memory");
39 break;
40 case 2:
41 asm volatile("// __xchg2\n"
42 "1: ldxrh %w0, %2\n"
43 " stlxrh %w1, %w3, %2\n"
44 " cbnz %w1, 1b\n"
45 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr)
46 : "r" (x)
47 : "memory");
48 break;
49 case 4:
50 asm volatile("// __xchg4\n"
51 "1: ldxr %w0, %2\n"
52 " stlxr %w1, %w3, %2\n"
53 " cbnz %w1, 1b\n"
54 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr)
55 : "r" (x)
56 : "memory");
57 break;
58 case 8:
59 asm volatile("// __xchg8\n"
60 "1: ldxr %0, %2\n"
61 " stlxr %w1, %3, %2\n"
62 " cbnz %w1, 1b\n"
63 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr)
64 : "r" (x)
65 : "memory");
66 break;
67 default:
68 BUILD_BUG();
69 }
70
71 smp_mb();
72 return ret;
73 }
74
75 #define xchg(ptr,x) \
76 ({ \
77 __typeof__(*(ptr)) __ret; \
78 __ret = (__typeof__(*(ptr))) \
79 __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \
80 __ret; \
81 })
82
83 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
84 unsigned long new, int size)
85 {
86 unsigned long oldval = 0, res;
87
88 switch (size) {
89 case 1:
90 do {
91 asm volatile("// __cmpxchg1\n"
92 " ldxrb %w1, %2\n"
93 " mov %w0, #0\n"
94 " cmp %w1, %w3\n"
95 " b.ne 1f\n"
96 " stxrb %w0, %w4, %2\n"
97 "1:\n"
98 : "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
99 : "Ir" (old), "r" (new)
100 : "cc");
101 } while (res);
102 break;
103
104 case 2:
105 do {
106 asm volatile("// __cmpxchg2\n"
107 " ldxrh %w1, %2\n"
108 " mov %w0, #0\n"
109 " cmp %w1, %w3\n"
110 " b.ne 1f\n"
111 " stxrh %w0, %w4, %2\n"
112 "1:\n"
113 : "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
114 : "Ir" (old), "r" (new)
115 : "cc");
116 } while (res);
117 break;
118
119 case 4:
120 do {
121 asm volatile("// __cmpxchg4\n"
122 " ldxr %w1, %2\n"
123 " mov %w0, #0\n"
124 " cmp %w1, %w3\n"
125 " b.ne 1f\n"
126 " stxr %w0, %w4, %2\n"
127 "1:\n"
128 : "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
129 : "Ir" (old), "r" (new)
130 : "cc");
131 } while (res);
132 break;
133
134 case 8:
135 do {
136 asm volatile("// __cmpxchg8\n"
137 " ldxr %1, %2\n"
138 " mov %w0, #0\n"
139 " cmp %1, %3\n"
140 " b.ne 1f\n"
141 " stxr %w0, %4, %2\n"
142 "1:\n"
143 : "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
144 : "Ir" (old), "r" (new)
145 : "cc");
146 } while (res);
147 break;
148
149 default:
150 BUILD_BUG();
151 }
152
153 return oldval;
154 }
155
156 #define system_has_cmpxchg_double() 1
157
158 static inline int __cmpxchg_double(volatile void *ptr1, volatile void *ptr2,
159 unsigned long old1, unsigned long old2,
160 unsigned long new1, unsigned long new2, int size)
161 {
162 unsigned long loop, lost;
163
164 switch (size) {
165 case 8:
166 VM_BUG_ON((unsigned long *)ptr2 - (unsigned long *)ptr1 != 1);
167 do {
168 asm volatile("// __cmpxchg_double8\n"
169 " ldxp %0, %1, %2\n"
170 " eor %0, %0, %3\n"
171 " eor %1, %1, %4\n"
172 " orr %1, %0, %1\n"
173 " mov %w0, #0\n"
174 " cbnz %1, 1f\n"
175 " stxp %w0, %5, %6, %2\n"
176 "1:\n"
177 : "=&r"(loop), "=&r"(lost), "+Q" (*(u64 *)ptr1)
178 : "r" (old1), "r"(old2), "r"(new1), "r"(new2));
179 } while (loop);
180 break;
181 default:
182 BUILD_BUG();
183 }
184
185 return !lost;
186 }
187
188 static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2,
189 unsigned long old1, unsigned long old2,
190 unsigned long new1, unsigned long new2, int size)
191 {
192 int ret;
193
194 smp_mb();
195 ret = __cmpxchg_double(ptr1, ptr2, old1, old2, new1, new2, size);
196 smp_mb();
197
198 return ret;
199 }
200
201 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
202 unsigned long new, int size)
203 {
204 unsigned long ret;
205
206 smp_mb();
207 ret = __cmpxchg(ptr, old, new, size);
208 smp_mb();
209
210 return ret;
211 }
212
213 #define cmpxchg(ptr, o, n) \
214 ({ \
215 __typeof__(*(ptr)) __ret; \
216 __ret = (__typeof__(*(ptr))) \
217 __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \
218 sizeof(*(ptr))); \
219 __ret; \
220 })
221
222 #define cmpxchg_local(ptr, o, n) \
223 ({ \
224 __typeof__(*(ptr)) __ret; \
225 __ret = (__typeof__(*(ptr))) \
226 __cmpxchg((ptr), (unsigned long)(o), \
227 (unsigned long)(n), sizeof(*(ptr))); \
228 __ret; \
229 })
230
231 #define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
232 ({\
233 int __ret;\
234 __ret = __cmpxchg_double_mb((ptr1), (ptr2), (unsigned long)(o1), \
235 (unsigned long)(o2), (unsigned long)(n1), \
236 (unsigned long)(n2), sizeof(*(ptr1)));\
237 __ret; \
238 })
239
240 #define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
241 ({\
242 int __ret;\
243 __ret = __cmpxchg_double((ptr1), (ptr2), (unsigned long)(o1), \
244 (unsigned long)(o2), (unsigned long)(n1), \
245 (unsigned long)(n2), sizeof(*(ptr1)));\
246 __ret; \
247 })
248
249 #define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
250 #define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
251 #define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
252 #define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
253
254 #define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
255 cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
256 o1, o2, n1, n2)
257
258 #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
259 #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
260
261 #define cmpxchg64_relaxed(ptr,o,n) cmpxchg_local((ptr),(o),(n))
262
263 #endif /* __ASM_CMPXCHG_H */
This page took 0.037992 seconds and 5 git commands to generate.