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