]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - include/asm-mips/atomic.h
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for...
[mirror_ubuntu-artful-kernel.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/spinlock.h>
21
22 #ifndef _ASM_ATOMIC_H
23 #define _ASM_ATOMIC_H
24
25 #include <linux/irqflags.h>
26 #include <asm/cpu-features.h>
27 #include <asm/war.h>
28
29 typedef struct { volatile int counter; } atomic_t;
30
31 #define ATOMIC_INIT(i) { (i) }
32
33 /*
34 * atomic_read - read atomic variable
35 * @v: pointer of type atomic_t
36 *
37 * Atomically reads the value of @v.
38 */
39 #define atomic_read(v) ((v)->counter)
40
41 /*
42 * atomic_set - set atomic variable
43 * @v: pointer of type atomic_t
44 * @i: required value
45 *
46 * Atomically sets the value of @v to @i.
47 */
48 #define atomic_set(v,i) ((v)->counter = (i))
49
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.
56 */
57 static __inline__ void atomic_add(int i, atomic_t * v)
58 {
59 if (cpu_has_llsc && R10000_LLSC_WAR) {
60 unsigned long temp;
61
62 __asm__ __volatile__(
63 " .set mips3 \n"
64 "1: ll %0, %1 # atomic_add \n"
65 " addu %0, %2 \n"
66 " sc %0, %1 \n"
67 " beqzl %0, 1b \n"
68 " .set mips0 \n"
69 : "=&r" (temp), "=m" (v->counter)
70 : "Ir" (i), "m" (v->counter));
71 } else if (cpu_has_llsc) {
72 unsigned long temp;
73
74 __asm__ __volatile__(
75 " .set mips3 \n"
76 "1: ll %0, %1 # atomic_add \n"
77 " addu %0, %2 \n"
78 " sc %0, %1 \n"
79 " beqz %0, 1b \n"
80 " .set mips0 \n"
81 : "=&r" (temp), "=m" (v->counter)
82 : "Ir" (i), "m" (v->counter));
83 } else {
84 unsigned long flags;
85
86 local_irq_save(flags);
87 v->counter += i;
88 local_irq_restore(flags);
89 }
90 }
91
92 /*
93 * atomic_sub - subtract the atomic variable
94 * @i: integer value to subtract
95 * @v: pointer of type atomic_t
96 *
97 * Atomically subtracts @i from @v.
98 */
99 static __inline__ void atomic_sub(int i, atomic_t * v)
100 {
101 if (cpu_has_llsc && R10000_LLSC_WAR) {
102 unsigned long temp;
103
104 __asm__ __volatile__(
105 " .set mips3 \n"
106 "1: ll %0, %1 # atomic_sub \n"
107 " subu %0, %2 \n"
108 " sc %0, %1 \n"
109 " beqzl %0, 1b \n"
110 " .set mips0 \n"
111 : "=&r" (temp), "=m" (v->counter)
112 : "Ir" (i), "m" (v->counter));
113 } else if (cpu_has_llsc) {
114 unsigned long temp;
115
116 __asm__ __volatile__(
117 " .set mips3 \n"
118 "1: ll %0, %1 # atomic_sub \n"
119 " subu %0, %2 \n"
120 " sc %0, %1 \n"
121 " beqz %0, 1b \n"
122 " .set mips0 \n"
123 : "=&r" (temp), "=m" (v->counter)
124 : "Ir" (i), "m" (v->counter));
125 } else {
126 unsigned long flags;
127
128 local_irq_save(flags);
129 v->counter -= i;
130 local_irq_restore(flags);
131 }
132 }
133
134 /*
135 * Same as above, but return the result value
136 */
137 static __inline__ int atomic_add_return(int i, atomic_t * v)
138 {
139 unsigned long result;
140
141 if (cpu_has_llsc && R10000_LLSC_WAR) {
142 unsigned long temp;
143
144 __asm__ __volatile__(
145 " .set mips3 \n"
146 "1: ll %1, %2 # atomic_add_return \n"
147 " addu %0, %1, %3 \n"
148 " sc %0, %2 \n"
149 " beqzl %0, 1b \n"
150 " addu %0, %1, %3 \n"
151 " sync \n"
152 " .set mips0 \n"
153 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
154 : "Ir" (i), "m" (v->counter)
155 : "memory");
156 } else if (cpu_has_llsc) {
157 unsigned long temp;
158
159 __asm__ __volatile__(
160 " .set mips3 \n"
161 "1: ll %1, %2 # atomic_add_return \n"
162 " addu %0, %1, %3 \n"
163 " sc %0, %2 \n"
164 " beqz %0, 1b \n"
165 " addu %0, %1, %3 \n"
166 " sync \n"
167 " .set mips0 \n"
168 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
169 : "Ir" (i), "m" (v->counter)
170 : "memory");
171 } else {
172 unsigned long flags;
173
174 local_irq_save(flags);
175 result = v->counter;
176 result += i;
177 v->counter = result;
178 local_irq_restore(flags);
179 }
180
181 return result;
182 }
183
184 static __inline__ int atomic_sub_return(int i, atomic_t * v)
185 {
186 unsigned long result;
187
188 if (cpu_has_llsc && R10000_LLSC_WAR) {
189 unsigned long temp;
190
191 __asm__ __volatile__(
192 " .set mips3 \n"
193 "1: ll %1, %2 # atomic_sub_return \n"
194 " subu %0, %1, %3 \n"
195 " sc %0, %2 \n"
196 " beqzl %0, 1b \n"
197 " subu %0, %1, %3 \n"
198 " sync \n"
199 " .set mips0 \n"
200 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
201 : "Ir" (i), "m" (v->counter)
202 : "memory");
203 } else if (cpu_has_llsc) {
204 unsigned long temp;
205
206 __asm__ __volatile__(
207 " .set mips3 \n"
208 "1: ll %1, %2 # atomic_sub_return \n"
209 " subu %0, %1, %3 \n"
210 " sc %0, %2 \n"
211 " beqz %0, 1b \n"
212 " subu %0, %1, %3 \n"
213 " sync \n"
214 " .set mips0 \n"
215 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
216 : "Ir" (i), "m" (v->counter)
217 : "memory");
218 } else {
219 unsigned long flags;
220
221 local_irq_save(flags);
222 result = v->counter;
223 result -= i;
224 v->counter = result;
225 local_irq_restore(flags);
226 }
227
228 return result;
229 }
230
231 /*
232 * atomic_sub_if_positive - conditionally subtract integer from atomic variable
233 * @i: integer value to subtract
234 * @v: pointer of type atomic_t
235 *
236 * Atomically test @v and subtract @i if @v is greater or equal than @i.
237 * The function returns the old value of @v minus @i.
238 */
239 static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
240 {
241 unsigned long result;
242
243 if (cpu_has_llsc && R10000_LLSC_WAR) {
244 unsigned long temp;
245
246 __asm__ __volatile__(
247 " .set mips3 \n"
248 "1: ll %1, %2 # atomic_sub_if_positive\n"
249 " subu %0, %1, %3 \n"
250 " bltz %0, 1f \n"
251 " sc %0, %2 \n"
252 " .set noreorder \n"
253 " beqzl %0, 1b \n"
254 " subu %0, %1, %3 \n"
255 " .set reorder \n"
256 " sync \n"
257 "1: \n"
258 " .set mips0 \n"
259 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
260 : "Ir" (i), "m" (v->counter)
261 : "memory");
262 } else if (cpu_has_llsc) {
263 unsigned long temp;
264
265 __asm__ __volatile__(
266 " .set mips3 \n"
267 "1: ll %1, %2 # atomic_sub_if_positive\n"
268 " subu %0, %1, %3 \n"
269 " bltz %0, 1f \n"
270 " sc %0, %2 \n"
271 " .set noreorder \n"
272 " beqz %0, 1b \n"
273 " subu %0, %1, %3 \n"
274 " .set reorder \n"
275 " sync \n"
276 "1: \n"
277 " .set mips0 \n"
278 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
279 : "Ir" (i), "m" (v->counter)
280 : "memory");
281 } else {
282 unsigned long flags;
283
284 local_irq_save(flags);
285 result = v->counter;
286 result -= i;
287 if (result >= 0)
288 v->counter = result;
289 local_irq_restore(flags);
290 }
291
292 return result;
293 }
294
295 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
296 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
297
298 /**
299 * atomic_add_unless - add unless the number is a given value
300 * @v: pointer of type atomic_t
301 * @a: the amount to add to v...
302 * @u: ...unless v is equal to u.
303 *
304 * Atomically adds @a to @v, so long as it was not @u.
305 * Returns non-zero if @v was not @u, and zero otherwise.
306 */
307 #define atomic_add_unless(v, a, u) \
308 ({ \
309 int c, old; \
310 c = atomic_read(v); \
311 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
312 c = old; \
313 c != (u); \
314 })
315 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
316
317 #define atomic_dec_return(v) atomic_sub_return(1,(v))
318 #define atomic_inc_return(v) atomic_add_return(1,(v))
319
320 /*
321 * atomic_sub_and_test - subtract value from variable and test result
322 * @i: integer value to subtract
323 * @v: pointer of type atomic_t
324 *
325 * Atomically subtracts @i from @v and returns
326 * true if the result is zero, or false for all
327 * other cases.
328 */
329 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
330
331 /*
332 * atomic_inc_and_test - increment and test
333 * @v: pointer of type atomic_t
334 *
335 * Atomically increments @v by 1
336 * and returns true if the result is zero, or false for all
337 * other cases.
338 */
339 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
340
341 /*
342 * atomic_dec_and_test - decrement by 1 and test
343 * @v: pointer of type atomic_t
344 *
345 * Atomically decrements @v by 1 and
346 * returns true if the result is 0, or false for all other
347 * cases.
348 */
349 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
350
351 /*
352 * atomic_dec_if_positive - decrement by 1 if old value positive
353 * @v: pointer of type atomic_t
354 */
355 #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
356
357 /*
358 * atomic_inc - increment atomic variable
359 * @v: pointer of type atomic_t
360 *
361 * Atomically increments @v by 1.
362 */
363 #define atomic_inc(v) atomic_add(1,(v))
364
365 /*
366 * atomic_dec - decrement and test
367 * @v: pointer of type atomic_t
368 *
369 * Atomically decrements @v by 1.
370 */
371 #define atomic_dec(v) atomic_sub(1,(v))
372
373 /*
374 * atomic_add_negative - add and test if negative
375 * @v: pointer of type atomic_t
376 * @i: integer value to add
377 *
378 * Atomically adds @i to @v and returns true
379 * if the result is negative, or false when
380 * result is greater than or equal to zero.
381 */
382 #define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
383
384 #ifdef CONFIG_64BIT
385
386 typedef struct { volatile __s64 counter; } atomic64_t;
387
388 #define ATOMIC64_INIT(i) { (i) }
389
390 /*
391 * atomic64_read - read atomic variable
392 * @v: pointer of type atomic64_t
393 *
394 */
395 #define atomic64_read(v) ((v)->counter)
396
397 /*
398 * atomic64_set - set atomic variable
399 * @v: pointer of type atomic64_t
400 * @i: required value
401 */
402 #define atomic64_set(v,i) ((v)->counter = (i))
403
404 /*
405 * atomic64_add - add integer to atomic variable
406 * @i: integer value to add
407 * @v: pointer of type atomic64_t
408 *
409 * Atomically adds @i to @v.
410 */
411 static __inline__ void atomic64_add(long i, atomic64_t * v)
412 {
413 if (cpu_has_llsc && R10000_LLSC_WAR) {
414 unsigned long temp;
415
416 __asm__ __volatile__(
417 " .set mips3 \n"
418 "1: lld %0, %1 # atomic64_add \n"
419 " addu %0, %2 \n"
420 " scd %0, %1 \n"
421 " beqzl %0, 1b \n"
422 " .set mips0 \n"
423 : "=&r" (temp), "=m" (v->counter)
424 : "Ir" (i), "m" (v->counter));
425 } else if (cpu_has_llsc) {
426 unsigned long temp;
427
428 __asm__ __volatile__(
429 " .set mips3 \n"
430 "1: lld %0, %1 # atomic64_add \n"
431 " addu %0, %2 \n"
432 " scd %0, %1 \n"
433 " beqz %0, 1b \n"
434 " .set mips0 \n"
435 : "=&r" (temp), "=m" (v->counter)
436 : "Ir" (i), "m" (v->counter));
437 } else {
438 unsigned long flags;
439
440 local_irq_save(flags);
441 v->counter += i;
442 local_irq_restore(flags);
443 }
444 }
445
446 /*
447 * atomic64_sub - subtract the atomic variable
448 * @i: integer value to subtract
449 * @v: pointer of type atomic64_t
450 *
451 * Atomically subtracts @i from @v.
452 */
453 static __inline__ void atomic64_sub(long i, atomic64_t * v)
454 {
455 if (cpu_has_llsc && R10000_LLSC_WAR) {
456 unsigned long temp;
457
458 __asm__ __volatile__(
459 " .set mips3 \n"
460 "1: lld %0, %1 # atomic64_sub \n"
461 " subu %0, %2 \n"
462 " scd %0, %1 \n"
463 " beqzl %0, 1b \n"
464 " .set mips0 \n"
465 : "=&r" (temp), "=m" (v->counter)
466 : "Ir" (i), "m" (v->counter));
467 } else if (cpu_has_llsc) {
468 unsigned long temp;
469
470 __asm__ __volatile__(
471 " .set mips3 \n"
472 "1: lld %0, %1 # atomic64_sub \n"
473 " subu %0, %2 \n"
474 " scd %0, %1 \n"
475 " beqz %0, 1b \n"
476 " .set mips0 \n"
477 : "=&r" (temp), "=m" (v->counter)
478 : "Ir" (i), "m" (v->counter));
479 } else {
480 unsigned long flags;
481
482 local_irq_save(flags);
483 v->counter -= i;
484 local_irq_restore(flags);
485 }
486 }
487
488 /*
489 * Same as above, but return the result value
490 */
491 static __inline__ long atomic64_add_return(long i, atomic64_t * v)
492 {
493 unsigned long result;
494
495 if (cpu_has_llsc && R10000_LLSC_WAR) {
496 unsigned long temp;
497
498 __asm__ __volatile__(
499 " .set mips3 \n"
500 "1: lld %1, %2 # atomic64_add_return \n"
501 " addu %0, %1, %3 \n"
502 " scd %0, %2 \n"
503 " beqzl %0, 1b \n"
504 " addu %0, %1, %3 \n"
505 " sync \n"
506 " .set mips0 \n"
507 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
508 : "Ir" (i), "m" (v->counter)
509 : "memory");
510 } else if (cpu_has_llsc) {
511 unsigned long temp;
512
513 __asm__ __volatile__(
514 " .set mips3 \n"
515 "1: lld %1, %2 # atomic64_add_return \n"
516 " addu %0, %1, %3 \n"
517 " scd %0, %2 \n"
518 " beqz %0, 1b \n"
519 " addu %0, %1, %3 \n"
520 " sync \n"
521 " .set mips0 \n"
522 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
523 : "Ir" (i), "m" (v->counter)
524 : "memory");
525 } else {
526 unsigned long flags;
527
528 local_irq_save(flags);
529 result = v->counter;
530 result += i;
531 v->counter = result;
532 local_irq_restore(flags);
533 }
534
535 return result;
536 }
537
538 static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
539 {
540 unsigned long result;
541
542 if (cpu_has_llsc && R10000_LLSC_WAR) {
543 unsigned long temp;
544
545 __asm__ __volatile__(
546 " .set mips3 \n"
547 "1: lld %1, %2 # atomic64_sub_return \n"
548 " subu %0, %1, %3 \n"
549 " scd %0, %2 \n"
550 " beqzl %0, 1b \n"
551 " subu %0, %1, %3 \n"
552 " sync \n"
553 " .set mips0 \n"
554 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
555 : "Ir" (i), "m" (v->counter)
556 : "memory");
557 } else if (cpu_has_llsc) {
558 unsigned long temp;
559
560 __asm__ __volatile__(
561 " .set mips3 \n"
562 "1: lld %1, %2 # atomic64_sub_return \n"
563 " subu %0, %1, %3 \n"
564 " scd %0, %2 \n"
565 " beqz %0, 1b \n"
566 " subu %0, %1, %3 \n"
567 " sync \n"
568 " .set mips0 \n"
569 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
570 : "Ir" (i), "m" (v->counter)
571 : "memory");
572 } else {
573 unsigned long flags;
574
575 local_irq_save(flags);
576 result = v->counter;
577 result -= i;
578 v->counter = result;
579 local_irq_restore(flags);
580 }
581
582 return result;
583 }
584
585 /*
586 * atomic64_sub_if_positive - conditionally subtract integer from atomic variable
587 * @i: integer value to subtract
588 * @v: pointer of type atomic64_t
589 *
590 * Atomically test @v and subtract @i if @v is greater or equal than @i.
591 * The function returns the old value of @v minus @i.
592 */
593 static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
594 {
595 unsigned long result;
596
597 if (cpu_has_llsc && R10000_LLSC_WAR) {
598 unsigned long temp;
599
600 __asm__ __volatile__(
601 " .set mips3 \n"
602 "1: lld %1, %2 # atomic64_sub_if_positive\n"
603 " dsubu %0, %1, %3 \n"
604 " bltz %0, 1f \n"
605 " scd %0, %2 \n"
606 " .set noreorder \n"
607 " beqzl %0, 1b \n"
608 " dsubu %0, %1, %3 \n"
609 " .set reorder \n"
610 " sync \n"
611 "1: \n"
612 " .set mips0 \n"
613 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
614 : "Ir" (i), "m" (v->counter)
615 : "memory");
616 } else if (cpu_has_llsc) {
617 unsigned long temp;
618
619 __asm__ __volatile__(
620 " .set mips3 \n"
621 "1: lld %1, %2 # atomic64_sub_if_positive\n"
622 " dsubu %0, %1, %3 \n"
623 " bltz %0, 1f \n"
624 " scd %0, %2 \n"
625 " .set noreorder \n"
626 " beqz %0, 1b \n"
627 " dsubu %0, %1, %3 \n"
628 " .set reorder \n"
629 " sync \n"
630 "1: \n"
631 " .set mips0 \n"
632 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
633 : "Ir" (i), "m" (v->counter)
634 : "memory");
635 } else {
636 unsigned long flags;
637
638 local_irq_save(flags);
639 result = v->counter;
640 result -= i;
641 if (result >= 0)
642 v->counter = result;
643 local_irq_restore(flags);
644 }
645
646 return result;
647 }
648
649 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
650 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
651
652 /*
653 * atomic64_sub_and_test - subtract value from variable and test result
654 * @i: integer value to subtract
655 * @v: pointer of type atomic64_t
656 *
657 * Atomically subtracts @i from @v and returns
658 * true if the result is zero, or false for all
659 * other cases.
660 */
661 #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
662
663 /*
664 * atomic64_inc_and_test - increment and test
665 * @v: pointer of type atomic64_t
666 *
667 * Atomically increments @v by 1
668 * and returns true if the result is zero, or false for all
669 * other cases.
670 */
671 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
672
673 /*
674 * atomic64_dec_and_test - decrement by 1 and test
675 * @v: pointer of type atomic64_t
676 *
677 * Atomically decrements @v by 1 and
678 * returns true if the result is 0, or false for all other
679 * cases.
680 */
681 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
682
683 /*
684 * atomic64_dec_if_positive - decrement by 1 if old value positive
685 * @v: pointer of type atomic64_t
686 */
687 #define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v)
688
689 /*
690 * atomic64_inc - increment atomic variable
691 * @v: pointer of type atomic64_t
692 *
693 * Atomically increments @v by 1.
694 */
695 #define atomic64_inc(v) atomic64_add(1,(v))
696
697 /*
698 * atomic64_dec - decrement and test
699 * @v: pointer of type atomic64_t
700 *
701 * Atomically decrements @v by 1.
702 */
703 #define atomic64_dec(v) atomic64_sub(1,(v))
704
705 /*
706 * atomic64_add_negative - add and test if negative
707 * @v: pointer of type atomic64_t
708 * @i: integer value to add
709 *
710 * Atomically adds @i to @v and returns true
711 * if the result is negative, or false when
712 * result is greater than or equal to zero.
713 */
714 #define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
715
716 #endif /* CONFIG_64BIT */
717
718 /*
719 * atomic*_return operations are serializing but not the non-*_return
720 * versions.
721 */
722 #define smp_mb__before_atomic_dec() smp_mb()
723 #define smp_mb__after_atomic_dec() smp_mb()
724 #define smp_mb__before_atomic_inc() smp_mb()
725 #define smp_mb__after_atomic_inc() smp_mb()
726
727 #include <asm-generic/atomic.h>
728 #endif /* _ASM_ATOMIC_H */