diff options
-rw-r--r-- | arch/x86/include/asm/atomic_32.h | 137 | ||||
-rw-r--r-- | arch/x86/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/lib/atomic64_32.c | 216 |
3 files changed, 237 insertions, 117 deletions
diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h index ae0fbb5b0578..311a43e47c0b 100644 --- a/arch/x86/include/asm/atomic_32.h +++ b/arch/x86/include/asm/atomic_32.h | |||
@@ -250,7 +250,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) | |||
250 | /* An 64bit atomic type */ | 250 | /* An 64bit atomic type */ |
251 | 251 | ||
252 | typedef struct { | 252 | typedef struct { |
253 | unsigned long long __aligned(8) counter; | 253 | u64 __aligned(8) counter; |
254 | } atomic64_t; | 254 | } atomic64_t; |
255 | 255 | ||
256 | #define ATOMIC64_INIT(val) { (val) } | 256 | #define ATOMIC64_INIT(val) { (val) } |
@@ -264,31 +264,7 @@ typedef struct { | |||
264 | */ | 264 | */ |
265 | #define __atomic64_read(ptr) ((ptr)->counter) | 265 | #define __atomic64_read(ptr) ((ptr)->counter) |
266 | 266 | ||
267 | static inline unsigned long long | 267 | extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val); |
268 | cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new) | ||
269 | { | ||
270 | asm volatile( | ||
271 | |||
272 | LOCK_PREFIX "cmpxchg8b (%[ptr])\n" | ||
273 | |||
274 | : "=A" (old) | ||
275 | |||
276 | : [ptr] "D" (ptr), | ||
277 | "A" (old), | ||
278 | "b" (ll_low(new)), | ||
279 | "c" (ll_high(new)) | ||
280 | |||
281 | : "memory"); | ||
282 | |||
283 | return old; | ||
284 | } | ||
285 | |||
286 | static inline unsigned long long | ||
287 | atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val, | ||
288 | unsigned long long new_val) | ||
289 | { | ||
290 | return cmpxchg8b(&ptr->counter, old_val, new_val); | ||
291 | } | ||
292 | 268 | ||
293 | /** | 269 | /** |
294 | * atomic64_xchg - xchg atomic64 variable | 270 | * atomic64_xchg - xchg atomic64 variable |
@@ -298,18 +274,7 @@ atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val, | |||
298 | * Atomically xchgs the value of @ptr to @new_val and returns | 274 | * Atomically xchgs the value of @ptr to @new_val and returns |
299 | * the old value. | 275 | * the old value. |
300 | */ | 276 | */ |
301 | 277 | extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val); | |
302 | static inline unsigned long long | ||
303 | atomic64_xchg(atomic64_t *ptr, unsigned long long new_val) | ||
304 | { | ||
305 | unsigned long long old_val; | ||
306 | |||
307 | do { | ||
308 | old_val = atomic_read(ptr); | ||
309 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
310 | |||
311 | return old_val; | ||
312 | } | ||
313 | 278 | ||
314 | /** | 279 | /** |
315 | * atomic64_set - set atomic64 variable | 280 | * atomic64_set - set atomic64 variable |
@@ -318,10 +283,7 @@ atomic64_xchg(atomic64_t *ptr, unsigned long long new_val) | |||
318 | * | 283 | * |
319 | * Atomically sets the value of @ptr to @new_val. | 284 | * Atomically sets the value of @ptr to @new_val. |
320 | */ | 285 | */ |
321 | static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) | 286 | extern void atomic64_set(atomic64_t *ptr, u64 new_val); |
322 | { | ||
323 | atomic64_xchg(ptr, new_val); | ||
324 | } | ||
325 | 287 | ||
326 | /** | 288 | /** |
327 | * atomic64_read - read atomic64 variable | 289 | * atomic64_read - read atomic64 variable |
@@ -329,16 +291,7 @@ static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) | |||
329 | * | 291 | * |
330 | * Atomically reads the value of @ptr and returns it. | 292 | * Atomically reads the value of @ptr and returns it. |
331 | */ | 293 | */ |
332 | static inline unsigned long long atomic64_read(atomic64_t *ptr) | 294 | extern u64 atomic64_read(atomic64_t *ptr); |
333 | { | ||
334 | unsigned long long curr_val; | ||
335 | |||
336 | do { | ||
337 | curr_val = __atomic64_read(ptr); | ||
338 | } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val); | ||
339 | |||
340 | return curr_val; | ||
341 | } | ||
342 | 295 | ||
343 | /** | 296 | /** |
344 | * atomic64_add_return - add and return | 297 | * atomic64_add_return - add and return |
@@ -347,34 +300,14 @@ static inline unsigned long long atomic64_read(atomic64_t *ptr) | |||
347 | * | 300 | * |
348 | * Atomically adds @delta to @ptr and returns @delta + *@ptr | 301 | * Atomically adds @delta to @ptr and returns @delta + *@ptr |
349 | */ | 302 | */ |
350 | static inline unsigned long long | 303 | extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr); |
351 | atomic64_add_return(unsigned long long delta, atomic64_t *ptr) | ||
352 | { | ||
353 | unsigned long long old_val, new_val; | ||
354 | |||
355 | do { | ||
356 | old_val = atomic_read(ptr); | ||
357 | new_val = old_val + delta; | ||
358 | |||
359 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
360 | |||
361 | return new_val; | ||
362 | } | ||
363 | |||
364 | static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr) | ||
365 | { | ||
366 | return atomic64_add_return(-delta, ptr); | ||
367 | } | ||
368 | 304 | ||
369 | static inline long atomic64_inc_return(atomic64_t *ptr) | 305 | /* |
370 | { | 306 | * Other variants with different arithmetic operators: |
371 | return atomic64_add_return(1, ptr); | 307 | */ |
372 | } | 308 | extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr); |
373 | 309 | extern u64 atomic64_inc_return(atomic64_t *ptr); | |
374 | static inline long atomic64_dec_return(atomic64_t *ptr) | 310 | extern u64 atomic64_dec_return(atomic64_t *ptr); |
375 | { | ||
376 | return atomic64_sub_return(1, ptr); | ||
377 | } | ||
378 | 311 | ||
379 | /** | 312 | /** |
380 | * atomic64_add - add integer to atomic64 variable | 313 | * atomic64_add - add integer to atomic64 variable |
@@ -383,10 +316,7 @@ static inline long atomic64_dec_return(atomic64_t *ptr) | |||
383 | * | 316 | * |
384 | * Atomically adds @delta to @ptr. | 317 | * Atomically adds @delta to @ptr. |
385 | */ | 318 | */ |
386 | static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) | 319 | extern void atomic64_add(u64 delta, atomic64_t *ptr); |
387 | { | ||
388 | atomic64_add_return(delta, ptr); | ||
389 | } | ||
390 | 320 | ||
391 | /** | 321 | /** |
392 | * atomic64_sub - subtract the atomic64 variable | 322 | * atomic64_sub - subtract the atomic64 variable |
@@ -395,10 +325,7 @@ static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) | |||
395 | * | 325 | * |
396 | * Atomically subtracts @delta from @ptr. | 326 | * Atomically subtracts @delta from @ptr. |
397 | */ | 327 | */ |
398 | static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) | 328 | extern void atomic64_sub(u64 delta, atomic64_t *ptr); |
399 | { | ||
400 | atomic64_add(-delta, ptr); | ||
401 | } | ||
402 | 329 | ||
403 | /** | 330 | /** |
404 | * atomic64_sub_and_test - subtract value from variable and test result | 331 | * atomic64_sub_and_test - subtract value from variable and test result |
@@ -409,13 +336,7 @@ static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) | |||
409 | * true if the result is zero, or false for all | 336 | * true if the result is zero, or false for all |
410 | * other cases. | 337 | * other cases. |
411 | */ | 338 | */ |
412 | static inline int | 339 | extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr); |
413 | atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr) | ||
414 | { | ||
415 | unsigned long long old_val = atomic64_sub_return(delta, ptr); | ||
416 | |||
417 | return old_val == 0; | ||
418 | } | ||
419 | 340 | ||
420 | /** | 341 | /** |
421 | * atomic64_inc - increment atomic64 variable | 342 | * atomic64_inc - increment atomic64 variable |
@@ -423,10 +344,7 @@ atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr) | |||
423 | * | 344 | * |
424 | * Atomically increments @ptr by 1. | 345 | * Atomically increments @ptr by 1. |
425 | */ | 346 | */ |
426 | static inline void atomic64_inc(atomic64_t *ptr) | 347 | extern void atomic64_inc(atomic64_t *ptr); |
427 | { | ||
428 | atomic64_add(1, ptr); | ||
429 | } | ||
430 | 348 | ||
431 | /** | 349 | /** |
432 | * atomic64_dec - decrement atomic64 variable | 350 | * atomic64_dec - decrement atomic64 variable |
@@ -434,10 +352,7 @@ static inline void atomic64_inc(atomic64_t *ptr) | |||
434 | * | 352 | * |
435 | * Atomically decrements @ptr by 1. | 353 | * Atomically decrements @ptr by 1. |
436 | */ | 354 | */ |
437 | static inline void atomic64_dec(atomic64_t *ptr) | 355 | extern void atomic64_dec(atomic64_t *ptr); |
438 | { | ||
439 | atomic64_sub(1, ptr); | ||
440 | } | ||
441 | 356 | ||
442 | /** | 357 | /** |
443 | * atomic64_dec_and_test - decrement and test | 358 | * atomic64_dec_and_test - decrement and test |
@@ -447,10 +362,7 @@ static inline void atomic64_dec(atomic64_t *ptr) | |||
447 | * returns true if the result is 0, or false for all other | 362 | * returns true if the result is 0, or false for all other |
448 | * cases. | 363 | * cases. |
449 | */ | 364 | */ |
450 | static inline int atomic64_dec_and_test(atomic64_t *ptr) | 365 | extern int atomic64_dec_and_test(atomic64_t *ptr); |
451 | { | ||
452 | return atomic64_sub_and_test(1, ptr); | ||
453 | } | ||
454 | 366 | ||
455 | /** | 367 | /** |
456 | * atomic64_inc_and_test - increment and test | 368 | * atomic64_inc_and_test - increment and test |
@@ -460,10 +372,7 @@ static inline int atomic64_dec_and_test(atomic64_t *ptr) | |||
460 | * and returns true if the result is zero, or false for all | 372 | * and returns true if the result is zero, or false for all |
461 | * other cases. | 373 | * other cases. |
462 | */ | 374 | */ |
463 | static inline int atomic64_inc_and_test(atomic64_t *ptr) | 375 | extern int atomic64_inc_and_test(atomic64_t *ptr); |
464 | { | ||
465 | return atomic64_sub_and_test(-1, ptr); | ||
466 | } | ||
467 | 376 | ||
468 | /** | 377 | /** |
469 | * atomic64_add_negative - add and test if negative | 378 | * atomic64_add_negative - add and test if negative |
@@ -474,13 +383,7 @@ static inline int atomic64_inc_and_test(atomic64_t *ptr) | |||
474 | * if the result is negative, or false when | 383 | * if the result is negative, or false when |
475 | * result is greater than or equal to zero. | 384 | * result is greater than or equal to zero. |
476 | */ | 385 | */ |
477 | static inline int | 386 | extern int atomic64_add_negative(u64 delta, atomic64_t *ptr); |
478 | atomic64_add_negative(unsigned long long delta, atomic64_t *ptr) | ||
479 | { | ||
480 | long long old_val = atomic64_add_return(delta, ptr); | ||
481 | |||
482 | return old_val < 0; | ||
483 | } | ||
484 | 387 | ||
485 | #include <asm-generic/atomic-long.h> | 388 | #include <asm-generic/atomic-long.h> |
486 | #endif /* _ASM_X86_ATOMIC_32_H */ | 389 | #endif /* _ASM_X86_ATOMIC_32_H */ |
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index f9d35632666b..c3c657c8bb83 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
@@ -10,6 +10,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o | |||
10 | lib-y += memcpy_$(BITS).o | 10 | lib-y += memcpy_$(BITS).o |
11 | 11 | ||
12 | ifeq ($(CONFIG_X86_32),y) | 12 | ifeq ($(CONFIG_X86_32),y) |
13 | lib-y += atomic64_32.o | ||
13 | lib-y += checksum_32.o | 14 | lib-y += checksum_32.o |
14 | lib-y += strstr_32.o | 15 | lib-y += strstr_32.o |
15 | lib-y += semaphore_32.o string_32.o | 16 | lib-y += semaphore_32.o string_32.o |
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c new file mode 100644 index 000000000000..d21e725d3d84 --- /dev/null +++ b/arch/x86/lib/atomic64_32.c | |||
@@ -0,0 +1,216 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <linux/types.h> | ||
3 | #include <asm/processor.h> | ||
4 | #include <asm/cmpxchg.h> | ||
5 | #include <asm/atomic.h> | ||
6 | |||
7 | static inline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new) | ||
8 | { | ||
9 | asm volatile( | ||
10 | |||
11 | LOCK_PREFIX "cmpxchg8b (%[ptr])\n" | ||
12 | |||
13 | : "=A" (old) | ||
14 | |||
15 | : [ptr] "D" (ptr), | ||
16 | "A" (old), | ||
17 | "b" (ll_low(new)), | ||
18 | "c" (ll_high(new)) | ||
19 | |||
20 | : "memory"); | ||
21 | |||
22 | return old; | ||
23 | } | ||
24 | |||
25 | u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val) | ||
26 | { | ||
27 | return cmpxchg8b(&ptr->counter, old_val, new_val); | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * atomic64_xchg - xchg atomic64 variable | ||
32 | * @ptr: pointer to type atomic64_t | ||
33 | * @new_val: value to assign | ||
34 | * | ||
35 | * Atomically xchgs the value of @ptr to @new_val and returns | ||
36 | * the old value. | ||
37 | */ | ||
38 | |||
39 | u64 atomic64_xchg(atomic64_t *ptr, u64 new_val) | ||
40 | { | ||
41 | u64 old_val; | ||
42 | |||
43 | do { | ||
44 | old_val = atomic_read(ptr); | ||
45 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
46 | |||
47 | return old_val; | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * atomic64_set - set atomic64 variable | ||
52 | * @ptr: pointer to type atomic64_t | ||
53 | * @new_val: value to assign | ||
54 | * | ||
55 | * Atomically sets the value of @ptr to @new_val. | ||
56 | */ | ||
57 | void atomic64_set(atomic64_t *ptr, u64 new_val) | ||
58 | { | ||
59 | atomic64_xchg(ptr, new_val); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * atomic64_read - read atomic64 variable | ||
64 | * @ptr: pointer to type atomic64_t | ||
65 | * | ||
66 | * Atomically reads the value of @ptr and returns it. | ||
67 | */ | ||
68 | u64 atomic64_read(atomic64_t *ptr) | ||
69 | { | ||
70 | u64 curr_val; | ||
71 | |||
72 | do { | ||
73 | curr_val = __atomic64_read(ptr); | ||
74 | } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val); | ||
75 | |||
76 | return curr_val; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * atomic64_add_return - add and return | ||
81 | * @delta: integer value to add | ||
82 | * @ptr: pointer to type atomic64_t | ||
83 | * | ||
84 | * Atomically adds @delta to @ptr and returns @delta + *@ptr | ||
85 | */ | ||
86 | u64 atomic64_add_return(u64 delta, atomic64_t *ptr) | ||
87 | { | ||
88 | u64 old_val, new_val; | ||
89 | |||
90 | do { | ||
91 | old_val = atomic_read(ptr); | ||
92 | new_val = old_val + delta; | ||
93 | |||
94 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
95 | |||
96 | return new_val; | ||
97 | } | ||
98 | |||
99 | u64 atomic64_sub_return(u64 delta, atomic64_t *ptr) | ||
100 | { | ||
101 | return atomic64_add_return(-delta, ptr); | ||
102 | } | ||
103 | |||
104 | u64 atomic64_inc_return(atomic64_t *ptr) | ||
105 | { | ||
106 | return atomic64_add_return(1, ptr); | ||
107 | } | ||
108 | |||
109 | u64 atomic64_dec_return(atomic64_t *ptr) | ||
110 | { | ||
111 | return atomic64_sub_return(1, ptr); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * atomic64_add - add integer to atomic64 variable | ||
116 | * @delta: integer value to add | ||
117 | * @ptr: pointer to type atomic64_t | ||
118 | * | ||
119 | * Atomically adds @delta to @ptr. | ||
120 | */ | ||
121 | void atomic64_add(u64 delta, atomic64_t *ptr) | ||
122 | { | ||
123 | atomic64_add_return(delta, ptr); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * atomic64_sub - subtract the atomic64 variable | ||
128 | * @delta: integer value to subtract | ||
129 | * @ptr: pointer to type atomic64_t | ||
130 | * | ||
131 | * Atomically subtracts @delta from @ptr. | ||
132 | */ | ||
133 | void atomic64_sub(u64 delta, atomic64_t *ptr) | ||
134 | { | ||
135 | atomic64_add(-delta, ptr); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * atomic64_sub_and_test - subtract value from variable and test result | ||
140 | * @delta: integer value to subtract | ||
141 | * @ptr: pointer to type atomic64_t | ||
142 | * | ||
143 | * Atomically subtracts @delta from @ptr and returns | ||
144 | * true if the result is zero, or false for all | ||
145 | * other cases. | ||
146 | */ | ||
147 | int atomic64_sub_and_test(u64 delta, atomic64_t *ptr) | ||
148 | { | ||
149 | u64 old_val = atomic64_sub_return(delta, ptr); | ||
150 | |||
151 | return old_val == 0; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * atomic64_inc - increment atomic64 variable | ||
156 | * @ptr: pointer to type atomic64_t | ||
157 | * | ||
158 | * Atomically increments @ptr by 1. | ||
159 | */ | ||
160 | void atomic64_inc(atomic64_t *ptr) | ||
161 | { | ||
162 | atomic64_add(1, ptr); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * atomic64_dec - decrement atomic64 variable | ||
167 | * @ptr: pointer to type atomic64_t | ||
168 | * | ||
169 | * Atomically decrements @ptr by 1. | ||
170 | */ | ||
171 | void atomic64_dec(atomic64_t *ptr) | ||
172 | { | ||
173 | atomic64_sub(1, ptr); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * atomic64_dec_and_test - decrement and test | ||
178 | * @ptr: pointer to type atomic64_t | ||
179 | * | ||
180 | * Atomically decrements @ptr by 1 and | ||
181 | * returns true if the result is 0, or false for all other | ||
182 | * cases. | ||
183 | */ | ||
184 | int atomic64_dec_and_test(atomic64_t *ptr) | ||
185 | { | ||
186 | return atomic64_sub_and_test(1, ptr); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * atomic64_inc_and_test - increment and test | ||
191 | * @ptr: pointer to type atomic64_t | ||
192 | * | ||
193 | * Atomically increments @ptr by 1 | ||
194 | * and returns true if the result is zero, or false for all | ||
195 | * other cases. | ||
196 | */ | ||
197 | int atomic64_inc_and_test(atomic64_t *ptr) | ||
198 | { | ||
199 | return atomic64_sub_and_test(-1, ptr); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * atomic64_add_negative - add and test if negative | ||
204 | * @delta: integer value to add | ||
205 | * @ptr: pointer to type atomic64_t | ||
206 | * | ||
207 | * Atomically adds @delta to @ptr and returns true | ||
208 | * if the result is negative, or false when | ||
209 | * result is greater than or equal to zero. | ||
210 | */ | ||
211 | int atomic64_add_negative(u64 delta, atomic64_t *ptr) | ||
212 | { | ||
213 | long long old_val = atomic64_add_return(delta, ptr); | ||
214 | |||
215 | return old_val < 0; | ||
216 | } | ||