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