ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-ppc64 / atomic.h
1 /*
2  * PowerPC64 atomic operations
3  *
4  * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
5  * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version
10  * 2 of the License, or (at your option) any later version.
11  */
12
13 #ifndef _ASM_PPC64_ATOMIC_H_ 
14 #define _ASM_PPC64_ATOMIC_H_
15
16 #include <asm/memory.h>
17
18 typedef struct { volatile int counter; } atomic_t;
19
20 #define ATOMIC_INIT(i)  { (i) }
21
22 #define atomic_read(v)          ((v)->counter)
23 #define atomic_set(v,i)         (((v)->counter) = (i))
24
25 static __inline__ void atomic_add(int a, atomic_t *v)
26 {
27         int t;
28
29         __asm__ __volatile__(
30 "1:     lwarx   %0,0,%3         # atomic_add\n\
31         add     %0,%2,%0\n\
32         stwcx.  %0,0,%3\n\
33         bne-    1b"
34         : "=&r" (t), "=m" (v->counter)
35         : "r" (a), "r" (&v->counter), "m" (v->counter)
36         : "cc");
37 }
38
39 static __inline__ int atomic_add_return(int a, atomic_t *v)
40 {
41         int t;
42
43         __asm__ __volatile__(
44         EIEIO_ON_SMP
45 "1:     lwarx   %0,0,%2         # atomic_add_return\n\
46         add     %0,%1,%0\n\
47         stwcx.  %0,0,%2\n\
48         bne-    1b"
49         ISYNC_ON_SMP
50         : "=&r" (t)
51         : "r" (a), "r" (&v->counter)
52         : "cc", "memory");
53
54         return t;
55 }
56
57 static __inline__ void atomic_sub(int a, atomic_t *v)
58 {
59         int t;
60
61         __asm__ __volatile__(
62 "1:     lwarx   %0,0,%3         # atomic_sub\n\
63         subf    %0,%2,%0\n\
64         stwcx.  %0,0,%3\n\
65         bne-    1b"
66         : "=&r" (t), "=m" (v->counter)
67         : "r" (a), "r" (&v->counter), "m" (v->counter)
68         : "cc");
69 }
70
71 static __inline__ int atomic_sub_return(int a, atomic_t *v)
72 {
73         int t;
74
75         __asm__ __volatile__(
76         EIEIO_ON_SMP
77 "1:     lwarx   %0,0,%2         # atomic_sub_return\n\
78         subf    %0,%1,%0\n\
79         stwcx.  %0,0,%2\n\
80         bne-    1b"
81         ISYNC_ON_SMP
82         : "=&r" (t)
83         : "r" (a), "r" (&v->counter)
84         : "cc", "memory");
85
86         return t;
87 }
88
89 static __inline__ void atomic_inc(atomic_t *v)
90 {
91         int t;
92
93         __asm__ __volatile__(
94 "1:     lwarx   %0,0,%2         # atomic_inc\n\
95         addic   %0,%0,1\n\
96         stwcx.  %0,0,%2\n\
97         bne-    1b"
98         : "=&r" (t), "=m" (v->counter)
99         : "r" (&v->counter), "m" (v->counter)
100         : "cc");
101 }
102
103 static __inline__ int atomic_inc_return(atomic_t *v)
104 {
105         int t;
106
107         __asm__ __volatile__(
108         EIEIO_ON_SMP
109 "1:     lwarx   %0,0,%1         # atomic_inc_return\n\
110         addic   %0,%0,1\n\
111         stwcx.  %0,0,%1\n\
112         bne-    1b"
113         ISYNC_ON_SMP
114         : "=&r" (t)
115         : "r" (&v->counter)
116         : "cc", "memory");
117
118         return t;
119 }
120
121 static __inline__ void atomic_dec(atomic_t *v)
122 {
123         int t;
124
125         __asm__ __volatile__(
126 "1:     lwarx   %0,0,%2         # atomic_dec\n\
127         addic   %0,%0,-1\n\
128         stwcx.  %0,0,%2\n\
129         bne-    1b"
130         : "=&r" (t), "=m" (v->counter)
131         : "r" (&v->counter), "m" (v->counter)
132         : "cc");
133 }
134
135 static __inline__ int atomic_dec_return(atomic_t *v)
136 {
137         int t;
138
139         __asm__ __volatile__(
140         EIEIO_ON_SMP
141 "1:     lwarx   %0,0,%1         # atomic_dec_return\n\
142         addic   %0,%0,-1\n\
143         stwcx.  %0,0,%1\n\
144         bne-    1b"
145         ISYNC_ON_SMP
146         : "=&r" (t)
147         : "r" (&v->counter)
148         : "cc", "memory");
149
150         return t;
151 }
152
153 #define atomic_sub_and_test(a, v)       (atomic_sub_return((a), (v)) == 0)
154 #define atomic_dec_and_test(v)          (atomic_dec_return((v)) == 0)
155
156 /*
157  * Atomically test *v and decrement if it is greater than 0.
158  * The function returns the old value of *v minus 1.
159  */
160 static __inline__ int atomic_dec_if_positive(atomic_t *v)
161 {
162         int t;
163
164         __asm__ __volatile__(
165         EIEIO_ON_SMP
166 "1:     lwarx   %0,0,%1         # atomic_dec_if_positive\n\
167         addic.  %0,%0,-1\n\
168         blt-    2f\n\
169         stwcx.  %0,0,%1\n\
170         bne-    1b"
171         ISYNC_ON_SMP
172         "\n\
173 2:"     : "=&r" (t)
174         : "r" (&v->counter)
175         : "cc", "memory");
176
177         return t;
178 }
179
180 #define smp_mb__before_atomic_dec()     smp_mb()
181 #define smp_mb__after_atomic_dec()      smp_mb()
182 #define smp_mb__before_atomic_inc()     smp_mb()
183 #define smp_mb__after_atomic_inc()      smp_mb()
184
185 #endif /* _ASM_PPC64_ATOMIC_H_ */