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