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