diff options
Diffstat (limited to 'include/asm-x86/cmpxchg_32.h')
-rw-r--r-- | include/asm-x86/cmpxchg_32.h | 344 |
1 files changed, 0 insertions, 344 deletions
diff --git a/include/asm-x86/cmpxchg_32.h b/include/asm-x86/cmpxchg_32.h deleted file mode 100644 index 0622e45cdf7c..000000000000 --- a/include/asm-x86/cmpxchg_32.h +++ /dev/null | |||
@@ -1,344 +0,0 @@ | |||
1 | #ifndef ASM_X86__CMPXCHG_32_H | ||
2 | #define ASM_X86__CMPXCHG_32_H | ||
3 | |||
4 | #include <linux/bitops.h> /* for LOCK_PREFIX */ | ||
5 | |||
6 | /* | ||
7 | * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you | ||
8 | * you need to test for the feature in boot_cpu_data. | ||
9 | */ | ||
10 | |||
11 | #define xchg(ptr, v) \ | ||
12 | ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr)))) | ||
13 | |||
14 | struct __xchg_dummy { | ||
15 | unsigned long a[100]; | ||
16 | }; | ||
17 | #define __xg(x) ((struct __xchg_dummy *)(x)) | ||
18 | |||
19 | /* | ||
20 | * The semantics of XCHGCMP8B are a bit strange, this is why | ||
21 | * there is a loop and the loading of %%eax and %%edx has to | ||
22 | * be inside. This inlines well in most cases, the cached | ||
23 | * cost is around ~38 cycles. (in the future we might want | ||
24 | * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that | ||
25 | * might have an implicit FPU-save as a cost, so it's not | ||
26 | * clear which path to go.) | ||
27 | * | ||
28 | * cmpxchg8b must be used with the lock prefix here to allow | ||
29 | * the instruction to be executed atomically, see page 3-102 | ||
30 | * of the instruction set reference 24319102.pdf. We need | ||
31 | * the reader side to see the coherent 64bit value. | ||
32 | */ | ||
33 | static inline void __set_64bit(unsigned long long *ptr, | ||
34 | unsigned int low, unsigned int high) | ||
35 | { | ||
36 | asm volatile("\n1:\t" | ||
37 | "movl (%0), %%eax\n\t" | ||
38 | "movl 4(%0), %%edx\n\t" | ||
39 | LOCK_PREFIX "cmpxchg8b (%0)\n\t" | ||
40 | "jnz 1b" | ||
41 | : /* no outputs */ | ||
42 | : "D"(ptr), | ||
43 | "b"(low), | ||
44 | "c"(high) | ||
45 | : "ax", "dx", "memory"); | ||
46 | } | ||
47 | |||
48 | static inline void __set_64bit_constant(unsigned long long *ptr, | ||
49 | unsigned long long value) | ||
50 | { | ||
51 | __set_64bit(ptr, (unsigned int)value, (unsigned int)(value >> 32)); | ||
52 | } | ||
53 | |||
54 | #define ll_low(x) *(((unsigned int *)&(x)) + 0) | ||
55 | #define ll_high(x) *(((unsigned int *)&(x)) + 1) | ||
56 | |||
57 | static inline void __set_64bit_var(unsigned long long *ptr, | ||
58 | unsigned long long value) | ||
59 | { | ||
60 | __set_64bit(ptr, ll_low(value), ll_high(value)); | ||
61 | } | ||
62 | |||
63 | #define set_64bit(ptr, value) \ | ||
64 | (__builtin_constant_p((value)) \ | ||
65 | ? __set_64bit_constant((ptr), (value)) \ | ||
66 | : __set_64bit_var((ptr), (value))) | ||
67 | |||
68 | #define _set_64bit(ptr, value) \ | ||
69 | (__builtin_constant_p(value) \ | ||
70 | ? __set_64bit(ptr, (unsigned int)(value), \ | ||
71 | (unsigned int)((value) >> 32)) \ | ||
72 | : __set_64bit(ptr, ll_low((value)), ll_high((value)))) | ||
73 | |||
74 | /* | ||
75 | * Note: no "lock" prefix even on SMP: xchg always implies lock anyway | ||
76 | * Note 2: xchg has side effect, so that attribute volatile is necessary, | ||
77 | * but generally the primitive is invalid, *ptr is output argument. --ANK | ||
78 | */ | ||
79 | static inline unsigned long __xchg(unsigned long x, volatile void *ptr, | ||
80 | int size) | ||
81 | { | ||
82 | switch (size) { | ||
83 | case 1: | ||
84 | asm volatile("xchgb %b0,%1" | ||
85 | : "=q" (x) | ||
86 | : "m" (*__xg(ptr)), "0" (x) | ||
87 | : "memory"); | ||
88 | break; | ||
89 | case 2: | ||
90 | asm volatile("xchgw %w0,%1" | ||
91 | : "=r" (x) | ||
92 | : "m" (*__xg(ptr)), "0" (x) | ||
93 | : "memory"); | ||
94 | break; | ||
95 | case 4: | ||
96 | asm volatile("xchgl %0,%1" | ||
97 | : "=r" (x) | ||
98 | : "m" (*__xg(ptr)), "0" (x) | ||
99 | : "memory"); | ||
100 | break; | ||
101 | } | ||
102 | return x; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | ||
107 | * store NEW in MEM. Return the initial value in MEM. Success is | ||
108 | * indicated by comparing RETURN with OLD. | ||
109 | */ | ||
110 | |||
111 | #ifdef CONFIG_X86_CMPXCHG | ||
112 | #define __HAVE_ARCH_CMPXCHG 1 | ||
113 | #define cmpxchg(ptr, o, n) \ | ||
114 | ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ | ||
115 | (unsigned long)(n), \ | ||
116 | sizeof(*(ptr)))) | ||
117 | #define sync_cmpxchg(ptr, o, n) \ | ||
118 | ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o), \ | ||
119 | (unsigned long)(n), \ | ||
120 | sizeof(*(ptr)))) | ||
121 | #define cmpxchg_local(ptr, o, n) \ | ||
122 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ | ||
123 | (unsigned long)(n), \ | ||
124 | sizeof(*(ptr)))) | ||
125 | #endif | ||
126 | |||
127 | #ifdef CONFIG_X86_CMPXCHG64 | ||
128 | #define cmpxchg64(ptr, o, n) \ | ||
129 | ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ | ||
130 | (unsigned long long)(n))) | ||
131 | #define cmpxchg64_local(ptr, o, n) \ | ||
132 | ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ | ||
133 | (unsigned long long)(n))) | ||
134 | #endif | ||
135 | |||
136 | static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, | ||
137 | unsigned long new, int size) | ||
138 | { | ||
139 | unsigned long prev; | ||
140 | switch (size) { | ||
141 | case 1: | ||
142 | asm volatile(LOCK_PREFIX "cmpxchgb %b1,%2" | ||
143 | : "=a"(prev) | ||
144 | : "q"(new), "m"(*__xg(ptr)), "0"(old) | ||
145 | : "memory"); | ||
146 | return prev; | ||
147 | case 2: | ||
148 | asm volatile(LOCK_PREFIX "cmpxchgw %w1,%2" | ||
149 | : "=a"(prev) | ||
150 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
151 | : "memory"); | ||
152 | return prev; | ||
153 | case 4: | ||
154 | asm volatile(LOCK_PREFIX "cmpxchgl %1,%2" | ||
155 | : "=a"(prev) | ||
156 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
157 | : "memory"); | ||
158 | return prev; | ||
159 | } | ||
160 | return old; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Always use locked operations when touching memory shared with a | ||
165 | * hypervisor, since the system may be SMP even if the guest kernel | ||
166 | * isn't. | ||
167 | */ | ||
168 | static inline unsigned long __sync_cmpxchg(volatile void *ptr, | ||
169 | unsigned long old, | ||
170 | unsigned long new, int size) | ||
171 | { | ||
172 | unsigned long prev; | ||
173 | switch (size) { | ||
174 | case 1: | ||
175 | asm volatile("lock; cmpxchgb %b1,%2" | ||
176 | : "=a"(prev) | ||
177 | : "q"(new), "m"(*__xg(ptr)), "0"(old) | ||
178 | : "memory"); | ||
179 | return prev; | ||
180 | case 2: | ||
181 | asm volatile("lock; cmpxchgw %w1,%2" | ||
182 | : "=a"(prev) | ||
183 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
184 | : "memory"); | ||
185 | return prev; | ||
186 | case 4: | ||
187 | asm volatile("lock; cmpxchgl %1,%2" | ||
188 | : "=a"(prev) | ||
189 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
190 | : "memory"); | ||
191 | return prev; | ||
192 | } | ||
193 | return old; | ||
194 | } | ||
195 | |||
196 | static inline unsigned long __cmpxchg_local(volatile void *ptr, | ||
197 | unsigned long old, | ||
198 | unsigned long new, int size) | ||
199 | { | ||
200 | unsigned long prev; | ||
201 | switch (size) { | ||
202 | case 1: | ||
203 | asm volatile("cmpxchgb %b1,%2" | ||
204 | : "=a"(prev) | ||
205 | : "q"(new), "m"(*__xg(ptr)), "0"(old) | ||
206 | : "memory"); | ||
207 | return prev; | ||
208 | case 2: | ||
209 | asm volatile("cmpxchgw %w1,%2" | ||
210 | : "=a"(prev) | ||
211 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
212 | : "memory"); | ||
213 | return prev; | ||
214 | case 4: | ||
215 | asm volatile("cmpxchgl %1,%2" | ||
216 | : "=a"(prev) | ||
217 | : "r"(new), "m"(*__xg(ptr)), "0"(old) | ||
218 | : "memory"); | ||
219 | return prev; | ||
220 | } | ||
221 | return old; | ||
222 | } | ||
223 | |||
224 | static inline unsigned long long __cmpxchg64(volatile void *ptr, | ||
225 | unsigned long long old, | ||
226 | unsigned long long new) | ||
227 | { | ||
228 | unsigned long long prev; | ||
229 | asm volatile(LOCK_PREFIX "cmpxchg8b %3" | ||
230 | : "=A"(prev) | ||
231 | : "b"((unsigned long)new), | ||
232 | "c"((unsigned long)(new >> 32)), | ||
233 | "m"(*__xg(ptr)), | ||
234 | "0"(old) | ||
235 | : "memory"); | ||
236 | return prev; | ||
237 | } | ||
238 | |||
239 | static inline unsigned long long __cmpxchg64_local(volatile void *ptr, | ||
240 | unsigned long long old, | ||
241 | unsigned long long new) | ||
242 | { | ||
243 | unsigned long long prev; | ||
244 | asm volatile("cmpxchg8b %3" | ||
245 | : "=A"(prev) | ||
246 | : "b"((unsigned long)new), | ||
247 | "c"((unsigned long)(new >> 32)), | ||
248 | "m"(*__xg(ptr)), | ||
249 | "0"(old) | ||
250 | : "memory"); | ||
251 | return prev; | ||
252 | } | ||
253 | |||
254 | #ifndef CONFIG_X86_CMPXCHG | ||
255 | /* | ||
256 | * Building a kernel capable running on 80386. It may be necessary to | ||
257 | * simulate the cmpxchg on the 80386 CPU. For that purpose we define | ||
258 | * a function for each of the sizes we support. | ||
259 | */ | ||
260 | |||
261 | extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8); | ||
262 | extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16); | ||
263 | extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32); | ||
264 | |||
265 | static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, | ||
266 | unsigned long new, int size) | ||
267 | { | ||
268 | switch (size) { | ||
269 | case 1: | ||
270 | return cmpxchg_386_u8(ptr, old, new); | ||
271 | case 2: | ||
272 | return cmpxchg_386_u16(ptr, old, new); | ||
273 | case 4: | ||
274 | return cmpxchg_386_u32(ptr, old, new); | ||
275 | } | ||
276 | return old; | ||
277 | } | ||
278 | |||
279 | #define cmpxchg(ptr, o, n) \ | ||
280 | ({ \ | ||
281 | __typeof__(*(ptr)) __ret; \ | ||
282 | if (likely(boot_cpu_data.x86 > 3)) \ | ||
283 | __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \ | ||
284 | (unsigned long)(o), (unsigned long)(n), \ | ||
285 | sizeof(*(ptr))); \ | ||
286 | else \ | ||
287 | __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \ | ||
288 | (unsigned long)(o), (unsigned long)(n), \ | ||
289 | sizeof(*(ptr))); \ | ||
290 | __ret; \ | ||
291 | }) | ||
292 | #define cmpxchg_local(ptr, o, n) \ | ||
293 | ({ \ | ||
294 | __typeof__(*(ptr)) __ret; \ | ||
295 | if (likely(boot_cpu_data.x86 > 3)) \ | ||
296 | __ret = (__typeof__(*(ptr)))__cmpxchg_local((ptr), \ | ||
297 | (unsigned long)(o), (unsigned long)(n), \ | ||
298 | sizeof(*(ptr))); \ | ||
299 | else \ | ||
300 | __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \ | ||
301 | (unsigned long)(o), (unsigned long)(n), \ | ||
302 | sizeof(*(ptr))); \ | ||
303 | __ret; \ | ||
304 | }) | ||
305 | #endif | ||
306 | |||
307 | #ifndef CONFIG_X86_CMPXCHG64 | ||
308 | /* | ||
309 | * Building a kernel capable running on 80386 and 80486. It may be necessary | ||
310 | * to simulate the cmpxchg8b on the 80386 and 80486 CPU. | ||
311 | */ | ||
312 | |||
313 | extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64); | ||
314 | |||
315 | #define cmpxchg64(ptr, o, n) \ | ||
316 | ({ \ | ||
317 | __typeof__(*(ptr)) __ret; \ | ||
318 | if (likely(boot_cpu_data.x86 > 4)) \ | ||
319 | __ret = (__typeof__(*(ptr)))__cmpxchg64((ptr), \ | ||
320 | (unsigned long long)(o), \ | ||
321 | (unsigned long long)(n)); \ | ||
322 | else \ | ||
323 | __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \ | ||
324 | (unsigned long long)(o), \ | ||
325 | (unsigned long long)(n)); \ | ||
326 | __ret; \ | ||
327 | }) | ||
328 | #define cmpxchg64_local(ptr, o, n) \ | ||
329 | ({ \ | ||
330 | __typeof__(*(ptr)) __ret; \ | ||
331 | if (likely(boot_cpu_data.x86 > 4)) \ | ||
332 | __ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \ | ||
333 | (unsigned long long)(o), \ | ||
334 | (unsigned long long)(n)); \ | ||
335 | else \ | ||
336 | __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \ | ||
337 | (unsigned long long)(o), \ | ||
338 | (unsigned long long)(n)); \ | ||
339 | __ret; \ | ||
340 | }) | ||
341 | |||
342 | #endif | ||
343 | |||
344 | #endif /* ASM_X86__CMPXCHG_32_H */ | ||