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