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