VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / 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, 97, 99, 2000, 03, 04 by Ralf Baechle
13  */
14
15 /*
16  * As workaround for the ATOMIC_DEC_AND_LOCK / atomic_dec_and_lock mess in
17  * <linux/spinlock.h> we have to include <linux/spinlock.h> outside the
18  * main big wrapper ...
19  */
20 #include <linux/config.h>
21 #include <linux/spinlock.h>
22
23 #ifndef _ASM_ATOMIC_H
24 #define _ASM_ATOMIC_H
25
26 extern spinlock_t atomic_lock;
27
28 typedef struct { volatile int counter; } atomic_t;
29
30 #define ATOMIC_INIT(i)    { (i) }
31
32 /*
33  * atomic_read - read atomic variable
34  * @v: pointer of type atomic_t
35  *
36  * Atomically reads the value of @v.
37  */
38 #define atomic_read(v)          ((v)->counter)
39
40 /*
41  * atomic_set - set atomic variable
42  * @v: pointer of type atomic_t
43  * @i: required value
44  *
45  * Atomically sets the value of @v to @i.
46  */
47 #define atomic_set(v,i)         ((v)->counter = (i))
48
49 #ifdef CONFIG_CPU_HAS_LLSC
50
51 /*
52  * atomic_add - add integer to atomic variable
53  * @i: integer value to add
54  * @v: pointer of type atomic_t
55  *
56  * Atomically adds @i to @v.
57  */
58 static __inline__ void atomic_add(int i, atomic_t * v)
59 {
60         unsigned long temp;
61
62         __asm__ __volatile__(
63         "1:     ll      %0, %1          # atomic_add            \n"
64         "       addu    %0, %2                                  \n"
65         "       sc      %0, %1                                  \n"
66         "       beqz    %0, 1b                                  \n"
67         : "=&r" (temp), "=m" (v->counter)
68         : "Ir" (i), "m" (v->counter));
69 }
70
71 /*
72  * atomic_sub - subtract the atomic variable
73  * @i: integer value to subtract
74  * @v: pointer of type atomic_t
75  *
76  * Atomically subtracts @i from @v.
77  */
78 static __inline__ void atomic_sub(int i, atomic_t * v)
79 {
80         unsigned long temp;
81
82         __asm__ __volatile__(
83         "1:     ll      %0, %1          # atomic_sub            \n"
84         "       subu    %0, %2                                  \n"
85         "       sc      %0, %1                                  \n"
86         "       beqz    %0, 1b                                  \n"
87         : "=&r" (temp), "=m" (v->counter)
88         : "Ir" (i), "m" (v->counter));
89 }
90
91 /*
92  * Same as above, but return the result value
93  */
94 static __inline__ int atomic_add_return(int i, atomic_t * v)
95 {
96         unsigned long temp, result;
97
98         __asm__ __volatile__(
99         "1:     ll      %1, %2          # atomic_add_return     \n"
100         "       addu    %0, %1, %3                              \n"
101         "       sc      %0, %2                                  \n"
102         "       beqz    %0, 1b                                  \n"
103         "       addu    %0, %1, %3                              \n"
104         "       sync                                            \n"
105         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
106         : "Ir" (i), "m" (v->counter)
107         : "memory");
108
109         return result;
110 }
111
112 static __inline__ int atomic_sub_return(int i, atomic_t * v)
113 {
114         unsigned long temp, result;
115
116         __asm__ __volatile__(
117         "1:     ll      %1, %2          # atomic_sub_return     \n"
118         "       subu    %0, %1, %3                              \n"
119         "       sc      %0, %2                                  \n"
120         "       beqz    %0, 1b                                  \n"
121         "       subu    %0, %1, %3                              \n"
122         "       sync                                            \n"
123         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
124         : "Ir" (i), "m" (v->counter)
125         : "memory");
126
127         return result;
128 }
129
130 /*
131  * atomic_sub_if_positive - add integer to atomic variable
132  * @v: pointer of type atomic_t
133  *
134  * Atomically test @v and decrement if it is greater than 0.
135  * The function returns the old value of @v minus 1.
136  */
137 static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
138 {
139         unsigned long temp, result;
140
141         __asm__ __volatile__(
142         "1:     ll      %1, %2          # atomic_sub_if_positive\n"
143         "       subu    %0, %1, %3                              \n"
144         "       bltz    %0, 1f                                  \n"
145         "       sc      %0, %2                                  \n"
146         "       beqz    %0, 1b                                  \n"
147         "       sync                                            \n"
148         "1:                                                     \n"
149         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
150         : "Ir" (i), "m" (v->counter)
151         : "memory");
152
153         return result;
154 }
155
156 #else
157
158 /*
159  * The MIPS I implementation is only atomic with respect to
160  * interrupts.  R3000 based multiprocessor machines are rare anyway ...
161  *
162  * atomic_add - add integer to atomic variable
163  * @i: integer value to add
164  * @v: pointer of type atomic_t
165  *
166  * Atomically adds @i to @v.
167  */
168 static __inline__ void atomic_add(int i, atomic_t * v)
169 {
170         unsigned long flags;
171
172         spin_lock_irqsave(&atomic_lock, flags);
173         v->counter += i;
174         spin_unlock_irqrestore(&atomic_lock, flags);
175 }
176
177 /*
178  * atomic_sub - subtract the atomic variable
179  * @i: integer value to subtract
180  * @v: pointer of type atomic_t
181  *
182  * Atomically subtracts @i from @v.
183  */
184 static __inline__ void atomic_sub(int i, atomic_t * v)
185 {
186         unsigned long flags;
187
188         spin_lock_irqsave(&atomic_lock, flags);
189         v->counter -= i;
190         spin_unlock_irqrestore(&atomic_lock, flags);
191 }
192
193 static __inline__ int atomic_add_return(int i, atomic_t * v)
194 {
195         unsigned long flags;
196         int temp;
197
198         spin_lock_irqsave(&atomic_lock, flags);
199         temp = v->counter;
200         temp += i;
201         v->counter = temp;
202         spin_unlock_irqrestore(&atomic_lock, flags);
203
204         return temp;
205 }
206
207 static __inline__ int atomic_sub_return(int i, atomic_t * v)
208 {
209         unsigned long flags;
210         int temp;
211
212         spin_lock_irqsave(&atomic_lock, flags);
213         temp = v->counter;
214         temp -= i;
215         v->counter = temp;
216         spin_unlock_irqrestore(&atomic_lock, flags);
217
218         return temp;
219 }
220
221 /*
222  * atomic_sub_if_positive - add integer to atomic variable
223  * @v: pointer of type atomic_t
224  *
225  * Atomically test @v and decrement if it is greater than 0.
226  * The function returns the old value of @v minus 1.
227  */
228 static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
229 {
230         unsigned long flags;
231         int temp;
232
233         spin_lock_irqsave(&atomic_lock, flags);
234         temp = v->counter;
235         temp -= i;
236         if (temp >= 0)
237                 v->counter = temp;
238         spin_unlock_irqrestore(&atomic_lock, flags);
239
240         return temp;
241 }
242
243 #endif /* CONFIG_CPU_HAS_LLSC */
244
245 #define atomic_dec_return(v) atomic_sub_return(1,(v))
246 #define atomic_inc_return(v) atomic_add_return(1,(v))
247
248 /*
249  * atomic_sub_and_test - subtract value from variable and test result
250  * @i: integer value to subtract
251  * @v: pointer of type atomic_t
252  *
253  * Atomically subtracts @i from @v and returns
254  * true if the result is zero, or false for all
255  * other cases.
256  */
257 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
258
259 /*
260  * atomic_inc_and_test - increment and test
261  * @v: pointer of type atomic_t
262  *
263  * Atomically increments @v by 1
264  * and returns true if the result is zero, or false for all
265  * other cases.
266  */
267 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
268
269 /*
270  * atomic_dec_and_test - decrement by 1 and test
271  * @v: pointer of type atomic_t
272  *
273  * Atomically decrements @v by 1 and
274  * returns true if the result is 0, or false for all other
275  * cases.
276  */
277 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
278
279 /*
280  * atomic_dec_if_positive - decrement by 1 if old value positive
281  * @v: pointer of type atomic_t
282  */
283 #define atomic_dec_if_positive(v)       atomic_sub_if_positive(1, v)
284
285 /*
286  * atomic_inc - increment atomic variable
287  * @v: pointer of type atomic_t
288  *
289  * Atomically increments @v by 1.
290  */
291 #define atomic_inc(v) atomic_add(1,(v))
292
293 /*
294  * atomic_dec - decrement and test
295  * @v: pointer of type atomic_t
296  *
297  * Atomically decrements @v by 1.
298  */
299 #define atomic_dec(v) atomic_sub(1,(v))
300
301 /*
302  * atomic_add_negative - add and test if negative
303  * @v: pointer of type atomic_t
304  * @i: integer value to add
305  *
306  * Atomically adds @i to @v and returns true
307  * if the result is negative, or false when
308  * result is greater than or equal to zero.
309  */
310 #define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
311
312 #ifdef CONFIG_MIPS64
313
314 typedef struct { volatile __s64 counter; } atomic64_t;
315
316 #define ATOMIC64_INIT(i)    { (i) }
317
318 /*
319  * atomic64_read - read atomic variable
320  * @v: pointer of type atomic64_t
321  *
322  */
323 #define atomic64_read(v)        ((v)->counter)
324
325 /*
326  * atomic64_set - set atomic variable
327  * @v: pointer of type atomic64_t
328  * @i: required value
329  */
330 #define atomic64_set(v,i)       ((v)->counter = (i))
331
332 #ifdef CONFIG_CPU_HAS_LLDSCD
333
334 /*
335  * atomic64_add - add integer to atomic variable
336  * @i: integer value to add
337  * @v: pointer of type atomic64_t
338  *
339  * Atomically adds @i to @v.
340  */
341 static __inline__ void atomic64_add(long i, atomic64_t * v)
342 {
343         unsigned long temp;
344
345         __asm__ __volatile__(
346         "1:     lld     %0, %1          # atomic64_add          \n"
347         "       addu    %0, %2                                  \n"
348         "       scd     %0, %1                                  \n"
349         "       beqz    %0, 1b                                  \n"
350         : "=&r" (temp), "=m" (v->counter)
351         : "Ir" (i), "m" (v->counter));
352 }
353
354 /*
355  * atomic64_sub - subtract the atomic variable
356  * @i: integer value to subtract
357  * @v: pointer of type atomic64_t
358  *
359  * Atomically subtracts @i from @v.
360  */
361 static __inline__ void atomic64_sub(long i, atomic64_t * v)
362 {
363         unsigned long temp;
364
365         __asm__ __volatile__(
366         "1:     lld     %0, %1          # atomic64_sub          \n"
367         "       subu    %0, %2                                  \n"
368         "       scd     %0, %1                                  \n"
369         "       beqz    %0, 1b                                  \n"
370         : "=&r" (temp), "=m" (v->counter)
371         : "Ir" (i), "m" (v->counter));
372 }
373
374 /*
375  * Same as above, but return the result value
376  */
377 static __inline__ long atomic64_add_return(long i, atomic64_t * v)
378 {
379         unsigned long temp, result;
380
381         __asm__ __volatile__(
382         "1:     lld     %1, %2          # atomic64_add_return   \n"
383         "       addu    %0, %1, %3                              \n"
384         "       scd     %0, %2                                  \n"
385         "       beqz    %0, 1b                                  \n"
386         "       addu    %0, %1, %3                              \n"
387         "       sync                                            \n"
388         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
389         : "Ir" (i), "m" (v->counter)
390         : "memory");
391
392         return result;
393 }
394
395 static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
396 {
397         unsigned long temp, result;
398
399         __asm__ __volatile__(
400         "1:     lld     %1, %2          # atomic64_sub_return   \n"
401         "       subu    %0, %1, %3                              \n"
402         "       scd     %0, %2                                  \n"
403         "       beqz    %0, 1b                                  \n"
404         "       subu    %0, %1, %3                              \n"
405         "       sync                                            \n"
406         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
407         : "Ir" (i), "m" (v->counter)
408         : "memory");
409
410         return result;
411 }
412
413 /*
414  * atomic64_sub_if_positive - add integer to atomic variable
415  * @v: pointer of type atomic64_t
416  *
417  * Atomically test @v and decrement if it is greater than 0.
418  * The function returns the old value of @v minus 1.
419  */
420 static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
421 {
422         unsigned long temp, result;
423
424         __asm__ __volatile__(
425         "1:     lld     %1, %2          # atomic64_sub_if_positive\n"
426         "       dsubu   %0, %1, %3                              \n"
427         "       bltz    %0, 1f                                  \n"
428         "       scd     %0, %2                                  \n"
429         "       beqz    %0, 1b                                  \n"
430         "       sync                                            \n"
431         "1:                                                     \n"
432         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
433         : "Ir" (i), "m" (v->counter)
434         : "memory");
435
436         return result;
437 }
438
439 #else
440
441 /*
442  * This implementation is only atomic with respect to interrupts.  It can't
443  * be used on SMP
444  *
445  * atomic64_add - add integer to atomic variable
446  * @i: integer value to add
447  * @v: pointer of type atomic64_t
448  *
449  * Atomically adds @i to @v.
450  */
451 static __inline__ void atomic64_add(long i, atomic64_t * v)
452 {
453         unsigned long flags;
454
455         spin_lock_irqsave(&atomic_lock, flags);
456         v->counter += i;
457         spin_unlock_irqrestore(&atomic_lock, flags);
458 }
459
460 /*
461  * atomic64_sub - subtract the atomic variable
462  * @i: integer value to subtract
463  * @v: pointer of type atomic64_t
464  *
465  * Atomically subtracts @i from @v.
466  */
467 static __inline__ void atomic64_sub(long i, atomic64_t * v)
468 {
469         unsigned long flags;
470
471         spin_lock_irqsave(&atomic_lock, flags);
472         v->counter -= i;
473         spin_unlock_irqrestore(&atomic_lock, flags);
474 }
475
476 static __inline__ long atomic64_add_return(long i, atomic64_t * v)
477 {
478         unsigned long flags;
479         long temp;
480
481         spin_lock_irqsave(&atomic_lock, flags);
482         temp = v->counter;
483         temp += i;
484         v->counter = temp;
485         spin_unlock_irqrestore(&atomic_lock, flags);
486
487         return temp;
488 }
489
490 static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
491 {
492         unsigned long flags;
493         long temp;
494
495         spin_lock_irqsave(&atomic_lock, flags);
496         temp = v->counter;
497         temp -= i;
498         v->counter = temp;
499         spin_unlock_irqrestore(&atomic_lock, flags);
500
501         return temp;
502 }
503
504 /*
505  * atomic64_sub_if_positive - add integer to atomic variable
506  * @v: pointer of type atomic64_t
507  *
508  * Atomically test @v and decrement if it is greater than 0.
509  * The function returns the old value of @v minus 1.
510  */
511 static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
512 {
513         unsigned long flags;
514         long temp;
515
516         spin_lock_irqsave(&atomic_lock, flags);
517         temp = v->counter;
518         temp -= i;
519         if (temp >= 0)
520                 v->counter = temp;
521         spin_unlock_irqrestore(&atomic_lock, flags);
522
523         return temp;
524 }
525
526 #endif /* CONFIG_CPU_HAS_LLDSCD */
527
528 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
529 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
530
531 /*
532  * atomic64_sub_and_test - subtract value from variable and test result
533  * @i: integer value to subtract
534  * @v: pointer of type atomic64_t
535  *
536  * Atomically subtracts @i from @v and returns
537  * true if the result is zero, or false for all
538  * other cases.
539  */
540 #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
541
542 /*
543  * atomic64_inc_and_test - increment and test
544  * @v: pointer of type atomic64_t
545  *
546  * Atomically increments @v by 1
547  * and returns true if the result is zero, or false for all
548  * other cases.
549  */
550 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
551
552 /*
553  * atomic64_dec_and_test - decrement by 1 and test
554  * @v: pointer of type atomic64_t
555  *
556  * Atomically decrements @v by 1 and
557  * returns true if the result is 0, or false for all other
558  * cases.
559  */
560 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
561
562 /*
563  * atomic64_dec_if_positive - decrement by 1 if old value positive
564  * @v: pointer of type atomic64_t
565  */
566 #define atomic64_dec_if_positive(v)     atomic64_sub_if_positive(1, v)
567
568 /*
569  * atomic64_inc - increment atomic variable
570  * @v: pointer of type atomic64_t
571  *
572  * Atomically increments @v by 1.
573  */
574 #define atomic64_inc(v) atomic64_add(1,(v))
575
576 /*
577  * atomic64_dec - decrement and test
578  * @v: pointer of type atomic64_t
579  *
580  * Atomically decrements @v by 1.
581  */
582 #define atomic64_dec(v) atomic64_sub(1,(v))
583
584 /*
585  * atomic64_add_negative - add and test if negative
586  * @v: pointer of type atomic64_t
587  * @i: integer value to add
588  *
589  * Atomically adds @i to @v and returns true
590  * if the result is negative, or false when
591  * result is greater than or equal to zero.
592  */
593 #define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
594
595 #endif /* CONFIG_MIPS64 */
596
597 /*
598  * atomic*_return operations are serializing but not the non-*_return
599  * versions.
600  */
601 #define smp_mb__before_atomic_dec()     smp_mb()
602 #define smp_mb__after_atomic_dec()      smp_mb()
603 #define smp_mb__before_atomic_inc()     smp_mb()
604 #define smp_mb__after_atomic_inc()      smp_mb()
605
606 #endif /* _ASM_ATOMIC_H */