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