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
23typedef 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 */
51static __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 */
96static __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 */
137static __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
189static __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 */
249static __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 */
322static __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
407typedef 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 */
432static __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 */
477static __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 */
518static __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
570static __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 */
630static __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 */
704static __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