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