File: /usr/src/linux/include/asm-mips/atomic.h
1 /*
2 * Atomic operations that C can't guarantee us. Useful for
3 * resource counting etc..
4 *
5 * But use these as seldom as possible since they are much more slower
6 * than regular operations.
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 *
12 * Copyright (C) 1996, 1997, 2000 by Ralf Baechle
13 */
14 #ifndef __ASM_ATOMIC_H
15 #define __ASM_ATOMIC_H
16
17 #include <linux/config.h>
18
19 typedef struct { volatile int counter; } atomic_t;
20
21 #ifdef __KERNEL__
22 #define ATOMIC_INIT(i) { (i) }
23
24 /*
25 * atomic_read - read atomic variable
26 * @v: pointer of type atomic_t
27 *
28 * Atomically reads the value of @v. Note that the guaranteed
29 * useful range of an atomic_t is only 24 bits.
30 */
31 #define atomic_read(v) ((v)->counter)
32
33 /*
34 * atomic_set - set atomic variable
35 * @v: pointer of type atomic_t
36 * @i: required value
37 *
38 * Atomically sets the value of @v to @i. Note that the guaranteed
39 * useful range of an atomic_t is only 24 bits.
40 */
41 #define atomic_set(v,i) ((v)->counter = (i))
42
43 #ifndef CONFIG_CPU_HAS_LLSC
44
45 #include <asm/system.h>
46
47 /*
48 * The MIPS I implementation is only atomic with respect to
49 * interrupts. R3000 based multiprocessor machines are rare anyway ...
50 *
51 * atomic_add - add integer to atomic variable
52 * @i: integer value to add
53 * @v: pointer of type atomic_t
54 *
55 * Atomically adds @i to @v. Note that the guaranteed useful range
56 * of an atomic_t is only 24 bits.
57 */
58 extern __inline__ void atomic_add(int i, atomic_t * v)
59 {
60 int flags;
61
62 save_flags(flags);
63 cli();
64 v->counter += i;
65 restore_flags(flags);
66 }
67
68 /*
69 * atomic_sub - subtract the atomic variable
70 * @i: integer value to subtract
71 * @v: pointer of type atomic_t
72 *
73 * Atomically subtracts @i from @v. Note that the guaranteed
74 * useful range of an atomic_t is only 24 bits.
75 */
76 extern __inline__ void atomic_sub(int i, atomic_t * v)
77 {
78 int flags;
79
80 save_flags(flags);
81 cli();
82 v->counter -= i;
83 restore_flags(flags);
84 }
85
86 extern __inline__ int atomic_add_return(int i, atomic_t * v)
87 {
88 int temp, flags;
89
90 save_flags(flags);
91 cli();
92 temp = v->counter;
93 temp += i;
94 v->counter = temp;
95 restore_flags(flags);
96
97 return temp;
98 }
99
100 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
101 {
102 int temp, flags;
103
104 save_flags(flags);
105 cli();
106 temp = v->counter;
107 temp -= i;
108 v->counter = temp;
109 restore_flags(flags);
110
111 return temp;
112 }
113
114 #else
115
116 /*
117 * ... while for MIPS II and better we can use ll/sc instruction. This
118 * implementation is SMP safe ...
119 */
120
121 /*
122 * atomic_add - add integer to atomic variable
123 * @i: integer value to add
124 * @v: pointer of type atomic_t
125 *
126 * Atomically adds @i to @v. Note that the guaranteed useful range
127 * of an atomic_t is only 24 bits.
128 */
129 extern __inline__ void atomic_add(int i, atomic_t * v)
130 {
131 unsigned long temp;
132
133 __asm__ __volatile__(
134 "1: ll %0, %1 # atomic_add\n"
135 " addu %0, %2 \n"
136 " sc %0, %1 \n"
137 " beqz %0, 1b \n"
138 : "=&r" (temp), "=m" (v->counter)
139 : "Ir" (i), "m" (v->counter));
140 }
141
142 /*
143 * atomic_sub - subtract the atomic variable
144 * @i: integer value to subtract
145 * @v: pointer of type atomic_t
146 *
147 * Atomically subtracts @i from @v. Note that the guaranteed
148 * useful range of an atomic_t is only 24 bits.
149 */
150 extern __inline__ void atomic_sub(int i, atomic_t * v)
151 {
152 unsigned long temp;
153
154 __asm__ __volatile__(
155 "1: ll %0, %1 # atomic_sub\n"
156 " subu %0, %2 \n"
157 " sc %0, %1 \n"
158 " beqz %0, 1b \n"
159 : "=&r" (temp), "=m" (v->counter)
160 : "Ir" (i), "m" (v->counter));
161 }
162
163 /*
164 * Same as above, but return the result value
165 */
166 extern __inline__ int atomic_add_return(int i, atomic_t * v)
167 {
168 unsigned long temp, result;
169
170 __asm__ __volatile__(
171 ".set push # atomic_add_return\n"
172 ".set noreorder \n"
173 "1: ll %1, %2 \n"
174 " addu %0, %1, %3 \n"
175 " sc %0, %2 \n"
176 " beqz %0, 1b \n"
177 " addu %0, %1, %3 \n"
178 ".set pop \n"
179 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
180 : "Ir" (i), "m" (v->counter)
181 : "memory");
182
183 return result;
184 }
185
186 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
187 {
188 unsigned long temp, result;
189
190 __asm__ __volatile__(
191 ".set push \n"
192 ".set noreorder # atomic_sub_return\n"
193 "1: ll %1, %2 \n"
194 " subu %0, %1, %3 \n"
195 " sc %0, %2 \n"
196 " beqz %0, 1b \n"
197 " subu %0, %1, %3 \n"
198 ".set pop \n"
199 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
200 : "Ir" (i), "m" (v->counter)
201 : "memory");
202
203 return result;
204 }
205 #endif
206
207 #define atomic_dec_return(v) atomic_sub_return(1,(v))
208 #define atomic_inc_return(v) atomic_add_return(1,(v))
209
210 /*
211 * atomic_sub_and_test - subtract value from variable and test result
212 * @i: integer value to subtract
213 * @v: pointer of type atomic_t
214 *
215 * Atomically subtracts @i from @v and returns
216 * true if the result is zero, or false for all
217 * other cases. Note that the guaranteed
218 * useful range of an atomic_t is only 24 bits.
219 */
220 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
221
222 /*
223 * atomic_inc_and_test - increment and test
224 * @v: pointer of type atomic_t
225 *
226 * Atomically increments @v by 1
227 * and returns true if the result is zero, or false for all
228 * other cases. Note that the guaranteed
229 * useful range of an atomic_t is only 24 bits.
230 */
231 #define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)
232
233 /*
234 * atomic_dec_and_test - decrement by 1 and test
235 * @v: pointer of type atomic_t
236 *
237 * Atomically decrements @v by 1 and
238 * returns true if the result is 0, or false for all other
239 * cases. Note that the guaranteed
240 * useful range of an atomic_t is only 24 bits.
241 */
242 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
243
244 /*
245 * atomic_inc - increment atomic variable
246 * @v: pointer of type atomic_t
247 *
248 * Atomically increments @v by 1. Note that the guaranteed
249 * useful range of an atomic_t is only 24 bits.
250 */
251 #define atomic_inc(v) atomic_add(1,(v))
252
253 /*
254 * atomic_dec - decrement and test
255 * @v: pointer of type atomic_t
256 *
257 * Atomically decrements @v by 1. Note that the guaranteed
258 * useful range of an atomic_t is only 24 bits.
259 */
260 #define atomic_dec(v) atomic_sub(1,(v))
261
262 /*
263 * atomic_add_negative - add and test if negative
264 * @v: pointer of type atomic_t
265 * @i: integer value to add
266 *
267 * Atomically adds @i to @v and returns true
268 * if the result is negative, or false when
269 * result is greater than or equal to zero. Note that the guaranteed
270 * useful range of an atomic_t is only 24 bits.
271 *
272 * Currently not implemented for MIPS.
273 */
274
275 /* Atomic operations are already serializing */
276 #define smp_mb__before_atomic_dec() barrier()
277 #define smp_mb__after_atomic_dec() barrier()
278 #define smp_mb__before_atomic_inc() barrier()
279 #define smp_mb__after_atomic_inc() barrier()
280
281 #endif /* defined(__KERNEL__) */
282
283 #endif /* __ASM_ATOMIC_H */
284