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