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