]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - include/asm-mips/atomic.h
2 * Atomic operations that C can't guarantee us. Useful for
3 * resource counting etc..
5 * But use these as seldom as possible since they are much more slower
6 * than regular operations.
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
12 * Copyright (C) 1996, 97, 99, 2000, 03, 04 by Ralf Baechle
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 ...
20 #include <linux/config.h>
21 #include <linux/spinlock.h>
26 #include <asm/cpu-features.h>
27 #include <asm/interrupt.h>
30 typedef struct { volatile int counter
; } atomic_t
;
32 #define ATOMIC_INIT(i) { (i) }
35 * atomic_read - read atomic variable
36 * @v: pointer of type atomic_t
38 * Atomically reads the value of @v.
40 #define atomic_read(v) ((v)->counter)
43 * atomic_set - set atomic variable
44 * @v: pointer of type atomic_t
47 * Atomically sets the value of @v to @i.
49 #define atomic_set(v,i) ((v)->counter = (i))
52 * atomic_add - add integer to atomic variable
53 * @i: integer value to add
54 * @v: pointer of type atomic_t
56 * Atomically adds @i to @v.
58 static __inline__
void atomic_add(int i
, atomic_t
* v
)
60 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
65 "1: ll %0, %1 # atomic_add \n"
70 : "=&r" (temp
), "=m" (v
->counter
)
71 : "Ir" (i
), "m" (v
->counter
));
72 } else if (cpu_has_llsc
) {
77 "1: ll %0, %1 # atomic_add \n"
82 : "=&r" (temp
), "=m" (v
->counter
)
83 : "Ir" (i
), "m" (v
->counter
));
87 local_irq_save(flags
);
89 local_irq_restore(flags
);
94 * atomic_sub - subtract the atomic variable
95 * @i: integer value to subtract
96 * @v: pointer of type atomic_t
98 * Atomically subtracts @i from @v.
100 static __inline__
void atomic_sub(int i
, atomic_t
* v
)
102 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
105 __asm__
__volatile__(
107 "1: ll %0, %1 # atomic_sub \n"
112 : "=&r" (temp
), "=m" (v
->counter
)
113 : "Ir" (i
), "m" (v
->counter
));
114 } else if (cpu_has_llsc
) {
117 __asm__
__volatile__(
119 "1: ll %0, %1 # atomic_sub \n"
124 : "=&r" (temp
), "=m" (v
->counter
)
125 : "Ir" (i
), "m" (v
->counter
));
129 local_irq_save(flags
);
131 local_irq_restore(flags
);
136 * Same as above, but return the result value
138 static __inline__
int atomic_add_return(int i
, atomic_t
* v
)
140 unsigned long result
;
142 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
145 __asm__
__volatile__(
147 "1: ll %1, %2 # atomic_add_return \n"
148 " addu %0, %1, %3 \n"
151 " addu %0, %1, %3 \n"
154 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
155 : "Ir" (i
), "m" (v
->counter
)
157 } else if (cpu_has_llsc
) {
160 __asm__
__volatile__(
162 "1: ll %1, %2 # atomic_add_return \n"
163 " addu %0, %1, %3 \n"
166 " addu %0, %1, %3 \n"
169 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
170 : "Ir" (i
), "m" (v
->counter
)
175 local_irq_save(flags
);
179 local_irq_restore(flags
);
185 static __inline__
int atomic_sub_return(int i
, atomic_t
* v
)
187 unsigned long result
;
189 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
192 __asm__
__volatile__(
194 "1: ll %1, %2 # atomic_sub_return \n"
195 " subu %0, %1, %3 \n"
198 " subu %0, %1, %3 \n"
201 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
202 : "Ir" (i
), "m" (v
->counter
)
204 } else if (cpu_has_llsc
) {
207 __asm__
__volatile__(
209 "1: ll %1, %2 # atomic_sub_return \n"
210 " subu %0, %1, %3 \n"
213 " subu %0, %1, %3 \n"
216 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
217 : "Ir" (i
), "m" (v
->counter
)
222 local_irq_save(flags
);
226 local_irq_restore(flags
);
233 * atomic_sub_if_positive - conditionally subtract integer from atomic variable
234 * @i: integer value to subtract
235 * @v: pointer of type atomic_t
237 * Atomically test @v and subtract @i if @v is greater or equal than @i.
238 * The function returns the old value of @v minus @i.
240 static __inline__
int atomic_sub_if_positive(int i
, atomic_t
* v
)
242 unsigned long result
;
244 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
247 __asm__
__volatile__(
249 "1: ll %1, %2 # atomic_sub_if_positive\n"
250 " subu %0, %1, %3 \n"
257 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
258 : "Ir" (i
), "m" (v
->counter
)
260 } else if (cpu_has_llsc
) {
263 __asm__
__volatile__(
265 "1: ll %1, %2 # atomic_sub_if_positive\n"
266 " subu %0, %1, %3 \n"
273 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
274 : "Ir" (i
), "m" (v
->counter
)
279 local_irq_save(flags
);
284 local_irq_restore(flags
);
290 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
291 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
294 * atomic_add_unless - add unless the number is a given value
295 * @v: pointer of type atomic_t
296 * @a: the amount to add to v...
297 * @u: ...unless v is equal to u.
299 * Atomically adds @a to @v, so long as it was not @u.
300 * Returns non-zero if @v was not @u, and zero otherwise.
302 #define atomic_add_unless(v, a, u) \
305 c = atomic_read(v); \
306 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
310 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
312 #define atomic_dec_return(v) atomic_sub_return(1,(v))
313 #define atomic_inc_return(v) atomic_add_return(1,(v))
316 * atomic_sub_and_test - subtract value from variable and test result
317 * @i: integer value to subtract
318 * @v: pointer of type atomic_t
320 * Atomically subtracts @i from @v and returns
321 * true if the result is zero, or false for all
324 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
327 * atomic_inc_and_test - increment and test
328 * @v: pointer of type atomic_t
330 * Atomically increments @v by 1
331 * and returns true if the result is zero, or false for all
334 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
337 * atomic_dec_and_test - decrement by 1 and test
338 * @v: pointer of type atomic_t
340 * Atomically decrements @v by 1 and
341 * returns true if the result is 0, or false for all other
344 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
347 * atomic_dec_if_positive - decrement by 1 if old value positive
348 * @v: pointer of type atomic_t
350 #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
353 * atomic_inc - increment atomic variable
354 * @v: pointer of type atomic_t
356 * Atomically increments @v by 1.
358 #define atomic_inc(v) atomic_add(1,(v))
361 * atomic_dec - decrement and test
362 * @v: pointer of type atomic_t
364 * Atomically decrements @v by 1.
366 #define atomic_dec(v) atomic_sub(1,(v))
369 * atomic_add_negative - add and test if negative
370 * @v: pointer of type atomic_t
371 * @i: integer value to add
373 * Atomically adds @i to @v and returns true
374 * if the result is negative, or false when
375 * result is greater than or equal to zero.
377 #define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
381 typedef struct { volatile __s64 counter
; } atomic64_t
;
383 #define ATOMIC64_INIT(i) { (i) }
386 * atomic64_read - read atomic variable
387 * @v: pointer of type atomic64_t
390 #define atomic64_read(v) ((v)->counter)
393 * atomic64_set - set atomic variable
394 * @v: pointer of type atomic64_t
397 #define atomic64_set(v,i) ((v)->counter = (i))
400 * atomic64_add - add integer to atomic variable
401 * @i: integer value to add
402 * @v: pointer of type atomic64_t
404 * Atomically adds @i to @v.
406 static __inline__
void atomic64_add(long i
, atomic64_t
* v
)
408 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
411 __asm__
__volatile__(
413 "1: lld %0, %1 # atomic64_add \n"
418 : "=&r" (temp
), "=m" (v
->counter
)
419 : "Ir" (i
), "m" (v
->counter
));
420 } else if (cpu_has_llsc
) {
423 __asm__
__volatile__(
425 "1: lld %0, %1 # atomic64_add \n"
430 : "=&r" (temp
), "=m" (v
->counter
)
431 : "Ir" (i
), "m" (v
->counter
));
435 local_irq_save(flags
);
437 local_irq_restore(flags
);
442 * atomic64_sub - subtract the atomic variable
443 * @i: integer value to subtract
444 * @v: pointer of type atomic64_t
446 * Atomically subtracts @i from @v.
448 static __inline__
void atomic64_sub(long i
, atomic64_t
* v
)
450 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
453 __asm__
__volatile__(
455 "1: lld %0, %1 # atomic64_sub \n"
460 : "=&r" (temp
), "=m" (v
->counter
)
461 : "Ir" (i
), "m" (v
->counter
));
462 } else if (cpu_has_llsc
) {
465 __asm__
__volatile__(
467 "1: lld %0, %1 # atomic64_sub \n"
472 : "=&r" (temp
), "=m" (v
->counter
)
473 : "Ir" (i
), "m" (v
->counter
));
477 local_irq_save(flags
);
479 local_irq_restore(flags
);
484 * Same as above, but return the result value
486 static __inline__
long atomic64_add_return(long i
, atomic64_t
* v
)
488 unsigned long result
;
490 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
493 __asm__
__volatile__(
495 "1: lld %1, %2 # atomic64_add_return \n"
496 " addu %0, %1, %3 \n"
499 " addu %0, %1, %3 \n"
502 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
503 : "Ir" (i
), "m" (v
->counter
)
505 } else if (cpu_has_llsc
) {
508 __asm__
__volatile__(
510 "1: lld %1, %2 # atomic64_add_return \n"
511 " addu %0, %1, %3 \n"
514 " addu %0, %1, %3 \n"
517 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
518 : "Ir" (i
), "m" (v
->counter
)
523 local_irq_save(flags
);
527 local_irq_restore(flags
);
533 static __inline__
long atomic64_sub_return(long i
, atomic64_t
* v
)
535 unsigned long result
;
537 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
540 __asm__
__volatile__(
542 "1: lld %1, %2 # atomic64_sub_return \n"
543 " subu %0, %1, %3 \n"
546 " subu %0, %1, %3 \n"
549 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
550 : "Ir" (i
), "m" (v
->counter
)
552 } else if (cpu_has_llsc
) {
555 __asm__
__volatile__(
557 "1: lld %1, %2 # atomic64_sub_return \n"
558 " subu %0, %1, %3 \n"
561 " subu %0, %1, %3 \n"
564 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
565 : "Ir" (i
), "m" (v
->counter
)
570 local_irq_save(flags
);
574 local_irq_restore(flags
);
581 * atomic64_sub_if_positive - conditionally subtract integer from atomic variable
582 * @i: integer value to subtract
583 * @v: pointer of type atomic64_t
585 * Atomically test @v and subtract @i if @v is greater or equal than @i.
586 * The function returns the old value of @v minus @i.
588 static __inline__
long atomic64_sub_if_positive(long i
, atomic64_t
* v
)
590 unsigned long result
;
592 if (cpu_has_llsc
&& R10000_LLSC_WAR
) {
595 __asm__
__volatile__(
597 "1: lld %1, %2 # atomic64_sub_if_positive\n"
598 " dsubu %0, %1, %3 \n"
605 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
606 : "Ir" (i
), "m" (v
->counter
)
608 } else if (cpu_has_llsc
) {
611 __asm__
__volatile__(
613 "1: lld %1, %2 # atomic64_sub_if_positive\n"
614 " dsubu %0, %1, %3 \n"
621 : "=&r" (result
), "=&r" (temp
), "=m" (v
->counter
)
622 : "Ir" (i
), "m" (v
->counter
)
627 local_irq_save(flags
);
632 local_irq_restore(flags
);
638 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
639 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
642 * atomic64_sub_and_test - subtract value from variable and test result
643 * @i: integer value to subtract
644 * @v: pointer of type atomic64_t
646 * Atomically subtracts @i from @v and returns
647 * true if the result is zero, or false for all
650 #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
653 * atomic64_inc_and_test - increment and test
654 * @v: pointer of type atomic64_t
656 * Atomically increments @v by 1
657 * and returns true if the result is zero, or false for all
660 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
663 * atomic64_dec_and_test - decrement by 1 and test
664 * @v: pointer of type atomic64_t
666 * Atomically decrements @v by 1 and
667 * returns true if the result is 0, or false for all other
670 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
673 * atomic64_dec_if_positive - decrement by 1 if old value positive
674 * @v: pointer of type atomic64_t
676 #define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v)
679 * atomic64_inc - increment atomic variable
680 * @v: pointer of type atomic64_t
682 * Atomically increments @v by 1.
684 #define atomic64_inc(v) atomic64_add(1,(v))
687 * atomic64_dec - decrement and test
688 * @v: pointer of type atomic64_t
690 * Atomically decrements @v by 1.
692 #define atomic64_dec(v) atomic64_sub(1,(v))
695 * atomic64_add_negative - add and test if negative
696 * @v: pointer of type atomic64_t
697 * @i: integer value to add
699 * Atomically adds @i to @v and returns true
700 * if the result is negative, or false when
701 * result is greater than or equal to zero.
703 #define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
705 #endif /* CONFIG_64BIT */
708 * atomic*_return operations are serializing but not the non-*_return
711 #define smp_mb__before_atomic_dec() smp_mb()
712 #define smp_mb__after_atomic_dec() smp_mb()
713 #define smp_mb__before_atomic_inc() smp_mb()
714 #define smp_mb__after_atomic_inc() smp_mb()
716 #include <asm-generic/atomic.h>
717 #endif /* _ASM_ATOMIC_H */