]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/include/atomic.h
Merge ACPICA 20150717.
[FreeBSD/FreeBSD.git] / sys / arm64 / include / atomic.h
1 /*-
2  * Copyright (c) 2013 Andrew Turner <andrew@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #ifndef _MACHINE_ATOMIC_H_
30 #define _MACHINE_ATOMIC_H_
31
32 #define isb()           __asm __volatile("isb" : : : "memory")
33
34 /*
35  * Options for DMB and DSB:
36  *      oshld   Outer Shareable, load
37  *      oshst   Outer Shareable, store
38  *      osh     Outer Shareable, all
39  *      nshld   Non-shareable, load
40  *      nshst   Non-shareable, store
41  *      nsh     Non-shareable, all
42  *      ishld   Inner Shareable, load
43  *      ishst   Inner Shareable, store
44  *      ish     Inner Shareable, all
45  *      ld      Full system, load
46  *      st      Full system, store
47  *      sy      Full system, all
48  */
49 #define dsb(opt)        __asm __volatile("dsb " __STRING(opt) : : : "memory")
50 #define dmb(opt)        __asm __volatile("dmb " __STRING(opt) : : : "memory")
51
52 #define mb()    dmb(sy) /* Full system memory barrier all */
53 #define wmb()   dmb(st) /* Full system memory barrier store */
54 #define rmb()   dmb(ld) /* Full system memory barrier load */
55
56 static __inline void
57 atomic_add_32(volatile uint32_t *p, uint32_t val)
58 {
59         uint32_t tmp;
60         int res;
61
62         __asm __volatile(
63             "1: ldxr    %w0, [%2]      \n"
64             "   add     %w0, %w0, %w3  \n"
65             "   stxr    %w1, %w0, [%2] \n"
66             "   cbnz    %w1, 1b        \n"
67             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
68         );
69 }
70
71 static __inline void
72 atomic_clear_32(volatile uint32_t *p, uint32_t val)
73 {
74         uint32_t tmp;
75         int res;
76
77         __asm __volatile(
78             "1: ldxr    %w0, [%2]      \n"
79             "   bic     %w0, %w0, %w3  \n"
80             "   stxr    %w1, %w0, [%2] \n"
81             "   cbnz    %w1, 1b        \n"
82             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
83         );
84 }
85
86 static __inline int
87 atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
88 {
89         uint32_t tmp;
90         int res;
91
92         __asm __volatile(
93             "1: mov     %w1, #1        \n"
94             "   ldxr    %w0, [%2]      \n"
95             "   cmp     %w0, %w3       \n"
96             "   b.ne    2f             \n"
97             "   stxr    %w1, %w4, [%2] \n"
98             "   cbnz    %w1, 1b        \n"
99             "2:"
100             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
101             : : "cc"
102         );
103
104         return (!res);
105 }
106
107 static __inline uint32_t
108 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
109 {
110         uint32_t tmp, ret;
111         int res;
112
113         __asm __volatile(
114             "1: ldxr    %w4, [%2]      \n"
115             "   add     %w0, %w4, %w3  \n"
116             "   stxr    %w1, %w0, [%2] \n"
117             "   cbnz    %w1, 1b        \n"
118             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
119         );
120
121         return (ret);
122 }
123
124 static __inline uint32_t
125 atomic_readandclear_32(volatile uint32_t *p)
126 {
127         uint32_t tmp, ret;
128         int res;
129
130         __asm __volatile(
131             "   mov     %w0, #0        \n"
132             "1: ldxr    %w3, [%2]      \n"
133             "   stxr    %w1, %w0, [%2] \n"
134             "   cbnz    %w1, 1b        \n"
135             : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
136         );
137
138         return (ret);
139 }
140
141 static __inline void
142 atomic_set_32(volatile uint32_t *p, uint32_t val)
143 {
144         uint32_t tmp;
145         int res;
146
147         __asm __volatile(
148             "1: ldxr    %w0, [%2]      \n"
149             "   orr     %w0, %w0, %w3  \n"
150             "   stxr    %w1, %w0, [%2] \n"
151             "   cbnz    %w1, 1b        \n"
152             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
153         );
154 }
155
156 static __inline void
157 atomic_subtract_32(volatile uint32_t *p, uint32_t val)
158 {
159         uint32_t tmp;
160         int res;
161
162         __asm __volatile(
163             "1: ldxr    %w0, [%2]      \n"
164             "   sub     %w0, %w0, %w3  \n"
165             "   stxr    %w1, %w0, [%2] \n"
166             "   cbnz    %w1, 1b        \n"
167             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
168         );
169 }
170
171 #define atomic_add_int          atomic_add_32
172 #define atomic_clear_int        atomic_clear_32
173 #define atomic_cmpset_int       atomic_cmpset_32
174 #define atomic_fetchadd_int     atomic_fetchadd_32
175 #define atomic_readandclear_int atomic_readandclear_32
176 #define atomic_set_int          atomic_set_32
177 #define atomic_subtract_int     atomic_subtract_32
178
179 static __inline void
180 atomic_add_acq_32(volatile uint32_t *p, uint32_t val)
181 {
182         uint32_t tmp;
183         int res;
184
185         __asm __volatile(
186             "1: ldaxr   %w0, [%2]      \n"
187             "   add     %w0, %w0, %w3  \n"
188             "   stxr    %w1, %w0, [%2] \n"
189             "   cbnz    %w1, 1b        \n"
190             "2:"
191             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
192         );
193 }
194
195 static __inline void
196 atomic_clear_acq_32(volatile uint32_t *p, uint32_t val)
197 {
198         uint32_t tmp;
199         int res;
200
201         __asm __volatile(
202             "1: ldaxr   %w0, [%2]      \n"
203             "   bic     %w0, %w0, %w3  \n"
204             "   stxr    %w1, %w0, [%2] \n"
205             "   cbnz    %w1, 1b        \n"
206             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
207         );
208 }
209
210 static __inline int
211 atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
212 {
213         uint32_t tmp;
214         int res;
215
216         __asm __volatile(
217             "1: mov     %w1, #1        \n"
218             "   ldaxr   %w0, [%2]      \n"
219             "   cmp     %w0, %w3       \n"
220             "   b.ne    2f             \n"
221             "   stxr    %w1, %w4, [%2] \n"
222             "   cbnz    %w1, 1b        \n"
223             "2:"
224             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
225             : : "cc", "memory"
226         );
227
228         return (!res);
229 }
230
231 static __inline uint32_t
232 atomic_load_acq_32(volatile uint32_t *p)
233 {
234         uint32_t ret;
235
236         __asm __volatile(
237             "ldar       %w0, [%1] \n"
238             : "=&r" (ret) : "r" (p) : "memory");
239
240         return (ret);
241 }
242
243 static __inline void
244 atomic_set_acq_32(volatile uint32_t *p, uint32_t val)
245 {
246         uint32_t tmp;
247         int res;
248
249         __asm __volatile(
250             "1: ldaxr   %w0, [%2]      \n"
251             "   orr     %w0, %w0, %w3  \n"
252             "   stxr    %w1, %w0, [%2] \n"
253             "   cbnz    %w1, 1b        \n"
254             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
255         );
256 }
257
258 static __inline void
259 atomic_subtract_acq_32(volatile uint32_t *p, uint32_t val)
260 {
261         uint32_t tmp;
262         int res;
263
264         __asm __volatile(
265             "1: ldaxr   %w0, [%2]      \n"
266             "   sub     %w0, %w0, %w3  \n"
267             "   stxr    %w1, %w0, [%2] \n"
268             "   cbnz    %w1, 1b        \n"
269             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
270         );
271 }
272
273 #define atomic_add_acq_int      atomic_add_acq_32
274 #define atomic_clear_acq_int    atomic_clear_acq_32
275 #define atomic_cmpset_acq_int   atomic_cmpset_acq_32
276 #define atomic_load_acq_int     atomic_load_acq_32
277 #define atomic_set_acq_int      atomic_set_acq_32
278 #define atomic_subtract_acq_int atomic_subtract_acq_32
279
280 /* The atomic functions currently are both acq and rel, we should fix this. */
281
282 static __inline void
283 atomic_add_rel_32(volatile uint32_t *p, uint32_t val)
284 {
285         uint32_t tmp;
286         int res;
287
288         __asm __volatile(
289             "1: ldxr    %w0, [%2]      \n"
290             "   add     %w0, %w0, %w3  \n"
291             "   stlxr   %w1, %w0, [%2] \n"
292             "   cbnz    %w1, 1b        \n"
293             "2:"
294             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
295         );
296 }
297
298 static __inline void
299 atomic_clear_rel_32(volatile uint32_t *p, uint32_t val)
300 {
301         uint32_t tmp;
302         int res;
303
304         __asm __volatile(
305             "1: ldxr    %w0, [%2]      \n"
306             "   bic     %w0, %w0, %w3  \n"
307             "   stlxr   %w1, %w0, [%2] \n"
308             "   cbnz    %w1, 1b        \n"
309             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
310         );
311 }
312
313 static __inline int
314 atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
315 {
316         uint32_t tmp;
317         int res;
318
319         __asm __volatile(
320             "1: mov     %w1, #1        \n"
321             "   ldxr    %w0, [%2]      \n"
322             "   cmp     %w0, %w3       \n"
323             "   b.ne    2f             \n"
324             "   stlxr   %w1, %w4, [%2] \n"
325             "   cbnz    %w1, 1b        \n"
326             "2:"
327             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
328             : : "cc", "memory"
329         );
330
331         return (!res);
332 }
333
334 static __inline void
335 atomic_set_rel_32(volatile uint32_t *p, uint32_t val)
336 {
337         uint32_t tmp;
338         int res;
339
340         __asm __volatile(
341             "1: ldxr    %w0, [%2]      \n"
342             "   orr     %w0, %w0, %w3  \n"
343             "   stlxr   %w1, %w0, [%2] \n"
344             "   cbnz    %w1, 1b        \n"
345             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
346         );
347 }
348
349 static __inline void
350 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
351 {
352
353         __asm __volatile(
354             "stlr       %w0, [%1] \n"
355             : : "r" (val), "r" (p) : "memory");
356 }
357
358 static __inline void
359 atomic_subtract_rel_32(volatile uint32_t *p, uint32_t val)
360 {
361         uint32_t tmp;
362         int res;
363
364         __asm __volatile(
365             "1: ldxr    %w0, [%2]      \n"
366             "   sub     %w0, %w0, %w3  \n"
367             "   stlxr   %w1, %w0, [%2] \n"
368             "   cbnz    %w1, 1b        \n"
369             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
370         );
371 }
372
373 #define atomic_add_rel_int      atomic_add_rel_32
374 #define atomic_clear_rel_int    atomic_add_rel_32
375 #define atomic_cmpset_rel_int   atomic_cmpset_rel_32
376 #define atomic_set_rel_int      atomic_set_rel_32
377 #define atomic_subtract_rel_int atomic_subtract_rel_32
378 #define atomic_store_rel_int    atomic_store_rel_32
379
380
381 static __inline void
382 atomic_add_64(volatile uint64_t *p, uint64_t val)
383 {
384         uint64_t tmp;
385         int res;
386
387         __asm __volatile(
388             "1: ldxr    %0, [%2]      \n"
389             "   add     %0, %0, %3    \n"
390             "   stxr    %w1, %0, [%2] \n"
391             "   cbnz    %w1, 1b       \n"
392             : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (val) : : "cc"
393         );
394 }
395
396 static __inline void
397 atomic_clear_64(volatile uint64_t *p, uint64_t val)
398 {
399         uint64_t tmp;
400         int res;
401
402         __asm __volatile(
403             "1: ldxr    %0, [%2]      \n"
404             "   bic     %0, %0, %3    \n"
405             "   stxr    %w1, %0, [%2] \n"
406             "   cbnz    %w1, 1b       \n"
407             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
408         );
409 }
410
411 static __inline int
412 atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
413 {
414         uint64_t tmp;
415         int res;
416
417         __asm __volatile(
418             "1: mov     %w1, #1       \n"
419             "   ldxr    %0, [%2]      \n"
420             "   cmp     %0, %3        \n"
421             "   b.ne    2f            \n"
422             "   stxr    %w1, %4, [%2] \n"
423             "   cbnz    %w1, 1b       \n"
424             "2:"
425             : "=&r" (tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
426             : : "cc", "memory"
427         );
428
429         return (!res);
430 }
431
432 static __inline uint64_t
433 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
434 {
435         uint64_t tmp, ret;
436         int res;
437
438         __asm __volatile(
439             "1: ldxr    %4, [%2]      \n"
440             "   add     %0, %4, %3    \n"
441             "   stxr    %w1, %0, [%2] \n"
442             "   cbnz    %w1, 1b       \n"
443             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
444         );
445
446         return (ret);
447 }
448
449 static __inline uint64_t
450 atomic_readandclear_64(volatile uint64_t *p)
451 {
452         uint64_t tmp, ret;
453         int res;
454
455         __asm __volatile(
456             "   mov     %0, #0        \n"
457             "1: ldxr    %3, [%2]      \n"
458             "   stxr    %w1, %0, [%2] \n"
459             "   cbnz    %w1, 1b       \n"
460             : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
461         );
462
463         return (ret);
464 }
465
466 static __inline void
467 atomic_set_64(volatile uint64_t *p, uint64_t val)
468 {
469         uint64_t tmp;
470         int res;
471
472         __asm __volatile(
473             "1: ldxr    %0, [%2]      \n"
474             "   orr     %0, %0, %3    \n"
475             "   stxr    %w1, %0, [%2] \n"
476             "   cbnz    %w1, 1b       \n"
477             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
478         );
479 }
480
481 static __inline void
482 atomic_subtract_64(volatile uint64_t *p, uint64_t val)
483 {
484         uint64_t tmp;
485         int res;
486
487         __asm __volatile(
488             "1: ldxr    %0, [%2]      \n"
489             "   sub     %0, %0, %3    \n"
490             "   stxr    %w1, %0, [%2] \n"
491             "   cbnz    %w1, 1b       \n"
492             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
493         );
494 }
495
496 static __inline uint64_t
497 atomic_swap_64(volatile uint64_t *p, uint64_t val)
498 {
499         uint64_t old;
500         int res;
501
502         __asm __volatile(
503             "1: ldxr    %0, [%2]      \n"
504             "   stxr    %w1, %3, [%2] \n"
505             "   cbnz    %w1, 1b       \n"
506             : "=&r"(old), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
507         );
508
509         return (old);
510 }
511
512 #define atomic_add_long                 atomic_add_64
513 #define atomic_clear_long               atomic_clear_64
514 #define atomic_cmpset_long              atomic_cmpset_64
515 #define atomic_fetchadd_long            atomic_fetchadd_64
516 #define atomic_readandclear_long        atomic_readandclear_64
517 #define atomic_set_long                 atomic_set_64
518 #define atomic_subtract_long            atomic_subtract_64
519
520 #define atomic_add_ptr                  atomic_add_64
521 #define atomic_clear_ptr                atomic_clear_64
522 #define atomic_cmpset_ptr               atomic_cmpset_64
523 #define atomic_fetchadd_ptr             atomic_fetchadd_64
524 #define atomic_readandclear_ptr         atomic_readandclear_64
525 #define atomic_set_ptr                  atomic_set_64
526 #define atomic_subtract_ptr             atomic_subtract_64
527
528 static __inline void
529 atomic_add_acq_64(volatile uint64_t *p, uint64_t val)
530 {
531         uint64_t tmp;
532         int res;
533
534         __asm __volatile(
535             "1: ldaxr   %0, [%2]      \n"
536             "   add     %0, %0, %3    \n"
537             "   stxr    %w1, %0, [%2] \n"
538             "   cbnz    %w1, 1b       \n"
539             "2:"
540             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
541         );
542 }
543
544 static __inline void
545 atomic_clear_acq_64(volatile uint64_t *p, uint64_t val)
546 {
547         uint64_t tmp;
548         int res;
549
550         __asm __volatile(
551             "1: ldaxr   %0, [%2]      \n"
552             "   bic     %0, %0, %3    \n"
553             "   stxr    %w1, %0, [%2] \n"
554             "   cbnz    %w1, 1b       \n"
555             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
556         );
557 }
558
559 static __inline int
560 atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
561 {
562         uint64_t tmp;
563         int res;
564
565         __asm __volatile(
566             "1: mov     %w1, #1       \n"
567             "   ldaxr   %0, [%2]      \n"
568             "   cmp     %0, %3        \n"
569             "   b.ne    2f            \n"
570             "   stxr    %w1, %4, [%2] \n"
571             "   cbnz    %w1, 1b       \n"
572             "2:"
573             : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
574             : : "cc", "memory"
575         );
576
577         return (!res);
578 }
579
580 static __inline uint64_t
581 atomic_load_acq_64(volatile uint64_t *p)
582 {
583         uint64_t ret;
584
585         __asm __volatile(
586             "ldar       %0, [%1] \n"
587             : "=&r" (ret) : "r" (p) : "memory");
588
589         return (ret);
590 }
591
592 static __inline void
593 atomic_set_acq_64(volatile uint64_t *p, uint64_t val)
594 {
595         uint64_t tmp;
596         int res;
597
598         __asm __volatile(
599             "1: ldaxr   %0, [%2]      \n"
600             "   orr     %0, %0, %3    \n"
601             "   stxr    %w1, %0, [%2] \n"
602             "   cbnz    %w1, 1b       \n"
603             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
604         );
605 }
606
607 static __inline void
608 atomic_subtract_acq_64(volatile uint64_t *p, uint64_t val)
609 {
610         uint64_t tmp;
611         int res;
612
613         __asm __volatile(
614             "1: ldaxr   %0, [%2]      \n"
615             "   sub     %0, %0, %3    \n"
616             "   stxr    %w1, %0, [%2] \n"
617             "   cbnz    %w1, 1b       \n"
618             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
619         );
620 }
621
622 #define atomic_add_acq_long             atomic_add_acq_64
623 #define atomic_clear_acq_long           atomic_add_acq_64
624 #define atomic_cmpset_acq_long          atomic_cmpset_acq_64
625 #define atomic_load_acq_long            atomic_load_acq_64
626 #define atomic_set_acq_long             atomic_set_acq_64
627 #define atomic_subtract_acq_long        atomic_subtract_acq_64
628
629 #define atomic_add_acq_ptr              atomic_add_acq_64
630 #define atomic_clear_acq_ptr            atomic_add_acq_64
631 #define atomic_cmpset_acq_ptr           atomic_cmpset_acq_64
632 #define atomic_load_acq_ptr             atomic_load_acq_64
633 #define atomic_set_acq_ptr              atomic_set_acq_64
634 #define atomic_subtract_acq_ptr         atomic_subtract_acq_64
635
636 /*
637  * TODO: The atomic functions currently are both acq and rel, we should fix
638  * this.
639  */
640 static __inline void
641 atomic_add_rel_64(volatile uint64_t *p, uint64_t val)
642 {
643         uint64_t tmp;
644         int res;
645
646         __asm __volatile(
647             "1: ldxr    %0, [%2]      \n"
648             "   add     %0, %0, %3    \n"
649             "   stlxr   %w1, %0, [%2] \n"
650             "   cbnz    %w1, 1b       \n"
651             "2:"
652             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
653         );
654 }
655
656 static __inline void
657 atomic_clear_rel_64(volatile uint64_t *p, uint64_t val)
658 {
659         uint64_t tmp;
660         int res;
661
662         __asm __volatile(
663             "1: ldxr    %0, [%2]      \n"
664             "   bic     %0, %0, %3    \n"
665             "   stlxr   %w1, %0, [%2] \n"
666             "   cbnz    %w1, 1b       \n"
667             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
668         );
669 }
670
671 static __inline int
672 atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
673 {
674         uint64_t tmp;
675         int res;
676
677         __asm __volatile(
678             "1: mov     %w1, #1       \n"
679             "   ldxr    %0, [%2]      \n"
680             "   cmp     %0, %3        \n"
681             "   b.ne    2f            \n"
682             "   stlxr   %w1, %4, [%2] \n"
683             "   cbnz    %w1, 1b       \n"
684             "2:"
685             : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
686             : : "cc", "memory"
687         );
688
689         return (!res);
690 }
691
692 static __inline void
693 atomic_set_rel_64(volatile uint64_t *p, uint64_t val)
694 {
695         uint64_t tmp;
696         int res;
697
698         __asm __volatile(
699             "1: ldxr    %0, [%2]      \n"
700             "   orr     %0, %0, %3    \n"
701             "   stlxr   %w1, %0, [%2] \n"
702             "   cbnz    %w1, 1b       \n"
703             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
704         );
705 }
706
707 static __inline void
708 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
709 {
710
711         __asm __volatile(
712             "stlr       %0, [%1] \n"
713             : : "r" (val), "r" (p) : "memory");
714 }
715
716 static __inline void
717 atomic_subtract_rel_64(volatile uint64_t *p, uint64_t val)
718 {
719         uint64_t tmp;
720         int res;
721
722         __asm __volatile(
723             "1: ldxr    %0, [%2]      \n"
724             "   sub     %0, %0, %3    \n"
725             "   stlxr   %w1, %0, [%2] \n"
726             "   cbnz    %w1, 1b       \n"
727             : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
728         );
729 }
730
731 static __inline void
732 atomic_thread_fence_acq(void)
733 {
734
735         dmb(ld);
736 }
737
738 static __inline void
739 atomic_thread_fence_rel(void)
740 {
741
742         dmb(sy);
743 }
744
745 static __inline void
746 atomic_thread_fence_acq_rel(void)
747 {
748
749         dmb(sy);
750 }
751
752 static __inline void
753 atomic_thread_fence_seq_cst(void)
754 {
755
756         dmb(sy);
757 }
758
759 #define atomic_add_rel_long             atomic_add_rel_64
760 #define atomic_clear_rel_long           atomic_clear_rel_64
761 #define atomic_cmpset_rel_long          atomic_cmpset_rel_64
762 #define atomic_set_rel_long             atomic_set_rel_64
763 #define atomic_subtract_rel_long        atomic_subtract_rel_64
764 #define atomic_store_rel_long           atomic_store_rel_64
765
766 #define atomic_add_rel_ptr              atomic_add_rel_64
767 #define atomic_clear_rel_ptr            atomic_clear_rel_64
768 #define atomic_cmpset_rel_ptr           atomic_cmpset_rel_64
769 #define atomic_set_rel_ptr              atomic_set_rel_64
770 #define atomic_subtract_rel_ptr         atomic_subtract_rel_64
771 #define atomic_store_rel_ptr            atomic_store_rel_64
772
773 #endif /* _MACHINE_ATOMIC_H_ */
774