first public release
[dpdk.git] / lib / librte_eal / common / include / i686 / arch / rte_atomic.h
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  *  version: DPDK.L.1.2.3-3
34  */
35
36 /*
37  * Inspired from FreeBSD src/sys/i386/include/atomic.h
38  * Copyright (c) 1998 Doug Rabson
39  * All rights reserved.
40  */
41
42 #ifndef _RTE_ATOMIC_H_
43 #error "don't include this file directly, please include generic <rte_atomic.h>"
44 #endif
45
46 #ifndef _RTE_I686_ATOMIC_H_
47 #define _RTE_I686_ATOMIC_H_
48
49 /**
50  * @file
51  * Atomic Operations on i686
52  */
53
54 #if RTE_MAX_LCORE == 1
55 #define MPLOCKED                        /**< No need to insert MP lock prefix. */
56 #else
57 #define MPLOCKED        "lock ; "       /**< Insert MP lock prefix. */
58 #endif
59
60 /**
61  * General memory barrier.
62  *
63  * Guarantees that the LOAD and STORE operations generated before the
64  * barrier occur before the LOAD and STORE operations generated after.
65  */
66 #define rte_mb()  asm volatile(MPLOCKED "addl $0,(%%esp)" : : : "memory")
67
68 /**
69  * Write memory barrier.
70  *
71  * Guarantees that the STORE operations generated before the barrier
72  * occur before the STORE operations generated after.
73  */
74 #define rte_wmb() asm volatile(MPLOCKED "addl $0,(%%esp)" : : : "memory")
75
76 /**
77  * Read memory barrier.
78  *
79  * Guarantees that the LOAD operations generated before the barrier
80  * occur before the LOAD operations generated after.
81  */
82 #define rte_rmb() asm volatile(MPLOCKED "addl $0,(%%esp)" : : : "memory")
83
84 /*------------------------- 16 bit atomic operations -------------------------*/
85
86 /**
87  * Atomic compare and set.
88  *
89  * (atomic) equivalent to:
90  *   if (*dst == exp)
91  *     *dst = src (all 16-bit words)
92  *
93  * @param dst
94  *   The destination location into which the value will be written.
95  * @param exp
96  *   The expected value.
97  * @param src
98  *   The new value.
99  * @return
100  *   Non-zero on success; 0 on failure.
101  */
102 static inline int
103 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
104 {
105         uint8_t res;
106
107         asm volatile(
108                         MPLOCKED
109                         "cmpxchgw %[src], %[dst];"
110                         "sete %[res];"
111                         : [res] "=a" (res),     /* output */
112                           [dst] "=m" (*dst)
113                         : [src] "r" (src),      /* input */
114                           "a" (exp),
115                           "m" (*dst)
116                         : "memory");            /* no-clobber list */
117         return res;
118 }
119
120 /**
121  * The atomic counter structure.
122  */
123 typedef struct {
124         volatile int16_t cnt; /**< An internal counter value. */
125 } rte_atomic16_t;
126
127 /**
128  * Static initializer for an atomic counter.
129  */
130 #define RTE_ATOMIC16_INIT(val) { (val) }
131
132 /**
133  * Initialize an atomic counter.
134  *
135  * @param v
136  *   A pointer to the atomic counter.
137  */
138 static inline void
139 rte_atomic16_init(rte_atomic16_t *v)
140 {
141         v->cnt = 0;
142 }
143
144 /**
145  * Atomically read a 16-bit value from a counter.
146  *
147  * @param v
148  *   A pointer to the atomic counter.
149  * @return
150  *   The value of the counter.
151  */
152 static inline int16_t
153 rte_atomic16_read(const rte_atomic16_t *v)
154 {
155         return v->cnt;
156 }
157
158 /**
159  * Atomically set a counter to a 16-bit value.
160  *
161  * @param v
162  *   A pointer to the atomic counter.
163  * @param new_value
164  *   The new value for the counter.
165  */
166 static inline void
167 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
168 {
169         v->cnt = new_value;
170 }
171
172 /**
173  * Atomically add a 16-bit value to an atomic counter.
174  *
175  * @param v
176  *   A pointer to the atomic counter.
177  * @param inc
178  *   The value to be added to the counter.
179  */
180 static inline void
181 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
182 {
183         asm volatile(
184                         MPLOCKED
185                         "addw %[inc], %[cnt]"
186                         : [cnt] "=m" (v->cnt)   /* output */
187                         : [inc] "ir" (inc),     /* input */
188                           "m" (v->cnt)
189                         );
190 }
191
192 /**
193  * Atomically subtract a 16-bit value from an atomic counter.
194  *
195  * @param v
196  *   A pointer to the atomic counter.
197  * @param dec
198  *   The value to be subtracted from the counter.
199  */
200 static inline void
201 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
202 {
203         asm volatile(
204                         MPLOCKED
205                         "subw %[dec], %[cnt]"
206                         : [cnt] "=m" (v->cnt)   /* output */
207                         : [dec] "ir" (dec),     /* input */
208                           "m" (v->cnt)
209                         );
210 }
211
212 /**
213  * Atomically increment a counter by one.
214  *
215  * @param v
216  *   A pointer to the atomic counter.
217  */
218 static inline void
219 rte_atomic16_inc(rte_atomic16_t *v)
220 {
221         asm volatile(
222                         MPLOCKED
223                         "incw %[cnt]"
224                         : [cnt] "=m" (v->cnt)   /* output */
225                         : "m" (v->cnt)          /* input */
226                         );
227 }
228
229 /**
230  * Atomically decrement a counter by one.
231  *
232  * @param v
233  *   A pointer to the atomic counter.
234  */
235 static inline void
236 rte_atomic16_dec(rte_atomic16_t *v)
237 {
238         asm volatile(
239                         MPLOCKED
240                         "decw %[cnt]"
241                         : [cnt] "=m" (v->cnt)   /* output */
242                         : "m" (v->cnt)          /* input */
243                         );
244 }
245
246 /**
247  * Atomically add a 16-bit value to a counter and return the result.
248  *
249  * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
250  * returns the value of v after addition.
251  *
252  * @param v
253  *   A pointer to the atomic counter.
254  * @param inc
255  *   The value to be added to the counter.
256  * @return
257  *   The value of v after the addition.
258  */
259 static inline int16_t
260 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
261 {
262         int16_t prev = inc;
263
264         asm volatile(
265                         MPLOCKED
266                         "xaddw %[prev], %[cnt]"
267                         : [prev] "+r" (prev),   /* output */
268                           [cnt] "=m" (v->cnt)
269                         : "m" (v->cnt)          /* input */
270                         );
271         return (int16_t)(prev + inc);
272 }
273
274 /**
275  * Atomically subtract a 16-bit value from a counter and return
276  * the result.
277  *
278  * Atomically subtracts the 16-bit value (inc) from the atomic counter
279  * (v) and returns the value of v after the subtraction.
280  *
281  * @param v
282  *   A pointer to the atomic counter.
283  * @param dec
284  *   The value to be subtracted from the counter.
285  * @return
286  *   The value of v after the subtraction.
287  */
288 static inline int16_t
289 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
290 {
291         return rte_atomic16_add_return(v, (int16_t)-dec);
292 }
293
294 /**
295  * Atomically increment a 16-bit counter by one and test.
296  *
297  * Atomically increments the atomic counter (v) by one and returns true if
298  * the result is 0, or false in all other cases.
299  *
300  * @param v
301  *   A pointer to the atomic counter.
302  * @return
303  *   True if the result after the increment operation is 0; false otherwise.
304  */
305 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
306 {
307         uint8_t ret;
308
309         asm volatile(
310                         MPLOCKED
311                         "incw %[cnt] ; "
312                         "sete %[ret]"
313                         : [cnt] "+m" (v->cnt),  /* output */
314                           [ret] "=qm" (ret)
315                         );
316         return (ret != 0);
317 }
318
319 /**
320  * Atomically decrement a 16-bit counter by one and test.
321  *
322  * Atomically decrements the atomic counter (v) by one and returns true if
323  * the result is 0, or false in all other cases.
324  *
325  * @param v
326  *   A pointer to the atomic counter.
327  * @return
328  *   True if the result after the decrement operation is 0; false otherwise.
329  */
330 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
331 {
332         uint8_t ret;
333
334         asm volatile(MPLOCKED
335                         "decw %[cnt] ; "
336                         "sete %[ret]"
337                         : [cnt] "+m" (v->cnt),  /* output */
338                           [ret] "=qm" (ret)
339                         );
340         return (ret != 0);
341 }
342
343 /**
344  * Atomically test and set a 16-bit atomic counter.
345  *
346  * If the counter value is already set, return 0 (failed). Otherwise, set
347  * the counter value to 1 and return 1 (success).
348  *
349  * @param v
350  *   A pointer to the atomic counter.
351  * @return
352  *   0 if failed; else 1, success.
353  */
354 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
355 {
356         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
357 }
358
359 /**
360  * Atomically set a 16-bit counter to 0.
361  *
362  * @param v
363  *   A pointer to the atomic counter.
364  */
365 static inline void rte_atomic16_clear(rte_atomic16_t *v)
366 {
367         v->cnt = 0;
368 }
369
370 /*------------------------- 32 bit atomic operations -------------------------*/
371
372 /**
373  * Atomic compare and set.
374  *
375  * (atomic) equivalent to:
376  *   if (*dst == exp)
377  *     *dst = src (all 32-bit words)
378  *
379  * @param dst
380  *   The destination location into which the value will be written.
381  * @param exp
382  *   The expected value.
383  * @param src
384  *   The new value.
385  * @return
386  *   Non-zero on success; 0 on failure.
387  */
388 static inline int
389 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
390 {
391         uint8_t res;
392
393         asm volatile(
394                         MPLOCKED
395                         "cmpxchgl %[src], %[dst];"
396                         "sete %[res];"
397                         : [res] "=a" (res),     /* output */
398                           [dst] "=m" (*dst)
399                         : [src] "r" (src),      /* input */
400                           "a" (exp),
401                           "m" (*dst)
402                         : "memory");            /* no-clobber list */
403         return res;
404 }
405
406 /**
407  * The atomic counter structure.
408  */
409 typedef struct {
410         volatile int32_t cnt; /**< An internal counter value. */
411 } rte_atomic32_t;
412
413 /**
414  * Static initializer for an atomic counter.
415  */
416 #define RTE_ATOMIC32_INIT(val) { (val) }
417
418 /**
419  * Initialize an atomic counter.
420  *
421  * @param v
422  *   A pointer to the atomic counter.
423  */
424 static inline void
425 rte_atomic32_init(rte_atomic32_t *v)
426 {
427         v->cnt = 0;
428 }
429
430 /**
431  * Atomically read a 32-bit value from a counter.
432  *
433  * @param v
434  *   A pointer to the atomic counter.
435  * @return
436  *   The value of the counter.
437  */
438 static inline int32_t
439 rte_atomic32_read(const rte_atomic32_t *v)
440 {
441         return v->cnt;
442 }
443
444 /**
445  * Atomically set a counter to a 32-bit value.
446  *
447  * @param v
448  *   A pointer to the atomic counter.
449  * @param new_value
450  *   The new value for the counter.
451  */
452 static inline void
453 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
454 {
455         v->cnt = new_value;
456 }
457
458 /**
459  * Atomically add a 32-bit value to an atomic counter.
460  *
461  * @param v
462  *   A pointer to the atomic counter.
463  * @param inc
464  *   The value to be added to the counter.
465  */
466 static inline void
467 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
468 {
469         asm volatile(
470                         MPLOCKED
471                         "addl %[inc], %[cnt]"
472                         : [cnt] "=m" (v->cnt)   /* output */
473                         : [inc] "ir" (inc),     /* input */
474                           "m" (v->cnt)
475                         );
476 }
477
478 /**
479  * Atomically subtract a 32-bit value from an atomic counter.
480  *
481  * @param v
482  *   A pointer to the atomic counter.
483  * @param dec
484  *   The value to be subtracted from the counter.
485  */
486 static inline void
487 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
488 {
489         asm volatile(
490                         MPLOCKED
491                         "subl %[dec], %[cnt]"
492                         : [cnt] "=m" (v->cnt)   /* output */
493                         : [dec] "ir" (dec),     /* input */
494                           "m" (v->cnt)
495                         );
496 }
497
498 /**
499  * Atomically increment a counter by one.
500  *
501  * @param v
502  *   A pointer to the atomic counter.
503  */
504 static inline void
505 rte_atomic32_inc(rte_atomic32_t *v)
506 {
507         asm volatile(
508                         MPLOCKED
509                         "incl %[cnt]"
510                         : [cnt] "=m" (v->cnt)   /* output */
511                         : "m" (v->cnt)          /* input */
512                         );
513 }
514
515 /**
516  * Atomically decrement a counter by one.
517  *
518  * @param v
519  *   A pointer to the atomic counter.
520  */
521 static inline void
522 rte_atomic32_dec(rte_atomic32_t *v)
523 {
524         asm volatile(
525                         MPLOCKED
526                         "decl %[cnt]"
527                         : [cnt] "=m" (v->cnt)   /* output */
528                         : "m" (v->cnt)          /* input */
529                         );
530 }
531
532 /**
533  * Atomically add a 32-bit value to a counter and return the result.
534  *
535  * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
536  * returns the value of v after addition.
537  *
538  * @param v
539  *   A pointer to the atomic counter.
540  * @param inc
541  *   The value to be added to the counter.
542  * @return
543  *   The value of v after the addition.
544  */
545 static inline int32_t
546 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
547 {
548         int32_t prev = inc;
549
550         asm volatile(
551                         MPLOCKED
552                         "xaddl %[prev], %[cnt]"
553                         : [prev] "+r" (prev),   /* output */
554                           [cnt] "=m" (v->cnt)
555                         : "m" (v->cnt)          /* input */
556                         );
557         return (int32_t)(prev + inc);
558 }
559
560 /**
561  * Atomically subtract a 32-bit value from a counter and return
562  * the result.
563  *
564  * Atomically subtracts the 32-bit value (inc) from the atomic counter
565  * (v) and returns the value of v after the subtraction.
566  *
567  * @param v
568  *   A pointer to the atomic counter.
569  * @param dec
570  *   The value to be subtracted from the counter.
571  * @return
572  *   The value of v after the subtraction.
573  */
574 static inline int32_t
575 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
576 {
577         return rte_atomic32_add_return(v, -dec);
578 }
579
580 /**
581  * Atomically increment a 32-bit counter by one and test.
582  *
583  * Atomically increments the atomic counter (v) by one and returns true if
584  * the result is 0, or false in all other cases.
585  *
586  * @param v
587  *   A pointer to the atomic counter.
588  * @return
589  *   True if the result after the increment operation is 0; false otherwise.
590  */
591 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
592 {
593         uint8_t ret;
594
595         asm volatile(
596                         MPLOCKED
597                         "incl %[cnt] ; "
598                         "sete %[ret]"
599                         : [cnt] "+m" (v->cnt),  /* output */
600                           [ret] "=qm" (ret)
601                         );
602         return (ret != 0);
603 }
604
605 /**
606  * Atomically decrement a 32-bit counter by one and test.
607  *
608  * Atomically decrements the atomic counter (v) by one and returns true if
609  * the result is 0, or false in all other cases.
610  *
611  * @param v
612  *   A pointer to the atomic counter.
613  * @return
614  *   True if the result after the decrement operation is 0; false otherwise.
615  */
616 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
617 {
618         uint8_t ret;
619
620         asm volatile(MPLOCKED
621                         "decl %[cnt] ; "
622                         "sete %[ret]"
623                         : [cnt] "+m" (v->cnt),  /* output */
624                           [ret] "=qm" (ret)
625                         );
626         return (ret != 0);
627 }
628
629 /**
630  * Atomically test and set a 32-bit atomic counter.
631  *
632  * If the counter value is already set, return 0 (failed). Otherwise, set
633  * the counter value to 1 and return 1 (success).
634  *
635  * @param v
636  *   A pointer to the atomic counter.
637  * @return
638  *   0 if failed; else 1, success.
639  */
640 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
641 {
642         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
643 }
644
645 /**
646  * Atomically set a 32-bit counter to 0.
647  *
648  * @param v
649  *   A pointer to the atomic counter.
650  */
651 static inline void rte_atomic32_clear(rte_atomic32_t *v)
652 {
653         v->cnt = 0;
654 }
655
656 /*------------------------- 64 bit atomic operations -------------------------*/
657
658 /**
659  * An atomic compare and set function used by the mutex functions.
660  * (atomic) equivalent to:
661  *   if (*dst == exp)
662  *     *dst = src (all 64-bit words)
663  *
664  * @param dst
665  *   The destination into which the value will be written.
666  * @param exp
667  *   The expected value.
668  * @param src
669  *   The new value.
670  * @return
671  *   Non-zero on success; 0 on failure.
672  */
673 static inline int
674 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
675 {
676         uint8_t res;
677         union {
678                 struct {
679                         uint32_t l32;
680                         uint32_t h32;
681                 };
682                 uint64_t u64;
683         } _exp, _src;
684
685         _exp.u64 = exp;
686         _src.u64 = src;
687
688         asm volatile (
689                         MPLOCKED
690                         "cmpxchg8b (%[dst]);"
691                         "setz %[res];"
692                         : [res] "=a" (res)      /* result in eax */
693                         : [dst] "S" (dst),      /* esi */
694                           "b" (_src.l32),       /* ebx */
695                           "c" (_src.h32),       /* ecx */
696                           "a" (_exp.l32),       /* eax */
697                           "d" (_exp.h32)        /* edx */
698                         : "memory" );           /* no-clobber list */
699
700         return res;
701 }
702
703 /**
704  * The atomic counter structure.
705  */
706 typedef struct {
707         volatile int64_t cnt;  /**< Internal counter value. */
708 } rte_atomic64_t;
709
710 /**
711  * Static initializer for an atomic counter.
712  */
713 #define RTE_ATOMIC64_INIT(val) { (val) }
714
715 /**
716  * Initialize the atomic counter.
717  *
718  * @param v
719  *   A pointer to the atomic counter.
720  */
721 static inline void
722 rte_atomic64_init(rte_atomic64_t *v)
723 {
724         int success = 0;
725         uint64_t tmp;
726
727         while (success == 0) {
728                 tmp = v->cnt;
729                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
730                                               tmp, 0);
731         }
732 }
733
734 /**
735  * Atomically read a 64-bit counter.
736  *
737  * @param v
738  *   A pointer to the atomic counter.
739  * @return
740  *   The value of the counter.
741  */
742 static inline int64_t
743 rte_atomic64_read(rte_atomic64_t *v)
744 {
745         int success = 0;
746         uint64_t tmp;
747
748         while (success == 0) {
749                 tmp = v->cnt;
750                 /* replace the value by itself */
751                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
752                                               tmp, tmp);
753         }
754         return tmp;
755 }
756
757 /**
758  * Atomically set a 64-bit counter.
759  *
760  * @param v
761  *   A pointer to the atomic counter.
762  * @param new_value
763  *   The new value of the counter.
764  */
765 static inline void
766 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
767 {
768         int success = 0;
769         uint64_t tmp;
770
771         while (success == 0) {
772                 tmp = v->cnt;
773                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
774                                               tmp, new_value);
775         }
776 }
777
778 /**
779  * Atomically add a 64-bit value to a counter.
780  *
781  * @param v
782  *   A pointer to the atomic counter.
783  * @param inc
784  *   The value to be added to the counter.
785  */
786 static inline void
787 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
788 {
789         int success = 0;
790         uint64_t tmp;
791
792         while (success == 0) {
793                 tmp = v->cnt;
794                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
795                                               tmp, tmp + inc);
796         }
797 }
798
799 /**
800  * Atomically subtract a 64-bit value from a counter.
801  *
802  * @param v
803  *   A pointer to the atomic counter.
804  * @param dec
805  *   The value to be substracted from the counter.
806  */
807 static inline void
808 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
809 {
810         int success = 0;
811         uint64_t tmp;
812
813         while (success == 0) {
814                 tmp = v->cnt;
815                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
816                                               tmp, tmp - dec);
817         }
818 }
819
820 /**
821  * Atomically increment a 64-bit counter by one and test.
822  *
823  * @param v
824  *   A pointer to the atomic counter.
825  */
826 static inline void
827 rte_atomic64_inc(rte_atomic64_t *v)
828 {
829         rte_atomic64_add(v, 1);
830 }
831
832 /**
833  * Atomically decrement a 64-bit counter by one and test.
834  *
835  * @param v
836  *   A pointer to the atomic counter.
837  */
838 static inline void
839 rte_atomic64_dec(rte_atomic64_t *v)
840 {
841         rte_atomic64_sub(v, 1);
842 }
843
844 /**
845  * Add a 64-bit value to an atomic counter and return the result.
846  *
847  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
848  * returns the value of v after the addition.
849  *
850  * @param v
851  *   A pointer to the atomic counter.
852  * @param inc
853  *   The value to be added to the counter.
854  * @return
855  *   The value of v after the addition.
856  */
857 static inline int64_t
858 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
859 {
860         int success = 0;
861         uint64_t tmp;
862
863         while (success == 0) {
864                 tmp = v->cnt;
865                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
866                                               tmp, tmp + inc);
867         }
868
869         return tmp + inc;
870 }
871
872 /**
873  * Subtract a 64-bit value from an atomic counter and return the result.
874  *
875  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
876  * and returns the value of v after the substraction.
877  *
878  * @param v
879  *   A pointer to the atomic counter.
880  * @param dec
881  *   The value to be substracted from the counter.
882  * @return
883  *   The value of v after the substraction.
884  */
885 static inline int64_t
886 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
887 {
888         int success = 0;
889         uint64_t tmp;
890
891         while (success == 0) {
892                 tmp = v->cnt;
893                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
894                                               tmp, tmp - dec);
895         }
896
897         return tmp - dec;
898 }
899
900 /**
901  * Atomically increment a 64-bit counter by one and test.
902  *
903  * Atomically increments the atomic counter (v) by one and returns
904  * true if the result is 0, or false in all other cases.
905  *
906  * @param v
907  *   A pointer to the atomic counter.
908  * @return
909  *   True if the result after the addition is 0; false otherwise.
910  */
911 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
912 {
913         return rte_atomic64_add_return(v, 1) == 0;
914 }
915
916 /**
917  * Atomically decrement a 64-bit counter by one and test.
918  *
919  * Atomically decrements the atomic counter (v) by one and returns true if
920  * the result is 0, or false in all other cases.
921  *
922  * @param v
923  *   A pointer to the atomic counter.
924  * @return
925  *   True if the result after substraction is 0; false otherwise.
926  */
927 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
928 {
929         return rte_atomic64_sub_return(v, 1) == 0;
930 }
931
932 /**
933  * Atomically test and set a 64-bit atomic counter.
934  *
935  * If the counter value is already set, return 0 (failed). Otherwise, set
936  * the counter value to 1 and return 1 (success).
937  *
938  * @param v
939  *   A pointer to the atomic counter.
940  * @return
941  *   0 if failed; else 1, success.
942  */
943 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
944 {
945         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
946 }
947
948 /**
949  * Atomically set a 64-bit counter to 0.
950  *
951  * @param v
952  *   A pointer to the atomic counter.
953  */
954 static inline void rte_atomic64_clear(rte_atomic64_t *v)
955 {
956         rte_atomic64_set(v, 0);
957 }
958
959 #endif /* _RTE_I686_ATOMIC_H_ */