Imported Upstream version 16.07-rc4
[deb_dpdk.git] / lib / librte_eal / common / include / arch / ppc_64 / rte_atomic.h
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright (C) IBM Corporation 2014.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of IBM Corporation nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34  * Inspired from FreeBSD src/sys/powerpc/include/atomic.h
35  * Copyright (c) 2008 Marcel Moolenaar
36  * Copyright (c) 2001 Benno Rice
37  * Copyright (c) 2001 David E. O'Brien
38  * Copyright (c) 1998 Doug Rabson
39  * All rights reserved.
40  */
41
42 #ifndef _RTE_ATOMIC_PPC_64_H_
43 #define _RTE_ATOMIC_PPC_64_H_
44
45 #ifdef __cplusplus
46 extern "C" {
47 #endif
48
49 #include "generic/rte_atomic.h"
50
51 /**
52  * General memory barrier.
53  *
54  * Guarantees that the LOAD and STORE operations generated before the
55  * barrier occur before the LOAD and STORE operations generated after.
56  */
57 #define rte_mb()  {asm volatile("sync" : : : "memory"); }
58
59 /**
60  * Write memory barrier.
61  *
62  * Guarantees that the STORE operations generated before the barrier
63  * occur before the STORE operations generated after.
64  */
65 #ifdef RTE_ARCH_64
66 #define rte_wmb() {asm volatile("lwsync" : : : "memory"); }
67 #else
68 #define rte_wmb() {asm volatile("sync" : : : "memory"); }
69 #endif
70
71 /**
72  * Read memory barrier.
73  *
74  * Guarantees that the LOAD operations generated before the barrier
75  * occur before the LOAD operations generated after.
76  */
77 #ifdef RTE_ARCH_64
78 #define rte_rmb() {asm volatile("lwsync" : : : "memory"); }
79 #else
80 #define rte_rmb() {asm volatile("sync" : : : "memory"); }
81 #endif
82
83 #define rte_smp_mb() rte_mb()
84
85 #define rte_smp_wmb() rte_wmb()
86
87 #define rte_smp_rmb() rte_rmb()
88
89 /*------------------------- 16 bit atomic operations -------------------------*/
90 /* To be compatible with Power7, use GCC built-in functions for 16 bit
91  * operations */
92
93 #ifndef RTE_FORCE_INTRINSICS
94 static inline int
95 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
96 {
97         return __atomic_compare_exchange(dst, &exp, &src, 0, __ATOMIC_ACQUIRE,
98                 __ATOMIC_ACQUIRE) ? 1 : 0;
99 }
100
101 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
102 {
103         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
104 }
105
106 static inline void
107 rte_atomic16_inc(rte_atomic16_t *v)
108 {
109         __atomic_add_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE);
110 }
111
112 static inline void
113 rte_atomic16_dec(rte_atomic16_t *v)
114 {
115         __atomic_sub_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE);
116 }
117
118 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
119 {
120         return __atomic_add_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE) == 0;
121 }
122
123 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
124 {
125         return __atomic_sub_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE) == 0;
126 }
127
128 /*------------------------- 32 bit atomic operations -------------------------*/
129
130 static inline int
131 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
132 {
133         unsigned int ret = 0;
134
135         asm volatile(
136                         "\tlwsync\n"
137                         "1:\tlwarx %[ret], 0, %[dst]\n"
138                         "cmplw %[exp], %[ret]\n"
139                         "bne 2f\n"
140                         "stwcx. %[src], 0, %[dst]\n"
141                         "bne- 1b\n"
142                         "li %[ret], 1\n"
143                         "b 3f\n"
144                         "2:\n"
145                         "stwcx. %[ret], 0, %[dst]\n"
146                         "li %[ret], 0\n"
147                         "3:\n"
148                         "isync\n"
149                         : [ret] "=&r" (ret), "=m" (*dst)
150                         : [dst] "r" (dst),
151                           [exp] "r" (exp),
152                           [src] "r" (src),
153                           "m" (*dst)
154                         : "cc", "memory");
155
156         return ret;
157 }
158
159 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
160 {
161         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
162 }
163
164 static inline void
165 rte_atomic32_inc(rte_atomic32_t *v)
166 {
167         int t;
168
169         asm volatile(
170                         "1: lwarx %[t],0,%[cnt]\n"
171                         "addic %[t],%[t],1\n"
172                         "stwcx. %[t],0,%[cnt]\n"
173                         "bne- 1b\n"
174                         : [t] "=&r" (t), "=m" (v->cnt)
175                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
176                         : "cc", "xer", "memory");
177 }
178
179 static inline void
180 rte_atomic32_dec(rte_atomic32_t *v)
181 {
182         int t;
183
184         asm volatile(
185                         "1: lwarx %[t],0,%[cnt]\n"
186                         "addic %[t],%[t],-1\n"
187                         "stwcx. %[t],0,%[cnt]\n"
188                         "bne- 1b\n"
189                         : [t] "=&r" (t), "=m" (v->cnt)
190                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
191                         : "cc", "xer", "memory");
192 }
193
194 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
195 {
196         int ret;
197
198         asm volatile(
199                         "\n\tlwsync\n"
200                         "1: lwarx %[ret],0,%[cnt]\n"
201                         "addic  %[ret],%[ret],1\n"
202                         "stwcx. %[ret],0,%[cnt]\n"
203                         "bne- 1b\n"
204                         "isync\n"
205                         : [ret] "=&r" (ret)
206                         : [cnt] "r" (&v->cnt)
207                         : "cc", "xer", "memory");
208
209         return ret == 0;
210 }
211
212 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
213 {
214         int ret;
215
216         asm volatile(
217                         "\n\tlwsync\n"
218                         "1: lwarx %[ret],0,%[cnt]\n"
219                         "addic %[ret],%[ret],-1\n"
220                         "stwcx. %[ret],0,%[cnt]\n"
221                         "bne- 1b\n"
222                         "isync\n"
223                         : [ret] "=&r" (ret)
224                         : [cnt] "r" (&v->cnt)
225                         : "cc", "xer", "memory");
226
227         return ret == 0;
228 }
229 /*------------------------- 64 bit atomic operations -------------------------*/
230
231 static inline int
232 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
233 {
234         unsigned int ret = 0;
235
236         asm volatile (
237                         "\tlwsync\n"
238                         "1: ldarx %[ret], 0, %[dst]\n"
239                         "cmpld %[exp], %[ret]\n"
240                         "bne 2f\n"
241                         "stdcx. %[src], 0, %[dst]\n"
242                         "bne- 1b\n"
243                         "li %[ret], 1\n"
244                         "b 3f\n"
245                         "2:\n"
246                         "stdcx. %[ret], 0, %[dst]\n"
247                         "li %[ret], 0\n"
248                         "3:\n"
249                         "isync\n"
250                         : [ret] "=&r" (ret), "=m" (*dst)
251                         : [dst] "r" (dst),
252                           [exp] "r" (exp),
253                           [src] "r" (src),
254                           "m" (*dst)
255                         : "cc", "memory");
256         return ret;
257 }
258
259 static inline void
260 rte_atomic64_init(rte_atomic64_t *v)
261 {
262         v->cnt = 0;
263 }
264
265 static inline int64_t
266 rte_atomic64_read(rte_atomic64_t *v)
267 {
268         long ret;
269
270         asm volatile("ld%U1%X1 %[ret],%[cnt]"
271                 : [ret] "=r"(ret)
272                 : [cnt] "m"(v->cnt));
273
274         return ret;
275 }
276
277 static inline void
278 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
279 {
280         asm volatile("std%U0%X0 %[new_value],%[cnt]"
281                 : [cnt] "=m"(v->cnt)
282                 : [new_value] "r"(new_value));
283 }
284
285 static inline void
286 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
287 {
288         long t;
289
290         asm volatile(
291                         "1: ldarx %[t],0,%[cnt]\n"
292                         "add %[t],%[inc],%[t]\n"
293                         "stdcx. %[t],0,%[cnt]\n"
294                         "bne- 1b\n"
295                         : [t] "=&r" (t), "=m" (v->cnt)
296                         : [cnt] "r" (&v->cnt), [inc] "r" (inc), "m" (v->cnt)
297                         : "cc", "memory");
298 }
299
300 static inline void
301 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
302 {
303         long t;
304
305         asm volatile(
306                         "1: ldarx %[t],0,%[cnt]\n"
307                         "subf %[t],%[dec],%[t]\n"
308                         "stdcx. %[t],0,%[cnt]\n"
309                         "bne- 1b\n"
310                         : [t] "=&r" (t), "+m" (v->cnt)
311                         : [cnt] "r" (&v->cnt), [dec] "r" (dec), "m" (v->cnt)
312                         : "cc", "memory");
313 }
314
315 static inline void
316 rte_atomic64_inc(rte_atomic64_t *v)
317 {
318         long t;
319
320         asm volatile(
321                         "1: ldarx %[t],0,%[cnt]\n"
322                         "addic %[t],%[t],1\n"
323                         "stdcx. %[t],0,%[cnt]\n"
324                         "bne- 1b\n"
325                         : [t] "=&r" (t), "+m" (v->cnt)
326                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
327                         : "cc", "xer", "memory");
328 }
329
330 static inline void
331 rte_atomic64_dec(rte_atomic64_t *v)
332 {
333         long t;
334
335         asm volatile(
336                         "1: ldarx %[t],0,%[cnt]\n"
337                         "addic %[t],%[t],-1\n"
338                         "stdcx. %[t],0,%[cnt]\n"
339                         "bne- 1b\n"
340                         : [t] "=&r" (t), "+m" (v->cnt)
341                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
342                         : "cc", "xer", "memory");
343 }
344
345 static inline int64_t
346 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
347 {
348         long ret;
349
350         asm volatile(
351                         "\n\tlwsync\n"
352                         "1: ldarx %[ret],0,%[cnt]\n"
353                         "add %[ret],%[inc],%[ret]\n"
354                         "stdcx. %[ret],0,%[cnt]\n"
355                         "bne- 1b\n"
356                         "isync\n"
357                         : [ret] "=&r" (ret)
358                         : [inc] "r" (inc), [cnt] "r" (&v->cnt)
359                         : "cc", "memory");
360
361         return ret;
362 }
363
364 static inline int64_t
365 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
366 {
367         long ret;
368
369         asm volatile(
370                         "\n\tlwsync\n"
371                         "1: ldarx %[ret],0,%[cnt]\n"
372                         "subf %[ret],%[dec],%[ret]\n"
373                         "stdcx. %[ret],0,%[cnt]\n"
374                         "bne- 1b\n"
375                         "isync\n"
376                         : [ret] "=&r" (ret)
377                         : [dec] "r" (dec), [cnt] "r" (&v->cnt)
378                         : "cc", "memory");
379
380         return ret;
381 }
382
383 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
384 {
385         long ret;
386
387         asm volatile(
388                         "\n\tlwsync\n"
389                         "1: ldarx %[ret],0,%[cnt]\n"
390                         "addic %[ret],%[ret],1\n"
391                         "stdcx. %[ret],0,%[cnt]\n"
392                         "bne- 1b\n"
393                         "isync\n"
394                         : [ret] "=&r" (ret)
395                         : [cnt] "r" (&v->cnt)
396                         : "cc", "xer", "memory");
397
398         return ret == 0;
399 }
400
401 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
402 {
403         long ret;
404
405         asm volatile(
406                         "\n\tlwsync\n"
407                         "1: ldarx %[ret],0,%[cnt]\n"
408                         "addic %[ret],%[ret],-1\n"
409                         "stdcx. %[ret],0,%[cnt]\n"
410                         "bne- 1b\n"
411                         "isync\n"
412                         : [ret] "=&r" (ret)
413                         : [cnt] "r" (&v->cnt)
414                         : "cc", "xer", "memory");
415
416         return ret == 0;
417 }
418
419 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
420 {
421         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
422 }
423
424 /**
425  * Atomically set a 64-bit counter to 0.
426  *
427  * @param v
428  *   A pointer to the atomic counter.
429  */
430 static inline void rte_atomic64_clear(rte_atomic64_t *v)
431 {
432         v->cnt = 0;
433 }
434 #endif
435
436 #ifdef __cplusplus
437 }
438 #endif
439
440 #endif /* _RTE_ATOMIC_PPC_64_H_ */