28992d01292633f2d473eeae47e202497fa691a6
[deliverable/linux.git] / arch / powerpc / include / asm / atomic.h
1 #ifndef _ASM_POWERPC_ATOMIC_H_
2 #define _ASM_POWERPC_ATOMIC_H_
3
4 /*
5 * PowerPC atomic operations
6 */
7
8 #ifdef __KERNEL__
9 #include <linux/types.h>
10 #include <asm/cmpxchg.h>
11 #include <asm/barrier.h>
12
13 #define ATOMIC_INIT(i) { (i) }
14
15 static __inline__ int atomic_read(const atomic_t *v)
16 {
17 int t;
18
19 __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
20
21 return t;
22 }
23
24 static __inline__ void atomic_set(atomic_t *v, int i)
25 {
26 __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
27 }
28
29 static __inline__ void atomic_add(int a, atomic_t *v)
30 {
31 int t;
32
33 __asm__ __volatile__(
34 "1: lwarx %0,0,%3 # atomic_add\n\
35 add %0,%2,%0\n"
36 PPC405_ERR77(0,%3)
37 " stwcx. %0,0,%3 \n\
38 bne- 1b"
39 : "=&r" (t), "+m" (v->counter)
40 : "r" (a), "r" (&v->counter)
41 : "cc");
42 }
43
44 static __inline__ int atomic_add_return(int a, atomic_t *v)
45 {
46 int t;
47
48 __asm__ __volatile__(
49 PPC_ATOMIC_ENTRY_BARRIER
50 "1: lwarx %0,0,%2 # atomic_add_return\n\
51 add %0,%1,%0\n"
52 PPC405_ERR77(0,%2)
53 " stwcx. %0,0,%2 \n\
54 bne- 1b"
55 PPC_ATOMIC_EXIT_BARRIER
56 : "=&r" (t)
57 : "r" (a), "r" (&v->counter)
58 : "cc", "memory");
59
60 return t;
61 }
62
63 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
64
65 static __inline__ void atomic_sub(int a, atomic_t *v)
66 {
67 int t;
68
69 __asm__ __volatile__(
70 "1: lwarx %0,0,%3 # atomic_sub\n\
71 subf %0,%2,%0\n"
72 PPC405_ERR77(0,%3)
73 " stwcx. %0,0,%3 \n\
74 bne- 1b"
75 : "=&r" (t), "+m" (v->counter)
76 : "r" (a), "r" (&v->counter)
77 : "cc");
78 }
79
80 static __inline__ int atomic_sub_return(int a, atomic_t *v)
81 {
82 int t;
83
84 __asm__ __volatile__(
85 PPC_ATOMIC_ENTRY_BARRIER
86 "1: lwarx %0,0,%2 # atomic_sub_return\n\
87 subf %0,%1,%0\n"
88 PPC405_ERR77(0,%2)
89 " stwcx. %0,0,%2 \n\
90 bne- 1b"
91 PPC_ATOMIC_EXIT_BARRIER
92 : "=&r" (t)
93 : "r" (a), "r" (&v->counter)
94 : "cc", "memory");
95
96 return t;
97 }
98
99 static __inline__ void atomic_inc(atomic_t *v)
100 {
101 int t;
102
103 __asm__ __volatile__(
104 "1: lwarx %0,0,%2 # atomic_inc\n\
105 addic %0,%0,1\n"
106 PPC405_ERR77(0,%2)
107 " stwcx. %0,0,%2 \n\
108 bne- 1b"
109 : "=&r" (t), "+m" (v->counter)
110 : "r" (&v->counter)
111 : "cc", "xer");
112 }
113
114 static __inline__ int atomic_inc_return(atomic_t *v)
115 {
116 int t;
117
118 __asm__ __volatile__(
119 PPC_ATOMIC_ENTRY_BARRIER
120 "1: lwarx %0,0,%1 # atomic_inc_return\n\
121 addic %0,%0,1\n"
122 PPC405_ERR77(0,%1)
123 " stwcx. %0,0,%1 \n\
124 bne- 1b"
125 PPC_ATOMIC_EXIT_BARRIER
126 : "=&r" (t)
127 : "r" (&v->counter)
128 : "cc", "xer", "memory");
129
130 return t;
131 }
132
133 /*
134 * atomic_inc_and_test - increment and test
135 * @v: pointer of type atomic_t
136 *
137 * Atomically increments @v by 1
138 * and returns true if the result is zero, or false for all
139 * other cases.
140 */
141 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
142
143 static __inline__ void atomic_dec(atomic_t *v)
144 {
145 int t;
146
147 __asm__ __volatile__(
148 "1: lwarx %0,0,%2 # atomic_dec\n\
149 addic %0,%0,-1\n"
150 PPC405_ERR77(0,%2)\
151 " stwcx. %0,0,%2\n\
152 bne- 1b"
153 : "=&r" (t), "+m" (v->counter)
154 : "r" (&v->counter)
155 : "cc", "xer");
156 }
157
158 static __inline__ int atomic_dec_return(atomic_t *v)
159 {
160 int t;
161
162 __asm__ __volatile__(
163 PPC_ATOMIC_ENTRY_BARRIER
164 "1: lwarx %0,0,%1 # atomic_dec_return\n\
165 addic %0,%0,-1\n"
166 PPC405_ERR77(0,%1)
167 " stwcx. %0,0,%1\n\
168 bne- 1b"
169 PPC_ATOMIC_EXIT_BARRIER
170 : "=&r" (t)
171 : "r" (&v->counter)
172 : "cc", "xer", "memory");
173
174 return t;
175 }
176
177 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
178 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
179
180 /**
181 * __atomic_add_unless - add unless the number is a given value
182 * @v: pointer of type atomic_t
183 * @a: the amount to add to v...
184 * @u: ...unless v is equal to u.
185 *
186 * Atomically adds @a to @v, so long as it was not @u.
187 * Returns the old value of @v.
188 */
189 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
190 {
191 int t;
192
193 __asm__ __volatile__ (
194 PPC_ATOMIC_ENTRY_BARRIER
195 "1: lwarx %0,0,%1 # __atomic_add_unless\n\
196 cmpw 0,%0,%3 \n\
197 beq- 2f \n\
198 add %0,%2,%0 \n"
199 PPC405_ERR77(0,%2)
200 " stwcx. %0,0,%1 \n\
201 bne- 1b \n"
202 PPC_ATOMIC_EXIT_BARRIER
203 " subf %0,%2,%0 \n\
204 2:"
205 : "=&r" (t)
206 : "r" (&v->counter), "r" (a), "r" (u)
207 : "cc", "memory");
208
209 return t;
210 }
211
212 /**
213 * atomic_inc_not_zero - increment unless the number is zero
214 * @v: pointer of type atomic_t
215 *
216 * Atomically increments @v by 1, so long as @v is non-zero.
217 * Returns non-zero if @v was non-zero, and zero otherwise.
218 */
219 static __inline__ int atomic_inc_not_zero(atomic_t *v)
220 {
221 int t1, t2;
222
223 __asm__ __volatile__ (
224 PPC_ATOMIC_ENTRY_BARRIER
225 "1: lwarx %0,0,%2 # atomic_inc_not_zero\n\
226 cmpwi 0,%0,0\n\
227 beq- 2f\n\
228 addic %1,%0,1\n"
229 PPC405_ERR77(0,%2)
230 " stwcx. %1,0,%2\n\
231 bne- 1b\n"
232 PPC_ATOMIC_EXIT_BARRIER
233 "\n\
234 2:"
235 : "=&r" (t1), "=&r" (t2)
236 : "r" (&v->counter)
237 : "cc", "xer", "memory");
238
239 return t1;
240 }
241 #define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
242
243 #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0)
244 #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0)
245
246 /*
247 * Atomically test *v and decrement if it is greater than 0.
248 * The function returns the old value of *v minus 1, even if
249 * the atomic variable, v, was not decremented.
250 */
251 static __inline__ int atomic_dec_if_positive(atomic_t *v)
252 {
253 int t;
254
255 __asm__ __volatile__(
256 PPC_ATOMIC_ENTRY_BARRIER
257 "1: lwarx %0,0,%1 # atomic_dec_if_positive\n\
258 cmpwi %0,1\n\
259 addi %0,%0,-1\n\
260 blt- 2f\n"
261 PPC405_ERR77(0,%1)
262 " stwcx. %0,0,%1\n\
263 bne- 1b"
264 PPC_ATOMIC_EXIT_BARRIER
265 "\n\
266 2:" : "=&b" (t)
267 : "r" (&v->counter)
268 : "cc", "memory");
269
270 return t;
271 }
272 #define atomic_dec_if_positive atomic_dec_if_positive
273
274 #ifdef __powerpc64__
275
276 #define ATOMIC64_INIT(i) { (i) }
277
278 static __inline__ long atomic64_read(const atomic64_t *v)
279 {
280 long t;
281
282 __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
283
284 return t;
285 }
286
287 static __inline__ void atomic64_set(atomic64_t *v, long i)
288 {
289 __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
290 }
291
292 static __inline__ void atomic64_add(long a, atomic64_t *v)
293 {
294 long t;
295
296 __asm__ __volatile__(
297 "1: ldarx %0,0,%3 # atomic64_add\n\
298 add %0,%2,%0\n\
299 stdcx. %0,0,%3 \n\
300 bne- 1b"
301 : "=&r" (t), "+m" (v->counter)
302 : "r" (a), "r" (&v->counter)
303 : "cc");
304 }
305
306 static __inline__ long atomic64_add_return(long a, atomic64_t *v)
307 {
308 long t;
309
310 __asm__ __volatile__(
311 PPC_ATOMIC_ENTRY_BARRIER
312 "1: ldarx %0,0,%2 # atomic64_add_return\n\
313 add %0,%1,%0\n\
314 stdcx. %0,0,%2 \n\
315 bne- 1b"
316 PPC_ATOMIC_EXIT_BARRIER
317 : "=&r" (t)
318 : "r" (a), "r" (&v->counter)
319 : "cc", "memory");
320
321 return t;
322 }
323
324 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
325
326 static __inline__ void atomic64_sub(long a, atomic64_t *v)
327 {
328 long t;
329
330 __asm__ __volatile__(
331 "1: ldarx %0,0,%3 # atomic64_sub\n\
332 subf %0,%2,%0\n\
333 stdcx. %0,0,%3 \n\
334 bne- 1b"
335 : "=&r" (t), "+m" (v->counter)
336 : "r" (a), "r" (&v->counter)
337 : "cc");
338 }
339
340 static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
341 {
342 long t;
343
344 __asm__ __volatile__(
345 PPC_ATOMIC_ENTRY_BARRIER
346 "1: ldarx %0,0,%2 # atomic64_sub_return\n\
347 subf %0,%1,%0\n\
348 stdcx. %0,0,%2 \n\
349 bne- 1b"
350 PPC_ATOMIC_EXIT_BARRIER
351 : "=&r" (t)
352 : "r" (a), "r" (&v->counter)
353 : "cc", "memory");
354
355 return t;
356 }
357
358 static __inline__ void atomic64_inc(atomic64_t *v)
359 {
360 long t;
361
362 __asm__ __volatile__(
363 "1: ldarx %0,0,%2 # atomic64_inc\n\
364 addic %0,%0,1\n\
365 stdcx. %0,0,%2 \n\
366 bne- 1b"
367 : "=&r" (t), "+m" (v->counter)
368 : "r" (&v->counter)
369 : "cc", "xer");
370 }
371
372 static __inline__ long atomic64_inc_return(atomic64_t *v)
373 {
374 long t;
375
376 __asm__ __volatile__(
377 PPC_ATOMIC_ENTRY_BARRIER
378 "1: ldarx %0,0,%1 # atomic64_inc_return\n\
379 addic %0,%0,1\n\
380 stdcx. %0,0,%1 \n\
381 bne- 1b"
382 PPC_ATOMIC_EXIT_BARRIER
383 : "=&r" (t)
384 : "r" (&v->counter)
385 : "cc", "xer", "memory");
386
387 return t;
388 }
389
390 /*
391 * atomic64_inc_and_test - increment and test
392 * @v: pointer of type atomic64_t
393 *
394 * Atomically increments @v by 1
395 * and returns true if the result is zero, or false for all
396 * other cases.
397 */
398 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
399
400 static __inline__ void atomic64_dec(atomic64_t *v)
401 {
402 long t;
403
404 __asm__ __volatile__(
405 "1: ldarx %0,0,%2 # atomic64_dec\n\
406 addic %0,%0,-1\n\
407 stdcx. %0,0,%2\n\
408 bne- 1b"
409 : "=&r" (t), "+m" (v->counter)
410 : "r" (&v->counter)
411 : "cc", "xer");
412 }
413
414 static __inline__ long atomic64_dec_return(atomic64_t *v)
415 {
416 long t;
417
418 __asm__ __volatile__(
419 PPC_ATOMIC_ENTRY_BARRIER
420 "1: ldarx %0,0,%1 # atomic64_dec_return\n\
421 addic %0,%0,-1\n\
422 stdcx. %0,0,%1\n\
423 bne- 1b"
424 PPC_ATOMIC_EXIT_BARRIER
425 : "=&r" (t)
426 : "r" (&v->counter)
427 : "cc", "xer", "memory");
428
429 return t;
430 }
431
432 #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0)
433 #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
434
435 /*
436 * Atomically test *v and decrement if it is greater than 0.
437 * The function returns the old value of *v minus 1.
438 */
439 static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
440 {
441 long t;
442
443 __asm__ __volatile__(
444 PPC_ATOMIC_ENTRY_BARRIER
445 "1: ldarx %0,0,%1 # atomic64_dec_if_positive\n\
446 addic. %0,%0,-1\n\
447 blt- 2f\n\
448 stdcx. %0,0,%1\n\
449 bne- 1b"
450 PPC_ATOMIC_EXIT_BARRIER
451 "\n\
452 2:" : "=&r" (t)
453 : "r" (&v->counter)
454 : "cc", "xer", "memory");
455
456 return t;
457 }
458
459 #define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
460 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
461
462 /**
463 * atomic64_add_unless - add unless the number is a given value
464 * @v: pointer of type atomic64_t
465 * @a: the amount to add to v...
466 * @u: ...unless v is equal to u.
467 *
468 * Atomically adds @a to @v, so long as it was not @u.
469 * Returns the old value of @v.
470 */
471 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
472 {
473 long t;
474
475 __asm__ __volatile__ (
476 PPC_ATOMIC_ENTRY_BARRIER
477 "1: ldarx %0,0,%1 # __atomic_add_unless\n\
478 cmpd 0,%0,%3 \n\
479 beq- 2f \n\
480 add %0,%2,%0 \n"
481 " stdcx. %0,0,%1 \n\
482 bne- 1b \n"
483 PPC_ATOMIC_EXIT_BARRIER
484 " subf %0,%2,%0 \n\
485 2:"
486 : "=&r" (t)
487 : "r" (&v->counter), "r" (a), "r" (u)
488 : "cc", "memory");
489
490 return t != u;
491 }
492
493 /**
494 * atomic_inc64_not_zero - increment unless the number is zero
495 * @v: pointer of type atomic64_t
496 *
497 * Atomically increments @v by 1, so long as @v is non-zero.
498 * Returns non-zero if @v was non-zero, and zero otherwise.
499 */
500 static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
501 {
502 long t1, t2;
503
504 __asm__ __volatile__ (
505 PPC_ATOMIC_ENTRY_BARRIER
506 "1: ldarx %0,0,%2 # atomic64_inc_not_zero\n\
507 cmpdi 0,%0,0\n\
508 beq- 2f\n\
509 addic %1,%0,1\n\
510 stdcx. %1,0,%2\n\
511 bne- 1b\n"
512 PPC_ATOMIC_EXIT_BARRIER
513 "\n\
514 2:"
515 : "=&r" (t1), "=&r" (t2)
516 : "r" (&v->counter)
517 : "cc", "xer", "memory");
518
519 return t1;
520 }
521
522 #endif /* __powerpc64__ */
523
524 #endif /* __KERNEL__ */
525 #endif /* _ASM_POWERPC_ATOMIC_H_ */
This page took 0.043027 seconds and 4 git commands to generate.