more changes on original files
[linux-2.4.git] / include / asm-ppc / atomic.h
1 /*
2  * PowerPC atomic operations
3  */
4
5 #ifndef _ASM_PPC_ATOMIC_H_
6 #define _ASM_PPC_ATOMIC_H_
7
8 typedef struct { volatile int counter; } atomic_t;
9
10 #ifdef __KERNEL__
11
12 #define ATOMIC_INIT(i)  { (i) }
13
14 #define atomic_read(v)          ((v)->counter)
15 #define atomic_set(v,i)         (((v)->counter) = (i))
16
17 extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
18 extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
19
20 #ifdef CONFIG_SMP
21 #define SMP_ISYNC       "\n\tisync"
22 #else
23 #define SMP_ISYNC
24 #endif
25
26 /* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx.
27  * The old ATOMIC_SYNC_FIX covered some but not all of this.
28  */
29 #ifdef CONFIG_IBM405_ERR77
30 #define PPC405_ERR77(ra,rb)     "dcbt " #ra "," #rb ";"
31 #else
32 #define PPC405_ERR77(ra,rb)
33 #endif
34
35 static __inline__ void atomic_add(int a, atomic_t *v)
36 {
37         int t;
38
39         __asm__ __volatile__(
40 "1:     lwarx   %0,0,%3         # atomic_add\n\
41         add     %0,%2,%0\n"
42         PPC405_ERR77(0,%3)
43 "       stwcx.  %0,0,%3 \n\
44         bne-    1b"
45         : "=&r" (t), "=m" (v->counter)
46         : "r" (a), "r" (&v->counter), "m" (v->counter)
47         : "cc");
48 }
49
50 static __inline__ int atomic_add_return(int a, atomic_t *v)
51 {
52         int t;
53
54         __asm__ __volatile__(
55 "1:     lwarx   %0,0,%2         # atomic_add_return\n\
56         add     %0,%1,%0\n"
57         PPC405_ERR77(0,%2)
58 "       stwcx.  %0,0,%2 \n\
59         bne-    1b"
60         SMP_ISYNC
61         : "=&r" (t)
62         : "r" (a), "r" (&v->counter)
63         : "cc", "memory");
64
65         return t;
66 }
67
68 static __inline__ void atomic_sub(int a, atomic_t *v)
69 {
70         int t;
71
72         __asm__ __volatile__(
73 "1:     lwarx   %0,0,%3         # atomic_sub\n\
74         subf    %0,%2,%0\n"
75         PPC405_ERR77(0,%3)
76 "       stwcx.  %0,0,%3 \n\
77         bne-    1b"
78         : "=&r" (t), "=m" (v->counter)
79         : "r" (a), "r" (&v->counter), "m" (v->counter)
80         : "cc");
81 }
82
83 static __inline__ int atomic_sub_return(int a, atomic_t *v)
84 {
85         int t;
86
87         __asm__ __volatile__(
88 "1:     lwarx   %0,0,%2         # atomic_sub_return\n\
89         subf    %0,%1,%0\n"
90         PPC405_ERR77(0,%2)
91 "       stwcx.  %0,0,%2 \n\
92         bne-    1b"
93         SMP_ISYNC
94         : "=&r" (t)
95         : "r" (a), "r" (&v->counter)
96         : "cc", "memory");
97
98         return t;
99 }
100
101 static __inline__ void atomic_inc(atomic_t *v)
102 {
103         int t;
104
105         __asm__ __volatile__(
106 "1:     lwarx   %0,0,%2         # atomic_inc\n\
107         addic   %0,%0,1\n"
108         PPC405_ERR77(0,%2)
109 "       stwcx.  %0,0,%2 \n\
110         bne-    1b"
111         : "=&r" (t), "=m" (v->counter)
112         : "r" (&v->counter), "m" (v->counter)
113         : "cc");
114 }
115
116 static __inline__ int atomic_inc_return(atomic_t *v)
117 {
118         int t;
119
120         __asm__ __volatile__(
121 "1:     lwarx   %0,0,%1         # atomic_inc_return\n\
122         addic   %0,%0,1\n"
123         PPC405_ERR77(0,%1)
124 "       stwcx.  %0,0,%1 \n\
125         bne-    1b"
126         SMP_ISYNC
127         : "=&r" (t)
128         : "r" (&v->counter)
129         : "cc", "memory");
130
131         return t;
132 }
133
134 static __inline__ void atomic_dec(atomic_t *v)
135 {
136         int t;
137
138         __asm__ __volatile__(
139 "1:     lwarx   %0,0,%2         # atomic_dec\n\
140         addic   %0,%0,-1\n"
141         PPC405_ERR77(0,%2)\
142 "       stwcx.  %0,0,%2\n\
143         bne-    1b"
144         : "=&r" (t), "=m" (v->counter)
145         : "r" (&v->counter), "m" (v->counter)
146         : "cc");
147 }
148
149 static __inline__ int atomic_dec_return(atomic_t *v)
150 {
151         int t;
152
153         __asm__ __volatile__(
154 "1:     lwarx   %0,0,%1         # atomic_dec_return\n\
155         addic   %0,%0,-1\n"
156         PPC405_ERR77(0,%1)
157 "       stwcx.  %0,0,%1\n\
158         bne-    1b"
159         SMP_ISYNC
160         : "=&r" (t)
161         : "r" (&v->counter)
162         : "cc", "memory");
163
164         return t;
165 }
166
167 #define atomic_sub_and_test(a, v)       (atomic_sub_return((a), (v)) == 0)
168 #define atomic_dec_and_test(v)          (atomic_dec_return((v)) == 0)
169
170 /*
171  * Atomically test *v and decrement if it is greater than 0.
172  * The function returns the old value of *v minus 1.
173  */
174 static __inline__ int atomic_dec_if_positive(atomic_t *v)
175 {
176         int t;
177
178         __asm__ __volatile__(
179 "1:     lwarx   %0,0,%1         # atomic_dec_if_positive\n\
180         addic.  %0,%0,-1\n\
181         blt-    2f\n"
182         PPC405_ERR77(0,%1)
183 "       stwcx.  %0,0,%1\n\
184         bne-    1b"
185         SMP_ISYNC
186         "\n\
187 2:"     : "=&r" (t)
188         : "r" (&v->counter)
189         : "cc", "memory");
190
191         return t;
192 }
193
194 #define smp_mb__before_atomic_dec()     smp_mb()
195 #define smp_mb__after_atomic_dec()      smp_mb()
196 #define smp_mb__before_atomic_inc()     smp_mb()
197 #define smp_mb__after_atomic_inc()      smp_mb()
198
199 #endif /* __KERNEL__ */
200 #endif /* _ASM_PPC_ATOMIC_H_ */