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