069ce4673718cee5722b30b68e2f3a2f699b82fc
[dpdk.git] / lib / librte_eal / common / include / rte_atomic.h
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2013 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  */
34
35 #ifndef _RTE_ATOMIC_H_
36 #define _RTE_ATOMIC_H_
37
38 /**
39  * @file
40  * Atomic Operations
41  *
42  * This file defines a generic API for atomic
43  * operations. The implementation is architecture-specific.
44  *
45  * See lib/librte_eal/common/include/i686/arch/rte_atomic.h
46  * See lib/librte_eal/common/include/x86_64/arch/rte_atomic.h
47  */
48
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
52
53 #include <stdint.h>
54
55 #if RTE_MAX_LCORE == 1
56 #define MPLOCKED                        /**< No need to insert MP lock prefix. */
57 #else
58 #define MPLOCKED        "lock ; "       /**< Insert MP lock prefix. */
59 #endif
60
61 /**
62  * General memory barrier.
63  *
64  * Guarantees that the LOAD and STORE operations generated before the
65  * barrier occur before the LOAD and STORE operations generated after.
66  */
67 #define rte_mb() _mm_mfence()
68
69 /**
70  * Write memory barrier.
71  *
72  * Guarantees that the STORE operations generated before the barrier
73  * occur before the STORE operations generated after.
74  */
75 #define rte_wmb() _mm_sfence()
76
77 /**
78  * Read memory barrier.
79  *
80  * Guarantees that the LOAD operations generated before the barrier
81  * occur before the LOAD operations generated after.
82  */
83 #define rte_rmb() _mm_lfence()
84
85 #include <emmintrin.h>
86
87 /**
88  * @file
89  * Atomic Operations on x86_64
90  */
91
92 /*------------------------- 16 bit atomic operations -------------------------*/
93
94 /**
95  * Atomic compare and set.
96  *
97  * (atomic) equivalent to:
98  *   if (*dst == exp)
99  *     *dst = src (all 16-bit words)
100  *
101  * @param dst
102  *   The destination location into which the value will be written.
103  * @param exp
104  *   The expected value.
105  * @param src
106  *   The new value.
107  * @return
108  *   Non-zero on success; 0 on failure.
109  */
110 static inline int
111 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
112 {
113 #ifndef RTE_FORCE_INTRINSICS
114         uint8_t res;
115
116         asm volatile(
117                         MPLOCKED
118                         "cmpxchgw %[src], %[dst];"
119                         "sete %[res];"
120                         : [res] "=a" (res),     /* output */
121                           [dst] "=m" (*dst)
122                         : [src] "r" (src),      /* input */
123                           "a" (exp),
124                           "m" (*dst)
125                         : "memory");            /* no-clobber list */
126         return res;
127 #else
128         return __sync_bool_compare_and_swap(dst, exp, src);
129 #endif
130 }
131
132 /**
133  * The atomic counter structure.
134  */
135 typedef struct {
136         volatile int16_t cnt; /**< An internal counter value. */
137 } rte_atomic16_t;
138
139 /**
140  * Static initializer for an atomic counter.
141  */
142 #define RTE_ATOMIC16_INIT(val) { (val) }
143
144 /**
145  * Initialize an atomic counter.
146  *
147  * @param v
148  *   A pointer to the atomic counter.
149  */
150 static inline void
151 rte_atomic16_init(rte_atomic16_t *v)
152 {
153         v->cnt = 0;
154 }
155
156 /**
157  * Atomically read a 16-bit value from a counter.
158  *
159  * @param v
160  *   A pointer to the atomic counter.
161  * @return
162  *   The value of the counter.
163  */
164 static inline int16_t
165 rte_atomic16_read(const rte_atomic16_t *v)
166 {
167         return v->cnt;
168 }
169
170 /**
171  * Atomically set a counter to a 16-bit value.
172  *
173  * @param v
174  *   A pointer to the atomic counter.
175  * @param new_value
176  *   The new value for the counter.
177  */
178 static inline void
179 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
180 {
181         v->cnt = new_value;
182 }
183
184 /**
185  * Atomically add a 16-bit value to an atomic counter.
186  *
187  * @param v
188  *   A pointer to the atomic counter.
189  * @param inc
190  *   The value to be added to the counter.
191  */
192 static inline void
193 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
194 {
195         __sync_fetch_and_add(&v->cnt, inc);
196 }
197
198 /**
199  * Atomically subtract a 16-bit value from an atomic counter.
200  *
201  * @param v
202  *   A pointer to the atomic counter.
203  * @param dec
204  *   The value to be subtracted from the counter.
205  */
206 static inline void
207 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
208 {
209         __sync_fetch_and_sub(&v->cnt, dec);
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 #ifndef RTE_FORCE_INTRINSICS
222         asm volatile(
223                         MPLOCKED
224                         "incw %[cnt]"
225                         : [cnt] "=m" (v->cnt)   /* output */
226                         : "m" (v->cnt)          /* input */
227                         );
228 #else
229         rte_atomic16_add(v, 1);
230 #endif
231 }
232
233 /**
234  * Atomically decrement a counter by one.
235  *
236  * @param v
237  *   A pointer to the atomic counter.
238  */
239 static inline void
240 rte_atomic16_dec(rte_atomic16_t *v)
241 {
242 #ifndef RTE_FORCE_INTRINSICS
243         asm volatile(
244                         MPLOCKED
245                         "decw %[cnt]"
246                         : [cnt] "=m" (v->cnt)   /* output */
247                         : "m" (v->cnt)          /* input */
248                         );
249 #else
250         rte_atomic16_sub(v, 1);
251 #endif
252 }
253
254 /**
255  * Atomically add a 16-bit value to a counter and return the result.
256  *
257  * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
258  * returns the value of v after addition.
259  *
260  * @param v
261  *   A pointer to the atomic counter.
262  * @param inc
263  *   The value to be added to the counter.
264  * @return
265  *   The value of v after the addition.
266  */
267 static inline int16_t
268 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
269 {
270         return __sync_add_and_fetch(&v->cnt, inc);
271 }
272
273 /**
274  * Atomically subtract a 16-bit value from a counter and return
275  * the result.
276  *
277  * Atomically subtracts the 16-bit value (inc) from the atomic counter
278  * (v) and returns the value of v after the subtraction.
279  *
280  * @param v
281  *   A pointer to the atomic counter.
282  * @param dec
283  *   The value to be subtracted from the counter.
284  * @return
285  *   The value of v after the subtraction.
286  */
287 static inline int16_t
288 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
289 {
290         return __sync_sub_and_fetch(&v->cnt, dec);
291 }
292
293 /**
294  * Atomically increment a 16-bit counter by one and test.
295  *
296  * Atomically increments the atomic counter (v) by one and returns true if
297  * the result is 0, or false in all other cases.
298  *
299  * @param v
300  *   A pointer to the atomic counter.
301  * @return
302  *   True if the result after the increment operation is 0; false otherwise.
303  */
304 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
305 {
306 #ifndef RTE_FORCE_INTRINSICS
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 #else
318         return (__sync_add_and_fetch(&v->cnt, 1) == 0);
319 #endif
320 }
321
322 /**
323  * Atomically decrement a 16-bit counter by one and test.
324  *
325  * Atomically decrements the atomic counter (v) by one and returns true if
326  * the result is 0, or false in all other cases.
327  *
328  * @param v
329  *   A pointer to the atomic counter.
330  * @return
331  *   True if the result after the decrement operation is 0; false otherwise.
332  */
333 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
334 {
335 #ifndef RTE_FORCE_INTRINSICS
336         uint8_t ret;
337
338         asm volatile(MPLOCKED
339                         "decw %[cnt] ; "
340                         "sete %[ret]"
341                         : [cnt] "+m" (v->cnt),  /* output */
342                           [ret] "=qm" (ret)
343                         );
344         return (ret != 0);
345 #else
346         return (__sync_sub_and_fetch(&v->cnt, 1) == 0);
347 #endif
348 }
349
350 /**
351  * Atomically test and set a 16-bit atomic counter.
352  *
353  * If the counter value is already set, return 0 (failed). Otherwise, set
354  * the counter value to 1 and return 1 (success).
355  *
356  * @param v
357  *   A pointer to the atomic counter.
358  * @return
359  *   0 if failed; else 1, success.
360  */
361 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
362 {
363         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
364 }
365
366 /**
367  * Atomically set a 16-bit counter to 0.
368  *
369  * @param v
370  *   A pointer to the atomic counter.
371  */
372 static inline void rte_atomic16_clear(rte_atomic16_t *v)
373 {
374         v->cnt = 0;
375 }
376
377 /*------------------------- 32 bit atomic operations -------------------------*/
378
379 /**
380  * Atomic compare and set.
381  *
382  * (atomic) equivalent to:
383  *   if (*dst == exp)
384  *     *dst = src (all 32-bit words)
385  *
386  * @param dst
387  *   The destination location into which the value will be written.
388  * @param exp
389  *   The expected value.
390  * @param src
391  *   The new value.
392  * @return
393  *   Non-zero on success; 0 on failure.
394  */
395 static inline int
396 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
397 {
398 #ifndef RTE_FORCE_INTRINSICS
399         uint8_t res;
400
401         asm volatile(
402                         MPLOCKED
403                         "cmpxchgl %[src], %[dst];"
404                         "sete %[res];"
405                         : [res] "=a" (res),     /* output */
406                           [dst] "=m" (*dst)
407                         : [src] "r" (src),      /* input */
408                           "a" (exp),
409                           "m" (*dst)
410                         : "memory");            /* no-clobber list */
411         return res;
412 #else
413         return __sync_bool_compare_and_swap(dst, exp, src);
414 #endif
415 }
416
417 /**
418  * The atomic counter structure.
419  */
420 typedef struct {
421         volatile int32_t cnt; /**< An internal counter value. */
422 } rte_atomic32_t;
423
424 /**
425  * Static initializer for an atomic counter.
426  */
427 #define RTE_ATOMIC32_INIT(val) { (val) }
428
429 /**
430  * Initialize an atomic counter.
431  *
432  * @param v
433  *   A pointer to the atomic counter.
434  */
435 static inline void
436 rte_atomic32_init(rte_atomic32_t *v)
437 {
438         v->cnt = 0;
439 }
440
441 /**
442  * Atomically read a 32-bit value from a counter.
443  *
444  * @param v
445  *   A pointer to the atomic counter.
446  * @return
447  *   The value of the counter.
448  */
449 static inline int32_t
450 rte_atomic32_read(const rte_atomic32_t *v)
451 {
452         return v->cnt;
453 }
454
455 /**
456  * Atomically set a counter to a 32-bit value.
457  *
458  * @param v
459  *   A pointer to the atomic counter.
460  * @param new_value
461  *   The new value for the counter.
462  */
463 static inline void
464 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
465 {
466         v->cnt = new_value;
467 }
468
469 /**
470  * Atomically add a 32-bit value to an atomic counter.
471  *
472  * @param v
473  *   A pointer to the atomic counter.
474  * @param inc
475  *   The value to be added to the counter.
476  */
477 static inline void
478 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
479 {
480         __sync_fetch_and_add(&v->cnt, inc);
481 }
482
483 /**
484  * Atomically subtract a 32-bit value from an atomic counter.
485  *
486  * @param v
487  *   A pointer to the atomic counter.
488  * @param dec
489  *   The value to be subtracted from the counter.
490  */
491 static inline void
492 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
493 {
494         __sync_fetch_and_sub(&v->cnt, dec);
495 }
496
497 /**
498  * Atomically increment a counter by one.
499  *
500  * @param v
501  *   A pointer to the atomic counter.
502  */
503 static inline void
504 rte_atomic32_inc(rte_atomic32_t *v)
505 {
506 #ifndef RTE_FORCE_INTRINSICS
507         asm volatile(
508                         MPLOCKED
509                         "incl %[cnt]"
510                         : [cnt] "=m" (v->cnt)   /* output */
511                         : "m" (v->cnt)          /* input */
512                         );
513 #else
514         rte_atomic32_add(v, 1);
515 #endif
516 }
517
518 /**
519  * Atomically decrement a counter by one.
520  *
521  * @param v
522  *   A pointer to the atomic counter.
523  */
524 static inline void
525 rte_atomic32_dec(rte_atomic32_t *v)
526 {
527 #ifndef RTE_FORCE_INTRINSICS
528         asm volatile(
529                         MPLOCKED
530                         "decl %[cnt]"
531                         : [cnt] "=m" (v->cnt)   /* output */
532                         : "m" (v->cnt)          /* input */
533                         );
534 #else
535         rte_atomic32_sub(v,1);
536 #endif
537 }
538
539 /**
540  * Atomically add a 32-bit value to a counter and return the result.
541  *
542  * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
543  * returns the value of v after addition.
544  *
545  * @param v
546  *   A pointer to the atomic counter.
547  * @param inc
548  *   The value to be added to the counter.
549  * @return
550  *   The value of v after the addition.
551  */
552 static inline int32_t
553 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
554 {
555         return __sync_add_and_fetch(&v->cnt, inc);
556 }
557
558 /**
559  * Atomically subtract a 32-bit value from a counter and return
560  * the result.
561  *
562  * Atomically subtracts the 32-bit value (inc) from the atomic counter
563  * (v) and returns the value of v after the subtraction.
564  *
565  * @param v
566  *   A pointer to the atomic counter.
567  * @param dec
568  *   The value to be subtracted from the counter.
569  * @return
570  *   The value of v after the subtraction.
571  */
572 static inline int32_t
573 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
574 {
575         return __sync_sub_and_fetch(&v->cnt, dec);
576 }
577
578 /**
579  * Atomically increment a 32-bit counter by one and test.
580  *
581  * Atomically increments the atomic counter (v) by one and returns true if
582  * the result is 0, or false in all other cases.
583  *
584  * @param v
585  *   A pointer to the atomic counter.
586  * @return
587  *   True if the result after the increment operation is 0; false otherwise.
588  */
589 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
590 {
591 #ifndef RTE_FORCE_INTRINSICS
592         uint8_t ret;
593
594         asm volatile(
595                         MPLOCKED
596                         "incl %[cnt] ; "
597                         "sete %[ret]"
598                         : [cnt] "+m" (v->cnt),  /* output */
599                           [ret] "=qm" (ret)
600                         );
601         return (ret != 0);
602 #else
603         return (__sync_add_and_fetch(&v->cnt, 1) == 0);
604 #endif
605 }
606
607 /**
608  * Atomically decrement a 32-bit counter by one and test.
609  *
610  * Atomically decrements the atomic counter (v) by one and returns true if
611  * the result is 0, or false in all other cases.
612  *
613  * @param v
614  *   A pointer to the atomic counter.
615  * @return
616  *   True if the result after the decrement operation is 0; false otherwise.
617  */
618 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
619 {
620 #ifndef RTE_FORCE_INTRINSICS
621         uint8_t ret;
622
623         asm volatile(MPLOCKED
624                         "decl %[cnt] ; "
625                         "sete %[ret]"
626                         : [cnt] "+m" (v->cnt),  /* output */
627                           [ret] "=qm" (ret)
628                         );
629         return (ret != 0);
630 #else
631         return (__sync_sub_and_fetch(&v->cnt, 1) == 0);
632 #endif
633 }
634
635 /**
636  * Atomically test and set a 32-bit atomic counter.
637  *
638  * If the counter value is already set, return 0 (failed). Otherwise, set
639  * the counter value to 1 and return 1 (success).
640  *
641  * @param v
642  *   A pointer to the atomic counter.
643  * @return
644  *   0 if failed; else 1, success.
645  */
646 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
647 {
648         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
649 }
650
651 /**
652  * Atomically set a 32-bit counter to 0.
653  *
654  * @param v
655  *   A pointer to the atomic counter.
656  */
657 static inline void rte_atomic32_clear(rte_atomic32_t *v)
658 {
659         v->cnt = 0;
660 }
661
662 #ifndef RTE_FORCE_INTRINSICS
663 /* any other functions are in arch specific files */
664 #include "arch/rte_atomic.h"
665
666
667 #ifdef __DOXYGEN__
668
669 /*------------------------- 64 bit atomic operations -------------------------*/
670
671 /**
672  * An atomic compare and set function used by the mutex functions.
673  * (atomic) equivalent to:
674  *   if (*dst == exp)
675  *     *dst = src (all 64-bit words)
676  *
677  * @param dst
678  *   The destination into which the value will be written.
679  * @param exp
680  *   The expected value.
681  * @param src
682  *   The new value.
683  * @return
684  *   Non-zero on success; 0 on failure.
685  */
686 static inline int
687 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src);
688
689 /**
690  * The atomic counter structure.
691  */
692 typedef struct {
693         volatile int64_t cnt;  /**< Internal counter value. */
694 } rte_atomic64_t;
695
696 /**
697  * Static initializer for an atomic counter.
698  */
699 #define RTE_ATOMIC64_INIT(val) { (val) }
700
701 /**
702  * Initialize the atomic counter.
703  *
704  * @param v
705  *   A pointer to the atomic counter.
706  */
707 static inline void
708 rte_atomic64_init(rte_atomic64_t *v);
709
710 /**
711  * Atomically read a 64-bit counter.
712  *
713  * @param v
714  *   A pointer to the atomic counter.
715  * @return
716  *   The value of the counter.
717  */
718 static inline int64_t
719 rte_atomic64_read(rte_atomic64_t *v);
720
721 /**
722  * Atomically set a 64-bit counter.
723  *
724  * @param v
725  *   A pointer to the atomic counter.
726  * @param new_value
727  *   The new value of the counter.
728  */
729 static inline void
730 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value);
731
732 /**
733  * Atomically add a 64-bit value to a counter.
734  *
735  * @param v
736  *   A pointer to the atomic counter.
737  * @param inc
738  *   The value to be added to the counter.
739  */
740 static inline void
741 rte_atomic64_add(rte_atomic64_t *v, int64_t inc);
742
743 /**
744  * Atomically subtract a 64-bit value from a counter.
745  *
746  * @param v
747  *   A pointer to the atomic counter.
748  * @param dec
749  *   The value to be subtracted from the counter.
750  */
751 static inline void
752 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec);
753
754 /**
755  * Atomically increment a 64-bit counter by one and test.
756  *
757  * @param v
758  *   A pointer to the atomic counter.
759  */
760 static inline void
761 rte_atomic64_inc(rte_atomic64_t *v);
762
763 /**
764  * Atomically decrement a 64-bit counter by one and test.
765  *
766  * @param v
767  *   A pointer to the atomic counter.
768  */
769 static inline void
770 rte_atomic64_dec(rte_atomic64_t *v);
771
772 /**
773  * Add a 64-bit value to an atomic counter and return the result.
774  *
775  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
776  * returns the value of v after the addition.
777  *
778  * @param v
779  *   A pointer to the atomic counter.
780  * @param inc
781  *   The value to be added to the counter.
782  * @return
783  *   The value of v after the addition.
784  */
785 static inline int64_t
786 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc);
787
788 /**
789  * Subtract a 64-bit value from an atomic counter and return the result.
790  *
791  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
792  * and returns the value of v after the subtraction.
793  *
794  * @param v
795  *   A pointer to the atomic counter.
796  * @param dec
797  *   The value to be subtracted from the counter.
798  * @return
799  *   The value of v after the subtraction.
800  */
801 static inline int64_t
802 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec);
803
804 /**
805  * Atomically increment a 64-bit counter by one and test.
806  *
807  * Atomically increments the atomic counter (v) by one and returns
808  * true if the result is 0, or false in all other cases.
809  *
810  * @param v
811  *   A pointer to the atomic counter.
812  * @return
813  *   True if the result after the addition is 0; false otherwise.
814  */
815 static inline int
816 rte_atomic64_inc_and_test(rte_atomic64_t *v);
817
818 /**
819  * Atomically decrement a 64-bit counter by one and test.
820  *
821  * Atomically decrements the atomic counter (v) by one and returns true if
822  * the result is 0, or false in all other cases.
823  *
824  * @param v
825  *   A pointer to the atomic counter.
826  * @return
827  *   True if the result after subtraction is 0; false otherwise.
828  */
829 static inline int
830 rte_atomic64_dec_and_test(rte_atomic64_t *v);
831
832 /**
833  * Atomically test and set a 64-bit atomic counter.
834  *
835  * If the counter value is already set, return 0 (failed). Otherwise, set
836  * the counter value to 1 and return 1 (success).
837  *
838  * @param v
839  *   A pointer to the atomic counter.
840  * @return
841  *   0 if failed; else 1, success.
842  */
843 static inline int
844 rte_atomic64_test_and_set(rte_atomic64_t *v);
845
846 /**
847  * Atomically set a 64-bit counter to 0.
848  *
849  * @param v
850  *   A pointer to the atomic counter.
851  */
852 static inline void
853 rte_atomic64_clear(rte_atomic64_t *v);
854
855 #endif /* __DOXYGEN__ */
856
857 #else /*RTE_FORCE_INTRINSICS */
858
859 /*------------------------- 64 bit atomic operations -------------------------*/
860
861 /**
862  * An atomic compare and set function used by the mutex functions.
863  * (atomic) equivalent to:
864  *   if (*dst == exp)
865  *     *dst = src (all 64-bit words)
866  *
867  * @param dst
868  *   The destination into which the value will be written.
869  * @param exp
870  *   The expected value.
871  * @param src
872  *   The new value.
873  * @return
874  *   Non-zero on success; 0 on failure.
875  */
876 static inline int
877 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
878 {
879         return __sync_bool_compare_and_swap(dst, exp, src);
880 }
881
882 /**
883  * The atomic counter structure.
884  */
885 typedef struct {
886         volatile int64_t cnt;  /**< Internal counter value. */
887 } rte_atomic64_t;
888
889 /**
890  * Static initializer for an atomic counter.
891  */
892 #define RTE_ATOMIC64_INIT(val) { (val) }
893
894 /**
895  * Initialize the atomic counter.
896  *
897  * @param v
898  *   A pointer to the atomic counter.
899  */
900 static inline void
901 rte_atomic64_init(rte_atomic64_t *v)
902 {
903 #ifdef __LP64__
904         v->cnt = 0;
905 #else
906         int success = 0;
907         uint64_t tmp;
908
909         while (success == 0) {
910                 tmp = v->cnt;
911                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
912                                               tmp, 0);
913         }
914 #endif
915 }
916
917 /**
918  * Atomically read a 64-bit counter.
919  *
920  * @param v
921  *   A pointer to the atomic counter.
922  * @return
923  *   The value of the counter.
924  */
925 static inline int64_t
926 rte_atomic64_read(rte_atomic64_t *v)
927 {
928 #ifdef __LP64__
929         return v->cnt;
930 #else
931         int success = 0;
932         uint64_t tmp;
933
934         while (success == 0) {
935                 tmp = v->cnt;
936                 /* replace the value by itself */
937                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
938                                               tmp, tmp);
939         }
940         return tmp;
941 #endif
942 }
943
944 /**
945  * Atomically set a 64-bit counter.
946  *
947  * @param v
948  *   A pointer to the atomic counter.
949  * @param new_value
950  *   The new value of the counter.
951  */
952 static inline void
953 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
954 {
955 #ifdef __LP64__
956         v->cnt = new_value;
957 #else
958         int success = 0;
959         uint64_t tmp;
960
961         while (success == 0) {
962                 tmp = v->cnt;
963                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
964                                               tmp, new_value);
965         }
966 #endif
967 }
968
969 /**
970  * Atomically add a 64-bit value to a counter.
971  *
972  * @param v
973  *   A pointer to the atomic counter.
974  * @param inc
975  *   The value to be added to the counter.
976  */
977 static inline void
978 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
979 {
980         __sync_fetch_and_add(&v->cnt, inc);
981 }
982
983 /**
984  * Atomically subtract a 64-bit value from a counter.
985  *
986  * @param v
987  *   A pointer to the atomic counter.
988  * @param dec
989  *   The value to be substracted from the counter.
990  */
991 static inline void
992 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
993 {
994         __sync_fetch_and_sub(&v->cnt, dec);
995 }
996
997 /**
998  * Atomically increment a 64-bit counter by one and test.
999  *
1000  * @param v
1001  *   A pointer to the atomic counter.
1002  */
1003 static inline void
1004 rte_atomic64_inc(rte_atomic64_t *v)
1005 {
1006         rte_atomic64_add(v, 1);
1007 }
1008
1009 /**
1010  * Atomically decrement a 64-bit counter by one and test.
1011  *
1012  * @param v
1013  *   A pointer to the atomic counter.
1014  */
1015 static inline void
1016 rte_atomic64_dec(rte_atomic64_t *v)
1017 {
1018         rte_atomic64_sub(v, 1);
1019 }
1020
1021 /**
1022  * Add a 64-bit value to an atomic counter and return the result.
1023  *
1024  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
1025  * returns the value of v after the addition.
1026  *
1027  * @param v
1028  *   A pointer to the atomic counter.
1029  * @param inc
1030  *   The value to be added to the counter.
1031  * @return
1032  *   The value of v after the addition.
1033  */
1034 static inline int64_t
1035 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
1036 {
1037         return __sync_add_and_fetch(&v->cnt, inc);
1038 }
1039
1040 /**
1041  * Subtract a 64-bit value from an atomic counter and return the result.
1042  *
1043  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
1044  * and returns the value of v after the substraction.
1045  *
1046  * @param v
1047  *   A pointer to the atomic counter.
1048  * @param dec
1049  *   The value to be substracted from the counter.
1050  * @return
1051  *   The value of v after the substraction.
1052  */
1053 static inline int64_t
1054 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
1055 {
1056         return __sync_sub_and_fetch(&v->cnt, dec);
1057 }
1058
1059 /**
1060  * Atomically increment a 64-bit counter by one and test.
1061  *
1062  * Atomically increments the atomic counter (v) by one and returns
1063  * true if the result is 0, or false in all other cases.
1064  *
1065  * @param v
1066  *   A pointer to the atomic counter.
1067  * @return
1068  *   True if the result after the addition is 0; false otherwise.
1069  */
1070 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
1071 {
1072         return rte_atomic64_add_return(v, 1) == 0;
1073 }
1074
1075 /**
1076  * Atomically decrement a 64-bit counter by one and test.
1077  *
1078  * Atomically decrements the atomic counter (v) by one and returns true if
1079  * the result is 0, or false in all other cases.
1080  *
1081  * @param v
1082  *   A pointer to the atomic counter.
1083  * @return
1084  *   True if the result after substraction is 0; false otherwise.
1085  */
1086 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
1087 {
1088         return rte_atomic64_sub_return(v, 1) == 0;
1089 }
1090
1091 /**
1092  * Atomically test and set a 64-bit atomic counter.
1093  *
1094  * If the counter value is already set, return 0 (failed). Otherwise, set
1095  * the counter value to 1 and return 1 (success).
1096  *
1097  * @param v
1098  *   A pointer to the atomic counter.
1099  * @return
1100  *   0 if failed; else 1, success.
1101  */
1102 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
1103 {
1104         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
1105 }
1106
1107 /**
1108  * Atomically set a 64-bit counter to 0.
1109  *
1110  * @param v
1111  *   A pointer to the atomic counter.
1112  */
1113 static inline void rte_atomic64_clear(rte_atomic64_t *v)
1114 {
1115         rte_atomic64_set(v, 0);
1116 }
1117
1118 #endif /*RTE_FORCE_INTRINSICS */
1119
1120 #ifdef __cplusplus
1121 }
1122 #endif
1123
1124 #endif /* _RTE_ATOMIC_H_ */