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