37f5eff20e35e7398aff90cf9c2aa5d0a492f225
[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 <stdint.h>
50 #include "generic/rte_atomic.h"
51
52 /**
53  * General memory barrier.
54  *
55  * Guarantees that the LOAD and STORE operations generated before the
56  * barrier occur before the LOAD and STORE operations generated after.
57  */
58 #define rte_mb()  {asm volatile("sync" : : : "memory"); }
59
60 /**
61  * Write memory barrier.
62  *
63  * Guarantees that the STORE operations generated before the barrier
64  * occur before the STORE operations generated after.
65  */
66 #ifdef RTE_ARCH_64
67 #define rte_wmb() asm volatile("lwsync" : : : "memory")
68 #else
69 #define rte_wmb() asm volatile("sync" : : : "memory")
70 #endif
71
72 /**
73  * Read memory barrier.
74  *
75  * Guarantees that the LOAD operations generated before the barrier
76  * occur before the LOAD operations generated after.
77  */
78 #ifdef RTE_ARCH_64
79 #define rte_rmb() asm volatile("lwsync" : : : "memory")
80 #else
81 #define rte_rmb() asm volatile("sync" : : : "memory")
82 #endif
83
84 #define rte_smp_mb() rte_mb()
85
86 #define rte_smp_wmb() rte_wmb()
87
88 #define rte_smp_rmb() rte_rmb()
89
90 /*------------------------- 16 bit atomic operations -------------------------*/
91 /* To be compatible with Power7, use GCC built-in functions for 16 bit
92  * operations */
93
94 #ifndef RTE_FORCE_INTRINSICS
95 static inline int
96 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
97 {
98         return __atomic_compare_exchange(dst, &exp, &src, 0, __ATOMIC_ACQUIRE,
99                 __ATOMIC_ACQUIRE) ? 1 : 0;
100 }
101
102 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
103 {
104         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
105 }
106
107 static inline void
108 rte_atomic16_inc(rte_atomic16_t *v)
109 {
110         __atomic_add_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE);
111 }
112
113 static inline void
114 rte_atomic16_dec(rte_atomic16_t *v)
115 {
116         __atomic_sub_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE);
117 }
118
119 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
120 {
121         return __atomic_add_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE) == 0;
122 }
123
124 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
125 {
126         return __atomic_sub_fetch(&v->cnt, 1, __ATOMIC_ACQUIRE) == 0;
127 }
128
129 /*------------------------- 32 bit atomic operations -------------------------*/
130
131 static inline int
132 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
133 {
134         unsigned int ret = 0;
135
136         asm volatile(
137                         "\tlwsync\n"
138                         "1:\tlwarx %[ret], 0, %[dst]\n"
139                         "cmplw %[exp], %[ret]\n"
140                         "bne 2f\n"
141                         "stwcx. %[src], 0, %[dst]\n"
142                         "bne- 1b\n"
143                         "li %[ret], 1\n"
144                         "b 3f\n"
145                         "2:\n"
146                         "stwcx. %[ret], 0, %[dst]\n"
147                         "li %[ret], 0\n"
148                         "3:\n"
149                         "isync\n"
150                         : [ret] "=&r" (ret), "=m" (*dst)
151                         : [dst] "r" (dst),
152                           [exp] "r" (exp),
153                           [src] "r" (src),
154                           "m" (*dst)
155                         : "cc", "memory");
156
157         return ret;
158 }
159
160 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
161 {
162         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
163 }
164
165 static inline void
166 rte_atomic32_inc(rte_atomic32_t *v)
167 {
168         int t;
169
170         asm volatile(
171                         "1: lwarx %[t],0,%[cnt]\n"
172                         "addic %[t],%[t],1\n"
173                         "stwcx. %[t],0,%[cnt]\n"
174                         "bne- 1b\n"
175                         : [t] "=&r" (t), "=m" (v->cnt)
176                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
177                         : "cc", "xer", "memory");
178 }
179
180 static inline void
181 rte_atomic32_dec(rte_atomic32_t *v)
182 {
183         int t;
184
185         asm volatile(
186                         "1: lwarx %[t],0,%[cnt]\n"
187                         "addic %[t],%[t],-1\n"
188                         "stwcx. %[t],0,%[cnt]\n"
189                         "bne- 1b\n"
190                         : [t] "=&r" (t), "=m" (v->cnt)
191                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
192                         : "cc", "xer", "memory");
193 }
194
195 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
196 {
197         int ret;
198
199         asm volatile(
200                         "\n\tlwsync\n"
201                         "1: lwarx %[ret],0,%[cnt]\n"
202                         "addic  %[ret],%[ret],1\n"
203                         "stwcx. %[ret],0,%[cnt]\n"
204                         "bne- 1b\n"
205                         "isync\n"
206                         : [ret] "=&r" (ret)
207                         : [cnt] "r" (&v->cnt)
208                         : "cc", "xer", "memory");
209
210         return ret == 0;
211 }
212
213 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
214 {
215         int ret;
216
217         asm volatile(
218                         "\n\tlwsync\n"
219                         "1: lwarx %[ret],0,%[cnt]\n"
220                         "addic %[ret],%[ret],-1\n"
221                         "stwcx. %[ret],0,%[cnt]\n"
222                         "bne- 1b\n"
223                         "isync\n"
224                         : [ret] "=&r" (ret)
225                         : [cnt] "r" (&v->cnt)
226                         : "cc", "xer", "memory");
227
228         return ret == 0;
229 }
230 /*------------------------- 64 bit atomic operations -------------------------*/
231
232 static inline int
233 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
234 {
235         unsigned int ret = 0;
236
237         asm volatile (
238                         "\tlwsync\n"
239                         "1: ldarx %[ret], 0, %[dst]\n"
240                         "cmpld %[exp], %[ret]\n"
241                         "bne 2f\n"
242                         "stdcx. %[src], 0, %[dst]\n"
243                         "bne- 1b\n"
244                         "li %[ret], 1\n"
245                         "b 3f\n"
246                         "2:\n"
247                         "stdcx. %[ret], 0, %[dst]\n"
248                         "li %[ret], 0\n"
249                         "3:\n"
250                         "isync\n"
251                         : [ret] "=&r" (ret), "=m" (*dst)
252                         : [dst] "r" (dst),
253                           [exp] "r" (exp),
254                           [src] "r" (src),
255                           "m" (*dst)
256                         : "cc", "memory");
257         return ret;
258 }
259
260 static inline void
261 rte_atomic64_init(rte_atomic64_t *v)
262 {
263         v->cnt = 0;
264 }
265
266 static inline int64_t
267 rte_atomic64_read(rte_atomic64_t *v)
268 {
269         long ret;
270
271         asm volatile("ld%U1%X1 %[ret],%[cnt]"
272                 : [ret] "=r"(ret)
273                 : [cnt] "m"(v->cnt));
274
275         return ret;
276 }
277
278 static inline void
279 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
280 {
281         asm volatile("std%U0%X0 %[new_value],%[cnt]"
282                 : [cnt] "=m"(v->cnt)
283                 : [new_value] "r"(new_value));
284 }
285
286 static inline void
287 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
288 {
289         long t;
290
291         asm volatile(
292                         "1: ldarx %[t],0,%[cnt]\n"
293                         "add %[t],%[inc],%[t]\n"
294                         "stdcx. %[t],0,%[cnt]\n"
295                         "bne- 1b\n"
296                         : [t] "=&r" (t), "=m" (v->cnt)
297                         : [cnt] "r" (&v->cnt), [inc] "r" (inc), "m" (v->cnt)
298                         : "cc", "memory");
299 }
300
301 static inline void
302 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
303 {
304         long t;
305
306         asm volatile(
307                         "1: ldarx %[t],0,%[cnt]\n"
308                         "subf %[t],%[dec],%[t]\n"
309                         "stdcx. %[t],0,%[cnt]\n"
310                         "bne- 1b\n"
311                         : [t] "=&r" (t), "+m" (v->cnt)
312                         : [cnt] "r" (&v->cnt), [dec] "r" (dec), "m" (v->cnt)
313                         : "cc", "memory");
314 }
315
316 static inline void
317 rte_atomic64_inc(rte_atomic64_t *v)
318 {
319         long t;
320
321         asm volatile(
322                         "1: ldarx %[t],0,%[cnt]\n"
323                         "addic %[t],%[t],1\n"
324                         "stdcx. %[t],0,%[cnt]\n"
325                         "bne- 1b\n"
326                         : [t] "=&r" (t), "+m" (v->cnt)
327                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
328                         : "cc", "xer", "memory");
329 }
330
331 static inline void
332 rte_atomic64_dec(rte_atomic64_t *v)
333 {
334         long t;
335
336         asm volatile(
337                         "1: ldarx %[t],0,%[cnt]\n"
338                         "addic %[t],%[t],-1\n"
339                         "stdcx. %[t],0,%[cnt]\n"
340                         "bne- 1b\n"
341                         : [t] "=&r" (t), "+m" (v->cnt)
342                         : [cnt] "r" (&v->cnt), "m" (v->cnt)
343                         : "cc", "xer", "memory");
344 }
345
346 static inline int64_t
347 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
348 {
349         long ret;
350
351         asm volatile(
352                         "\n\tlwsync\n"
353                         "1: ldarx %[ret],0,%[cnt]\n"
354                         "add %[ret],%[inc],%[ret]\n"
355                         "stdcx. %[ret],0,%[cnt]\n"
356                         "bne- 1b\n"
357                         "isync\n"
358                         : [ret] "=&r" (ret)
359                         : [inc] "r" (inc), [cnt] "r" (&v->cnt)
360                         : "cc", "memory");
361
362         return ret;
363 }
364
365 static inline int64_t
366 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
367 {
368         long ret;
369
370         asm volatile(
371                         "\n\tlwsync\n"
372                         "1: ldarx %[ret],0,%[cnt]\n"
373                         "subf %[ret],%[dec],%[ret]\n"
374                         "stdcx. %[ret],0,%[cnt]\n"
375                         "bne- 1b\n"
376                         "isync\n"
377                         : [ret] "=&r" (ret)
378                         : [dec] "r" (dec), [cnt] "r" (&v->cnt)
379                         : "cc", "memory");
380
381         return ret;
382 }
383
384 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
385 {
386         long ret;
387
388         asm volatile(
389                         "\n\tlwsync\n"
390                         "1: ldarx %[ret],0,%[cnt]\n"
391                         "addic %[ret],%[ret],1\n"
392                         "stdcx. %[ret],0,%[cnt]\n"
393                         "bne- 1b\n"
394                         "isync\n"
395                         : [ret] "=&r" (ret)
396                         : [cnt] "r" (&v->cnt)
397                         : "cc", "xer", "memory");
398
399         return ret == 0;
400 }
401
402 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
403 {
404         long ret;
405
406         asm volatile(
407                         "\n\tlwsync\n"
408                         "1: ldarx %[ret],0,%[cnt]\n"
409                         "addic %[ret],%[ret],-1\n"
410                         "stdcx. %[ret],0,%[cnt]\n"
411                         "bne- 1b\n"
412                         "isync\n"
413                         : [ret] "=&r" (ret)
414                         : [cnt] "r" (&v->cnt)
415                         : "cc", "xer", "memory");
416
417         return ret == 0;
418 }
419
420 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
421 {
422         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
423 }
424
425 /**
426  * Atomically set a 64-bit counter to 0.
427  *
428  * @param v
429  *   A pointer to the atomic counter.
430  */
431 static inline void rte_atomic64_clear(rte_atomic64_t *v)
432 {
433         v->cnt = 0;
434 }
435 #endif
436
437 #ifdef __cplusplus
438 }
439 #endif
440
441 #endif /* _RTE_ATOMIC_PPC_64_H_ */