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