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