doc: whitespace changes in licenses
[dpdk.git] / lib / librte_eal / common / include / x86_64 / arch / 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  * Inspired from FreeBSD src/sys/amd64/include/atomic.h
36  * Copyright (c) 1998 Doug Rabson
37  * All rights reserved.
38  */
39
40 #ifndef _RTE_ATOMIC_H_
41 #error "don't include this file directly, please include generic <rte_atomic.h>"
42 #endif
43
44 #ifndef _RTE_X86_64_ATOMIC_H_
45 #define _RTE_X86_64_ATOMIC_H_
46
47
48 /*------------------------- 64 bit atomic operations -------------------------*/
49
50 /**
51  * An atomic compare and set function used by the mutex functions.
52  * (atomic) equivalent to:
53  *   if (*dst == exp)
54  *     *dst = src (all 64-bit words)
55  *
56  * @param dst
57  *   The destination into which the value will be written.
58  * @param exp
59  *   The expected value.
60  * @param src
61  *   The new value.
62  * @return
63  *   Non-zero on success; 0 on failure.
64  */
65 static inline int
66 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
67 {
68         uint8_t res;
69
70         asm volatile(
71                         MPLOCKED
72                         "cmpxchgq %[src], %[dst];"
73                         "sete %[res];"
74                         : [res] "=a" (res),     /* output */
75                           [dst] "=m" (*dst)
76                         : [src] "r" (src),      /* input */
77                           "a" (exp),
78                           "m" (*dst)
79                         : "memory");            /* no-clobber list */
80
81         return res;
82 }
83
84 /**
85  * The atomic counter structure.
86  */
87 typedef struct {
88         volatile int64_t cnt;  /**< Internal counter value. */
89 } rte_atomic64_t;
90
91 /**
92  * Static initializer for an atomic counter.
93  */
94 #define RTE_ATOMIC64_INIT(val) { (val) }
95
96 /**
97  * Initialize the atomic counter.
98  *
99  * @param v
100  *   A pointer to the atomic counter.
101  */
102 static inline void
103 rte_atomic64_init(rte_atomic64_t *v)
104 {
105         v->cnt = 0;
106 }
107
108 /**
109  * Atomically read a 64-bit counter.
110  *
111  * @param v
112  *   A pointer to the atomic counter.
113  * @return
114  *   The value of the counter.
115  */
116 static inline int64_t
117 rte_atomic64_read(rte_atomic64_t *v)
118 {
119         return v->cnt;
120 }
121
122 /**
123  * Atomically set a 64-bit counter.
124  *
125  * @param v
126  *   A pointer to the atomic counter.
127  * @param new_value
128  *   The new value of the counter.
129  */
130 static inline void
131 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
132 {
133         v->cnt = new_value;
134 }
135
136 /**
137  * Atomically add a 64-bit value to a counter.
138  *
139  * @param v
140  *   A pointer to the atomic counter.
141  * @param inc
142  *   The value to be added to the counter.
143  */
144 static inline void
145 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
146 {
147         asm volatile(
148                         MPLOCKED
149                         "addq %[inc], %[cnt]"
150                         : [cnt] "=m" (v->cnt)   /* output */
151                         : [inc] "ir" (inc),     /* input */
152                           "m" (v->cnt)
153                         );
154 }
155
156 /**
157  * Atomically subtract a 64-bit value from a counter.
158  *
159  * @param v
160  *   A pointer to the atomic counter.
161  * @param dec
162  *   The value to be subtracted from the counter.
163  */
164 static inline void
165 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
166 {
167         asm volatile(
168                         MPLOCKED
169                         "subq %[dec], %[cnt]"
170                         : [cnt] "=m" (v->cnt)   /* output */
171                         : [dec] "ir" (dec),     /* input */
172                           "m" (v->cnt)
173                         );
174 }
175
176 /**
177  * Atomically increment a 64-bit counter by one and test.
178  *
179  * @param v
180  *   A pointer to the atomic counter.
181  */
182 static inline void
183 rte_atomic64_inc(rte_atomic64_t *v)
184 {
185         asm volatile(
186                         MPLOCKED
187                         "incq %[cnt]"
188                         : [cnt] "=m" (v->cnt)   /* output */
189                         : "m" (v->cnt)          /* input */
190                         );
191 }
192
193 /**
194  * Atomically decrement a 64-bit counter by one and test.
195  *
196  * @param v
197  *   A pointer to the atomic counter.
198  */
199 static inline void
200 rte_atomic64_dec(rte_atomic64_t *v)
201 {
202         asm volatile(
203                         MPLOCKED
204                         "decq %[cnt]"
205                         : [cnt] "=m" (v->cnt)   /* output */
206                         : "m" (v->cnt)          /* input */
207                         );
208 }
209
210 /**
211  * Add a 64-bit value to an atomic counter and return the result.
212  *
213  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
214  * returns the value of v after the addition.
215  *
216  * @param v
217  *   A pointer to the atomic counter.
218  * @param inc
219  *   The value to be added to the counter.
220  * @return
221  *   The value of v after the addition.
222  */
223 static inline int64_t
224 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
225 {
226         int64_t prev = inc;
227
228         asm volatile(
229                         MPLOCKED
230                         "xaddq %[prev], %[cnt]"
231                         : [prev] "+r" (prev),   /* output */
232                           [cnt] "=m" (v->cnt)
233                         : "m" (v->cnt)          /* input */
234                         );
235         return prev + inc;
236 }
237
238 /**
239  * Subtract a 64-bit value from an atomic counter and return the result.
240  *
241  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
242  * and returns the value of v after the subtraction.
243  *
244  * @param v
245  *   A pointer to the atomic counter.
246  * @param dec
247  *   The value to be subtracted from the counter.
248  * @return
249  *   The value of v after the subtraction.
250  */
251 static inline int64_t
252 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
253 {
254         return rte_atomic64_add_return(v, -dec);
255 }
256
257 /**
258  * Atomically increment a 64-bit counter by one and test.
259  *
260  * Atomically increments the atomic counter (v) by one and returns
261  * true if the result is 0, or false in all other cases.
262  *
263  * @param v
264  *   A pointer to the atomic counter.
265  * @return
266  *   True if the result after the addition is 0; false otherwise.
267  */
268 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
269 {
270         uint8_t ret;
271
272         asm volatile(
273                         MPLOCKED
274                         "incq %[cnt] ; "
275                         "sete %[ret]"
276                         : [cnt] "+m" (v->cnt), /* output */
277                           [ret] "=qm" (ret)
278                         );
279
280         return ret != 0;
281 }
282
283 /**
284  * Atomically decrement a 64-bit counter by one and test.
285  *
286  * Atomically decrements the atomic counter (v) by one and returns true if
287  * the result is 0, or false in all other cases.
288  *
289  * @param v
290  *   A pointer to the atomic counter.
291  * @return
292  *   True if the result after subtraction is 0; false otherwise.
293  */
294 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
295 {
296         uint8_t ret;
297
298         asm volatile(
299                         MPLOCKED
300                         "decq %[cnt] ; "
301                         "sete %[ret]"
302                         : [cnt] "+m" (v->cnt),  /* output */
303                           [ret] "=qm" (ret)
304                         );
305         return ret != 0;
306 }
307
308 /**
309  * Atomically test and set a 64-bit atomic counter.
310  *
311  * If the counter value is already set, return 0 (failed). Otherwise, set
312  * the counter value to 1 and return 1 (success).
313  *
314  * @param v
315  *   A pointer to the atomic counter.
316  * @return
317  *   0 if failed; else 1, success.
318  */
319 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
320 {
321         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
322 }
323
324 /**
325  * Atomically set a 64-bit counter to 0.
326  *
327  * @param v
328  *   A pointer to the atomic counter.
329  */
330 static inline void rte_atomic64_clear(rte_atomic64_t *v)
331 {
332         v->cnt = 0;
333 }
334
335 #endif /* _RTE_X86_64_ATOMIC_H_ */