eal: install all arch headers
[dpdk.git] / lib / librte_eal / common / include / arch / i686 / rte_atomic.h
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 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_I686_H_
41 #define _RTE_ATOMIC_I686_H_
42
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46
47 #include <emmintrin.h>
48 #include "generic/rte_atomic.h"
49
50 #if RTE_MAX_LCORE == 1
51 #define MPLOCKED                        /**< No need to insert MP lock prefix. */
52 #else
53 #define MPLOCKED        "lock ; "       /**< Insert MP lock prefix. */
54 #endif
55
56 #define rte_mb() _mm_mfence()
57
58 #define rte_wmb() _mm_sfence()
59
60 #define rte_rmb() _mm_lfence()
61
62 /*------------------------- 16 bit atomic operations -------------------------*/
63
64 #ifndef RTE_FORCE_INTRINSICS
65 static inline int
66 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
67 {
68         uint8_t res;
69
70         asm volatile(
71                         MPLOCKED
72                         "cmpxchgw %[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         return res;
81 }
82
83 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
84 {
85         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
86 }
87
88 static inline void
89 rte_atomic16_inc(rte_atomic16_t *v)
90 {
91         asm volatile(
92                         MPLOCKED
93                         "incw %[cnt]"
94                         : [cnt] "=m" (v->cnt)   /* output */
95                         : "m" (v->cnt)          /* input */
96                         );
97 }
98
99 static inline void
100 rte_atomic16_dec(rte_atomic16_t *v)
101 {
102         asm volatile(
103                         MPLOCKED
104                         "decw %[cnt]"
105                         : [cnt] "=m" (v->cnt)   /* output */
106                         : "m" (v->cnt)          /* input */
107                         );
108 }
109
110 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
111 {
112         uint8_t ret;
113
114         asm volatile(
115                         MPLOCKED
116                         "incw %[cnt] ; "
117                         "sete %[ret]"
118                         : [cnt] "+m" (v->cnt),  /* output */
119                           [ret] "=qm" (ret)
120                         );
121         return (ret != 0);
122 }
123
124 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
125 {
126         uint8_t ret;
127
128         asm volatile(MPLOCKED
129                         "decw %[cnt] ; "
130                         "sete %[ret]"
131                         : [cnt] "+m" (v->cnt),  /* output */
132                           [ret] "=qm" (ret)
133                         );
134         return (ret != 0);
135 }
136
137 /*------------------------- 32 bit atomic operations -------------------------*/
138
139 static inline int
140 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
141 {
142         uint8_t res;
143
144         asm volatile(
145                         MPLOCKED
146                         "cmpxchgl %[src], %[dst];"
147                         "sete %[res];"
148                         : [res] "=a" (res),     /* output */
149                           [dst] "=m" (*dst)
150                         : [src] "r" (src),      /* input */
151                           "a" (exp),
152                           "m" (*dst)
153                         : "memory");            /* no-clobber list */
154         return res;
155 }
156
157 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
158 {
159         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
160 }
161
162 static inline void
163 rte_atomic32_inc(rte_atomic32_t *v)
164 {
165         asm volatile(
166                         MPLOCKED
167                         "incl %[cnt]"
168                         : [cnt] "=m" (v->cnt)   /* output */
169                         : "m" (v->cnt)          /* input */
170                         );
171 }
172
173 static inline void
174 rte_atomic32_dec(rte_atomic32_t *v)
175 {
176         asm volatile(
177                         MPLOCKED
178                         "decl %[cnt]"
179                         : [cnt] "=m" (v->cnt)   /* output */
180                         : "m" (v->cnt)          /* input */
181                         );
182 }
183
184 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
185 {
186         uint8_t ret;
187
188         asm volatile(
189                         MPLOCKED
190                         "incl %[cnt] ; "
191                         "sete %[ret]"
192                         : [cnt] "+m" (v->cnt),  /* output */
193                           [ret] "=qm" (ret)
194                         );
195         return (ret != 0);
196 }
197
198 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
199 {
200         uint8_t ret;
201
202         asm volatile(MPLOCKED
203                         "decl %[cnt] ; "
204                         "sete %[ret]"
205                         : [cnt] "+m" (v->cnt),  /* output */
206                           [ret] "=qm" (ret)
207                         );
208         return (ret != 0);
209 }
210
211 /*------------------------- 64 bit atomic operations -------------------------*/
212
213 static inline int
214 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
215 {
216         uint8_t res;
217         union {
218                 struct {
219                         uint32_t l32;
220                         uint32_t h32;
221                 };
222                 uint64_t u64;
223         } _exp, _src;
224
225         _exp.u64 = exp;
226         _src.u64 = src;
227
228 #ifndef __PIC__
229     asm volatile (
230             MPLOCKED
231             "cmpxchg8b (%[dst]);"
232             "setz %[res];"
233             : [res] "=a" (res)      /* result in eax */
234             : [dst] "S" (dst),      /* esi */
235              "b" (_src.l32),       /* ebx */
236              "c" (_src.h32),       /* ecx */
237              "a" (_exp.l32),       /* eax */
238              "d" (_exp.h32)        /* edx */
239                         : "memory" );           /* no-clobber list */
240 #else
241         asm volatile (
242             "mov %%ebx, %%edi\n"
243                         MPLOCKED
244                         "cmpxchg8b (%[dst]);"
245                         "setz %[res];"
246             "xchgl %%ebx, %%edi;\n"
247                         : [res] "=a" (res)      /* result in eax */
248                         : [dst] "S" (dst),      /* esi */
249                           "D" (_src.l32),       /* ebx */
250                           "c" (_src.h32),       /* ecx */
251                           "a" (_exp.l32),       /* eax */
252                           "d" (_exp.h32)        /* edx */
253                         : "memory" );           /* no-clobber list */
254 #endif
255
256         return res;
257 }
258
259 static inline void
260 rte_atomic64_init(rte_atomic64_t *v)
261 {
262         int success = 0;
263         uint64_t tmp;
264
265         while (success == 0) {
266                 tmp = v->cnt;
267                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
268                                               tmp, 0);
269         }
270 }
271
272 static inline int64_t
273 rte_atomic64_read(rte_atomic64_t *v)
274 {
275         int success = 0;
276         uint64_t tmp;
277
278         while (success == 0) {
279                 tmp = v->cnt;
280                 /* replace the value by itself */
281                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
282                                               tmp, tmp);
283         }
284         return tmp;
285 }
286
287 static inline void
288 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
289 {
290         int success = 0;
291         uint64_t tmp;
292
293         while (success == 0) {
294                 tmp = v->cnt;
295                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
296                                               tmp, new_value);
297         }
298 }
299
300 static inline void
301 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
302 {
303         int success = 0;
304         uint64_t tmp;
305
306         while (success == 0) {
307                 tmp = v->cnt;
308                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
309                                               tmp, tmp + inc);
310         }
311 }
312
313 static inline void
314 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
315 {
316         int success = 0;
317         uint64_t tmp;
318
319         while (success == 0) {
320                 tmp = v->cnt;
321                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
322                                               tmp, tmp - dec);
323         }
324 }
325
326 static inline void
327 rte_atomic64_inc(rte_atomic64_t *v)
328 {
329         rte_atomic64_add(v, 1);
330 }
331
332 static inline void
333 rte_atomic64_dec(rte_atomic64_t *v)
334 {
335         rte_atomic64_sub(v, 1);
336 }
337
338 static inline int64_t
339 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
340 {
341         int success = 0;
342         uint64_t tmp;
343
344         while (success == 0) {
345                 tmp = v->cnt;
346                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
347                                               tmp, tmp + inc);
348         }
349
350         return tmp + inc;
351 }
352
353 static inline int64_t
354 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
355 {
356         int success = 0;
357         uint64_t tmp;
358
359         while (success == 0) {
360                 tmp = v->cnt;
361                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
362                                               tmp, tmp - dec);
363         }
364
365         return tmp - dec;
366 }
367
368 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
369 {
370         return rte_atomic64_add_return(v, 1) == 0;
371 }
372
373 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
374 {
375         return rte_atomic64_sub_return(v, 1) == 0;
376 }
377
378 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
379 {
380         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
381 }
382
383 static inline void rte_atomic64_clear(rte_atomic64_t *v)
384 {
385         rte_atomic64_set(v, 0);
386 }
387 #endif
388
389 #ifdef __cplusplus
390 }
391 #endif
392
393 #endif /* _RTE_ATOMIC_I686_H_ */