aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-07-03 07:26:39 -0400
committerIngo Molnar <mingo@elte.hu>2009-07-03 07:26:39 -0400
commitb7882b7c65abb00194bdb3d4a22d27d70fcc59ba (patch)
treef22b1090c014f6d1da33c3791590d636104e8841
parentbbf2a330d92c5afccfd17592ba9ccd50f41cf748 (diff)
x86: atomic64: Move the 32-bit atomic64_t implementation to a .c file
Linus noted that the atomic64_t primitives are all inlines currently which is crazy because these functions have a large register footprint anyway. Move them to a separate file: arch/x86/lib/atomic64_32.c Also, while at it, rename all uses of 'unsigned long long' to the much shorter u64. This makes the appearance of the prototypes a lot nicer - and it also uncovered a few bugs where (yet unused) API variants had 'long' as their return type instead of u64. [ More intrusive changes are not yet done in this patch. ] Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: David Howells <dhowells@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Arnd Bergmann <arnd@arndb.de> LKML-Reference: <alpine.LFD.2.01.0907021653030.3210@localhost.localdomain> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/include/asm/atomic_32.h137
-rw-r--r--arch/x86/lib/Makefile1
-rw-r--r--arch/x86/lib/atomic64_32.c216
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 ae0fbb5b057..311a43e47c0 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
252typedef struct { 252typedef 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
267static inline unsigned long long 267extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val);
268cmpxchg8b(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
286static inline unsigned long long
287atomic64_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 277extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val);
302static inline unsigned long long
303atomic64_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 */
321static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) 286extern 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 */
332static inline unsigned long long atomic64_read(atomic64_t *ptr) 294extern 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 */
350static inline unsigned long long 303extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr);
351atomic64_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
364static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr)
365{
366 return atomic64_add_return(-delta, ptr);
367}
368 304
369static 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} 308extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr);
373 309extern u64 atomic64_inc_return(atomic64_t *ptr);
374static inline long atomic64_dec_return(atomic64_t *ptr) 310extern 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 */
386static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) 319extern 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 */
398static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) 328extern 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 */
412static inline int 339extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr);
413atomic64_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 */
426static inline void atomic64_inc(atomic64_t *ptr) 347extern 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 */
437static inline void atomic64_dec(atomic64_t *ptr) 355extern 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 */
450static inline int atomic64_dec_and_test(atomic64_t *ptr) 365extern 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 */
463static inline int atomic64_inc_and_test(atomic64_t *ptr) 375extern 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 */
477static inline int 386extern int atomic64_add_negative(u64 delta, atomic64_t *ptr);
478atomic64_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 f9d35632666..c3c657c8bb8 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -10,6 +10,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o
10lib-y += memcpy_$(BITS).o 10lib-y += memcpy_$(BITS).o
11 11
12ifeq ($(CONFIG_X86_32),y) 12ifeq ($(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 00000000000..d21e725d3d8
--- /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
7static 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
25u64 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
39u64 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 */
57void 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 */
68u64 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 */
86u64 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
99u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
100{
101 return atomic64_add_return(-delta, ptr);
102}
103
104u64 atomic64_inc_return(atomic64_t *ptr)
105{
106 return atomic64_add_return(1, ptr);
107}
108
109u64 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 */
121void 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 */
133void 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 */
147int 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 */
160void 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 */
171void 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 */
184int 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 */
197int 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 */
211int 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}