first public release
[dpdk.git] / lib / librte_eal / common / include / x86_64 / arch / rte_atomic.h
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 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  *  version: DPDK.L.1.2.3-3
34  */
35
36 /*
37  * Inspired from FreeBSD src/sys/amd64/include/atomic.h
38  * Copyright (c) 1998 Doug Rabson
39  * All rights reserved.
40  */
41
42 #ifndef _RTE_ATOMIC_H_
43 #error "don't include this file directly, please include generic <rte_atomic.h>"
44 #endif
45
46 #ifndef _RTE_X86_64_ATOMIC_H_
47 #define _RTE_X86_64_ATOMIC_H_
48
49 /**
50  * @file
51  * Atomic Operations on x86_64
52  */
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()  asm volatile("mfence;" : : : "memory")
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() asm volatile("sfence;" : : : "memory")
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() asm volatile("lfence;" : : : "memory")
83
84 /*------------------------- 16 bit atomic operations -------------------------*/
85
86 /**
87  * Atomic compare and set.
88  *
89  * (atomic) equivalent to:
90  *   if (*dst == exp)
91  *     *dst = src (all 16-bit words)
92  *
93  * @param dst
94  *   The destination location into which the value will be written.
95  * @param exp
96  *   The expected value.
97  * @param src
98  *   The new value.
99  * @return
100  *   Non-zero on success; 0 on failure.
101  */
102 static inline int
103 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
104 {
105         uint8_t res;
106
107         asm volatile(
108                         MPLOCKED
109                         "cmpxchgw %[src], %[dst];"
110                         "sete %[res];"
111                         : [res] "=a" (res),     /* output */
112                           [dst] "=m" (*dst)
113                         : [src] "r" (src),      /* input */
114                           "a" (exp),
115                           "m" (*dst)
116                         : "memory");            /* no-clobber list */
117         return res;
118 }
119
120 /**
121  * The atomic counter structure.
122  */
123 typedef struct {
124         volatile int16_t cnt; /**< An internal counter value. */
125 } rte_atomic16_t;
126
127 /**
128  * Static initializer for an atomic counter.
129  */
130 #define RTE_ATOMIC16_INIT(val) { (val) }
131
132 /**
133  * Initialize an atomic counter.
134  *
135  * @param v
136  *   A pointer to the atomic counter.
137  */
138 static inline void
139 rte_atomic16_init(rte_atomic16_t *v)
140 {
141         v->cnt = 0;
142 }
143
144 /**
145  * Atomically read a 16-bit value from a counter.
146  *
147  * @param v
148  *   A pointer to the atomic counter.
149  * @return
150  *   The value of the counter.
151  */
152 static inline int16_t
153 rte_atomic16_read(const rte_atomic16_t *v)
154 {
155         return v->cnt;
156 }
157
158 /**
159  * Atomically set a counter to a 16-bit value.
160  *
161  * @param v
162  *   A pointer to the atomic counter.
163  * @param new_value
164  *   The new value for the counter.
165  */
166 static inline void
167 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
168 {
169         v->cnt = new_value;
170 }
171
172 /**
173  * Atomically add a 16-bit value to an atomic counter.
174  *
175  * @param v
176  *   A pointer to the atomic counter.
177  * @param inc
178  *   The value to be added to the counter.
179  */
180 static inline void
181 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
182 {
183         asm volatile(
184                         MPLOCKED
185                         "addw %[inc], %[cnt]"
186                         : [cnt] "=m" (v->cnt)   /* output */
187                         : [inc] "ir" (inc),     /* input */
188                           "m" (v->cnt)
189                         );
190 }
191
192 /**
193  * Atomically subtract a 16-bit value from an atomic counter.
194  *
195  * @param v
196  *   A pointer to the atomic counter.
197  * @param dec
198  *   The value to be subtracted from the counter.
199  */
200 static inline void
201 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
202 {
203         asm volatile(
204                         MPLOCKED
205                         "subw %[dec], %[cnt]"
206                         : [cnt] "=m" (v->cnt)   /* output */
207                         : [dec] "ir" (dec),     /* input */
208                           "m" (v->cnt)
209                         );
210 }
211
212 /**
213  * Atomically increment a counter by one.
214  *
215  * @param v
216  *   A pointer to the atomic counter.
217  */
218 static inline void
219 rte_atomic16_inc(rte_atomic16_t *v)
220 {
221         asm volatile(
222                         MPLOCKED
223                         "incw %[cnt]"
224                         : [cnt] "=m" (v->cnt)   /* output */
225                         : "m" (v->cnt)          /* input */
226                         );
227 }
228
229 /**
230  * Atomically decrement a counter by one.
231  *
232  * @param v
233  *   A pointer to the atomic counter.
234  */
235 static inline void
236 rte_atomic16_dec(rte_atomic16_t *v)
237 {
238         asm volatile(
239                         MPLOCKED
240                         "decw %[cnt]"
241                         : [cnt] "=m" (v->cnt)   /* output */
242                         : "m" (v->cnt)          /* input */
243                         );
244 }
245
246 /**
247  * Atomically add a 16-bit value to a counter and return the result.
248  *
249  * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
250  * returns the value of v after addition.
251  *
252  * @param v
253  *   A pointer to the atomic counter.
254  * @param inc
255  *   The value to be added to the counter.
256  * @return
257  *   The value of v after the addition.
258  */
259 static inline int16_t
260 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
261 {
262         int16_t prev = inc;
263
264         asm volatile(
265                         MPLOCKED
266                         "xaddw %[prev], %[cnt]"
267                         : [prev] "+r" (prev),   /* output */
268                           [cnt] "=m" (v->cnt)
269                         : "m" (v->cnt)          /* input */
270                         );
271         return (int16_t)(prev + inc);
272 }
273
274 /**
275  * Atomically subtract a 16-bit value from a counter and return
276  * the result.
277  *
278  * Atomically subtracts the 16-bit value (inc) from the atomic counter
279  * (v) and returns the value of v after the subtraction.
280  *
281  * @param v
282  *   A pointer to the atomic counter.
283  * @param dec
284  *   The value to be subtracted from the counter.
285  * @return
286  *   The value of v after the subtraction.
287  */
288 static inline int16_t
289 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
290 {
291         return rte_atomic16_add_return(v, (int16_t)-dec);
292 }
293
294 /**
295  * Atomically increment a 16-bit counter by one and test.
296  *
297  * Atomically increments the atomic counter (v) by one and returns true if
298  * the result is 0, or false in all other cases.
299  *
300  * @param v
301  *   A pointer to the atomic counter.
302  * @return
303  *   True if the result after the increment operation is 0; false otherwise.
304  */
305 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
306 {
307         uint8_t ret;
308
309         asm volatile(
310                         MPLOCKED
311                         "incw %[cnt] ; "
312                         "sete %[ret]"
313                         : [cnt] "+m" (v->cnt),  /* output */
314                           [ret] "=qm" (ret)
315                         );
316         return (ret != 0);
317 }
318
319 /**
320  * Atomically decrement a 16-bit counter by one and test.
321  *
322  * Atomically decrements the atomic counter (v) by one and returns true if
323  * the result is 0, or false in all other cases.
324  *
325  * @param v
326  *   A pointer to the atomic counter.
327  * @return
328  *   True if the result after the decrement operation is 0; false otherwise.
329  */
330 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
331 {
332         uint8_t ret;
333
334         asm volatile(MPLOCKED
335                         "decw %[cnt] ; "
336                         "sete %[ret]"
337                         : [cnt] "+m" (v->cnt),  /* output */
338                           [ret] "=qm" (ret)
339                         );
340         return (ret != 0);
341 }
342
343 /**
344  * Atomically test and set a 16-bit atomic counter.
345  *
346  * If the counter value is already set, return 0 (failed). Otherwise, set
347  * the counter value to 1 and return 1 (success).
348  *
349  * @param v
350  *   A pointer to the atomic counter.
351  * @return
352  *   0 if failed; else 1, success.
353  */
354 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
355 {
356         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
357 }
358
359 /**
360  * Atomically set a 16-bit counter to 0.
361  *
362  * @param v
363  *   A pointer to the atomic counter.
364  */
365 static inline void rte_atomic16_clear(rte_atomic16_t *v)
366 {
367         v->cnt = 0;
368 }
369
370 /*------------------------- 32 bit atomic operations -------------------------*/
371
372 /**
373  * Atomic compare and set.
374  *
375  * (atomic) equivalent to:
376  *   if (*dst == exp)
377  *     *dst = src (all 32-bit words)
378  *
379  * @param dst
380  *   The destination location into which the value will be written.
381  * @param exp
382  *   The expected value.
383  * @param src
384  *   The new value.
385  * @return
386  *   Non-zero on success; 0 on failure.
387  */
388 static inline int
389 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
390 {
391         uint8_t res;
392
393         asm volatile(
394                         MPLOCKED
395                         "cmpxchgl %[src], %[dst];"
396                         "sete %[res];"
397                         : [res] "=a" (res),     /* output */
398                           [dst] "=m" (*dst)
399                         : [src] "r" (src),      /* input */
400                           "a" (exp),
401                           "m" (*dst)
402                         : "memory");            /* no-clobber list */
403         return res;
404 }
405
406 /**
407  * The atomic counter structure.
408  */
409 typedef struct {
410         volatile int32_t cnt; /**< An internal counter value. */
411 } rte_atomic32_t;
412
413 /**
414  * Static initializer for an atomic counter.
415  */
416 #define RTE_ATOMIC32_INIT(val) { (val) }
417
418 /**
419  * Initialize an atomic counter.
420  *
421  * @param v
422  *   A pointer to the atomic counter.
423  */
424 static inline void
425 rte_atomic32_init(rte_atomic32_t *v)
426 {
427         v->cnt = 0;
428 }
429
430 /**
431  * Atomically read a 32-bit value from a counter.
432  *
433  * @param v
434  *   A pointer to the atomic counter.
435  * @return
436  *   The value of the counter.
437  */
438 static inline int32_t
439 rte_atomic32_read(const rte_atomic32_t *v)
440 {
441         return v->cnt;
442 }
443
444 /**
445  * Atomically set a counter to a 32-bit value.
446  *
447  * @param v
448  *   A pointer to the atomic counter.
449  * @param new_value
450  *   The new value for the counter.
451  */
452 static inline void
453 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
454 {
455         v->cnt = new_value;
456 }
457
458 /**
459  * Atomically add a 32-bit value to an atomic counter.
460  *
461  * @param v
462  *   A pointer to the atomic counter.
463  * @param inc
464  *   The value to be added to the counter.
465  */
466 static inline void
467 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
468 {
469         asm volatile(
470                         MPLOCKED
471                         "addl %[inc], %[cnt]"
472                         : [cnt] "=m" (v->cnt)   /* output */
473                         : [inc] "ir" (inc),     /* input */
474                           "m" (v->cnt)
475                         );
476 }
477
478 /**
479  * Atomically subtract a 32-bit value from an atomic counter.
480  *
481  * @param v
482  *   A pointer to the atomic counter.
483  * @param dec
484  *   The value to be subtracted from the counter.
485  */
486 static inline void
487 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
488 {
489         asm volatile(
490                         MPLOCKED
491                         "subl %[dec], %[cnt]"
492                         : [cnt] "=m" (v->cnt)   /* output */
493                         : [dec] "ir" (dec),     /* input */
494                           "m" (v->cnt)
495                         );
496 }
497
498 /**
499  * Atomically increment a counter by one.
500  *
501  * @param v
502  *   A pointer to the atomic counter.
503  */
504 static inline void
505 rte_atomic32_inc(rte_atomic32_t *v)
506 {
507         asm volatile(
508                         MPLOCKED
509                         "incl %[cnt]"
510                         : [cnt] "=m" (v->cnt)   /* output */
511                         : "m" (v->cnt)          /* input */
512                         );
513 }
514
515 /**
516  * Atomically decrement a counter by one.
517  *
518  * @param v
519  *   A pointer to the atomic counter.
520  */
521 static inline void
522 rte_atomic32_dec(rte_atomic32_t *v)
523 {
524         asm volatile(
525                         MPLOCKED
526                         "decl %[cnt]"
527                         : [cnt] "=m" (v->cnt)   /* output */
528                         : "m" (v->cnt)          /* input */
529                         );
530 }
531
532 /**
533  * Atomically add a 32-bit value to a counter and return the result.
534  *
535  * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
536  * returns the value of v after addition.
537  *
538  * @param v
539  *   A pointer to the atomic counter.
540  * @param inc
541  *   The value to be added to the counter.
542  * @return
543  *   The value of v after the addition.
544  */
545 static inline int32_t
546 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
547 {
548         int32_t prev = inc;
549
550         asm volatile(
551                         MPLOCKED
552                         "xaddl %[prev], %[cnt]"
553                         : [prev] "+r" (prev),   /* output */
554                           [cnt] "=m" (v->cnt)
555                         : "m" (v->cnt)          /* input */
556                         );
557         return (int32_t)(prev + inc);
558 }
559
560 /**
561  * Atomically subtract a 32-bit value from a counter and return
562  * the result.
563  *
564  * Atomically subtracts the 32-bit value (inc) from the atomic counter
565  * (v) and returns the value of v after the subtraction.
566  *
567  * @param v
568  *   A pointer to the atomic counter.
569  * @param dec
570  *   The value to be subtracted from the counter.
571  * @return
572  *   The value of v after the subtraction.
573  */
574 static inline int32_t
575 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
576 {
577         return rte_atomic32_add_return(v, -dec);
578 }
579
580 /**
581  * Atomically increment a 32-bit counter by one and test.
582  *
583  * Atomically increments the atomic counter (v) by one and returns true if
584  * the result is 0, or false in all other cases.
585  *
586  * @param v
587  *   A pointer to the atomic counter.
588  * @return
589  *   True if the result after the increment operation is 0; false otherwise.
590  */
591 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
592 {
593         uint8_t ret;
594
595         asm volatile(
596                         MPLOCKED
597                         "incl %[cnt] ; "
598                         "sete %[ret]"
599                         : [cnt] "+m" (v->cnt),  /* output */
600                           [ret] "=qm" (ret)
601                         );
602         return (ret != 0);
603 }
604
605 /**
606  * Atomically decrement a 32-bit counter by one and test.
607  *
608  * Atomically decrements the atomic counter (v) by one and returns true if
609  * the result is 0, or false in all other cases.
610  *
611  * @param v
612  *   A pointer to the atomic counter.
613  * @return
614  *   True if the result after the decrement operation is 0; false otherwise.
615  */
616 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
617 {
618         uint8_t ret;
619
620         asm volatile(MPLOCKED
621                         "decl %[cnt] ; "
622                         "sete %[ret]"
623                         : [cnt] "+m" (v->cnt),  /* output */
624                           [ret] "=qm" (ret)
625                         );
626         return (ret != 0);
627 }
628
629 /**
630  * Atomically test and set a 32-bit atomic counter.
631  *
632  * If the counter value is already set, return 0 (failed). Otherwise, set
633  * the counter value to 1 and return 1 (success).
634  *
635  * @param v
636  *   A pointer to the atomic counter.
637  * @return
638  *   0 if failed; else 1, success.
639  */
640 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
641 {
642         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
643 }
644
645 /**
646  * Atomically set a 32-bit counter to 0.
647  *
648  * @param v
649  *   A pointer to the atomic counter.
650  */
651 static inline void rte_atomic32_clear(rte_atomic32_t *v)
652 {
653         v->cnt = 0;
654 }
655
656 /*------------------------- 64 bit atomic operations -------------------------*/
657
658 /**
659  * An atomic compare and set function used by the mutex functions.
660  * (atomic) equivalent to:
661  *   if (*dst == exp)
662  *     *dst = src (all 64-bit words)
663  *
664  * @param dst
665  *   The destination into which the value will be written.
666  * @param exp
667  *   The expected value.
668  * @param src
669  *   The new value.
670  * @return
671  *   Non-zero on success; 0 on failure.
672  */
673 static inline int
674 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
675 {
676         uint8_t res;
677
678         asm volatile(
679                         MPLOCKED
680                         "cmpxchgq %[src], %[dst];"
681                         "sete %[res];"
682                         : [res] "=a" (res),     /* output */
683                           [dst] "=m" (*dst)
684                         : [src] "r" (src),      /* input */
685                           "a" (exp),
686                           "m" (*dst)
687                         : "memory");            /* no-clobber list */
688
689         return res;
690 }
691
692 /**
693  * The atomic counter structure.
694  */
695 typedef struct {
696         volatile int64_t cnt;  /**< Internal counter value. */
697 } rte_atomic64_t;
698
699 /**
700  * Static initializer for an atomic counter.
701  */
702 #define RTE_ATOMIC64_INIT(val) { (val) }
703
704 /**
705  * Initialize the atomic counter.
706  *
707  * @param v
708  *   A pointer to the atomic counter.
709  */
710 static inline void
711 rte_atomic64_init(rte_atomic64_t *v)
712 {
713         v->cnt = 0;
714 }
715
716 /**
717  * Atomically read a 64-bit counter.
718  *
719  * @param v
720  *   A pointer to the atomic counter.
721  * @return
722  *   The value of the counter.
723  */
724 static inline int64_t
725 rte_atomic64_read(rte_atomic64_t *v)
726 {
727         return v->cnt;
728 }
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         v->cnt = new_value;
742 }
743
744 /**
745  * Atomically add a 64-bit value to a counter.
746  *
747  * @param v
748  *   A pointer to the atomic counter.
749  * @param inc
750  *   The value to be added to the counter.
751  */
752 static inline void
753 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
754 {
755         asm volatile(
756                         MPLOCKED
757                         "addq %[inc], %[cnt]"
758                         : [cnt] "=m" (v->cnt)   /* output */
759                         : [inc] "ir" (inc),     /* input */
760                           "m" (v->cnt)
761                         );
762 }
763
764 /**
765  * Atomically subtract a 64-bit value from a counter.
766  *
767  * @param v
768  *   A pointer to the atomic counter.
769  * @param dec
770  *   The value to be subtracted from the counter.
771  */
772 static inline void
773 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
774 {
775         asm volatile(
776                         MPLOCKED
777                         "subq %[dec], %[cnt]"
778                         : [cnt] "=m" (v->cnt)   /* output */
779                         : [dec] "ir" (dec),     /* input */
780                           "m" (v->cnt)
781                         );
782 }
783
784 /**
785  * Atomically increment a 64-bit counter by one and test.
786  *
787  * @param v
788  *   A pointer to the atomic counter.
789  */
790 static inline void
791 rte_atomic64_inc(rte_atomic64_t *v)
792 {
793         asm volatile(
794                         MPLOCKED
795                         "incq %[cnt]"
796                         : [cnt] "=m" (v->cnt)   /* output */
797                         : "m" (v->cnt)          /* input */
798                         );
799 }
800
801 /**
802  * Atomically decrement a 64-bit counter by one and test.
803  *
804  * @param v
805  *   A pointer to the atomic counter.
806  */
807 static inline void
808 rte_atomic64_dec(rte_atomic64_t *v)
809 {
810         asm volatile(
811                         MPLOCKED
812                         "decq %[cnt]"
813                         : [cnt] "=m" (v->cnt)   /* output */
814                         : "m" (v->cnt)          /* input */
815                         );
816 }
817
818 /**
819  * Add a 64-bit value to an atomic counter and return the result.
820  *
821  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
822  * returns the value of v after the addition.
823  *
824  * @param v
825  *   A pointer to the atomic counter.
826  * @param inc
827  *   The value to be added to the counter.
828  * @return
829  *   The value of v after the addition.
830  */
831 static inline int64_t
832 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
833 {
834         int64_t prev = inc;
835
836         asm volatile(
837                         MPLOCKED
838                         "xaddq %[prev], %[cnt]"
839                         : [prev] "+r" (prev),   /* output */
840                           [cnt] "=m" (v->cnt)
841                         : "m" (v->cnt)          /* input */
842                         );
843         return prev + inc;
844 }
845
846 /**
847  * Subtract a 64-bit value from an atomic counter and return the result.
848  *
849  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
850  * and returns the value of v after the subtraction.
851  *
852  * @param v
853  *   A pointer to the atomic counter.
854  * @param dec
855  *   The value to be subtracted from the counter.
856  * @return
857  *   The value of v after the subtraction.
858  */
859 static inline int64_t
860 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
861 {
862         return rte_atomic64_add_return(v, -dec);
863 }
864
865 /**
866  * Atomically increment a 64-bit counter by one and test.
867  *
868  * Atomically increments the atomic counter (v) by one and returns
869  * true if the result is 0, or false in all other cases.
870  *
871  * @param v
872  *   A pointer to the atomic counter.
873  * @return
874  *   True if the result after the addition is 0; false otherwise.
875  */
876 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
877 {
878         uint8_t ret;
879
880         asm volatile(
881                         MPLOCKED
882                         "incq %[cnt] ; "
883                         "sete %[ret]"
884                         : [cnt] "+m" (v->cnt), /* output */
885                           [ret] "=qm" (ret)
886                         );
887
888         return ret != 0;
889 }
890
891 /**
892  * Atomically decrement a 64-bit counter by one and test.
893  *
894  * Atomically decrements the atomic counter (v) by one and returns true if
895  * the result is 0, or false in all other cases.
896  *
897  * @param v
898  *   A pointer to the atomic counter.
899  * @return
900  *   True if the result after subtraction is 0; false otherwise.
901  */
902 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
903 {
904         uint8_t ret;
905
906         asm volatile(
907                         MPLOCKED
908                         "decq %[cnt] ; "
909                         "sete %[ret]"
910                         : [cnt] "+m" (v->cnt),  /* output */
911                           [ret] "=qm" (ret)
912                         );
913         return ret != 0;
914 }
915
916 /**
917  * Atomically test and set a 64-bit atomic counter.
918  *
919  * If the counter value is already set, return 0 (failed). Otherwise, set
920  * the counter value to 1 and return 1 (success).
921  *
922  * @param v
923  *   A pointer to the atomic counter.
924  * @return
925  *   0 if failed; else 1, success.
926  */
927 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
928 {
929         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
930 }
931
932 /**
933  * Atomically set a 64-bit counter to 0.
934  *
935  * @param v
936  *   A pointer to the atomic counter.
937  */
938 static inline void rte_atomic64_clear(rte_atomic64_t *v)
939 {
940         v->cnt = 0;
941 }
942
943 #endif /* _RTE_X86_64_ATOMIC_H_ */