2 * Copyright (c) 2008 Marcel Moolenaar
3 * Copyright (c) 2001 Benno Rice
4 * Copyright (c) 2001 David E. O'Brien
5 * Copyright (c) 1998 Doug Rabson
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #ifndef _MACHINE_ATOMIC_H_
33 #define _MACHINE_ATOMIC_H_
36 #error this file needs sys/cdefs.h as a prerequisite
40 * The __ATOMIC_REL/ACQ() macros provide memory barriers only in conjunction
41 * with the atomic lXarx/stXcx. sequences below. They are not exposed outside
42 * of this file. See also Appendix B.2 of Book II of the architecture manual.
44 * Note that not all Book-E processors accept the light-weight sync variant.
45 * In particular, early models of E500 cores are known to wedge. Bank on all
46 * 64-bit capable CPUs to accept lwsync properly and pressimize 32-bit CPUs
47 * to use the heavier-weight sync.
51 #define mb() __asm __volatile("sync" : : : "memory")
52 #define rmb() __asm __volatile("lwsync" : : : "memory")
53 #define wmb() __asm __volatile("lwsync" : : : "memory")
54 #define __ATOMIC_REL() __asm __volatile("lwsync" : : : "memory")
55 #define __ATOMIC_ACQ() __asm __volatile("isync" : : : "memory")
57 #define mb() __asm __volatile("sync" : : : "memory")
58 #define rmb() __asm __volatile("sync" : : : "memory")
59 #define wmb() __asm __volatile("sync" : : : "memory")
60 #define __ATOMIC_REL() __asm __volatile("sync" : : : "memory")
61 #define __ATOMIC_ACQ() __asm __volatile("isync" : : : "memory")
69 __asm __volatile("lwsync" : : : "memory");
71 __asm __volatile("sync" : : : "memory");
80 #define __atomic_add_int(p, v, t) \
82 "1: lwarx %0, 0, %2\n" \
84 " stwcx. %0, 0, %2\n" \
86 : "=&r" (t), "=m" (*p) \
87 : "r" (p), "r" (v), "m" (*p) \
89 /* __atomic_add_int */
92 #define __atomic_add_long(p, v, t) \
94 "1: ldarx %0, 0, %2\n" \
96 " stdcx. %0, 0, %2\n" \
98 : "=&r" (t), "=m" (*p) \
99 : "r" (p), "r" (v), "m" (*p) \
101 /* __atomic_add_long */
103 #define __atomic_add_long(p, v, t) \
105 "1: lwarx %0, 0, %2\n" \
106 " add %0, %3, %0\n" \
107 " stwcx. %0, 0, %2\n" \
109 : "=&r" (t), "=m" (*p) \
110 : "r" (p), "r" (v), "m" (*p) \
112 /* __atomic_add_long */
115 #define _ATOMIC_ADD(type) \
116 static __inline void \
117 atomic_add_##type(volatile u_##type *p, u_##type v) { \
119 __atomic_add_##type(p, v, t); \
122 static __inline void \
123 atomic_add_acq_##type(volatile u_##type *p, u_##type v) { \
125 __atomic_add_##type(p, v, t); \
129 static __inline void \
130 atomic_add_rel_##type(volatile u_##type *p, u_##type v) { \
133 __atomic_add_##type(p, v, t); \
140 #define atomic_add_32 atomic_add_int
141 #define atomic_add_acq_32 atomic_add_acq_int
142 #define atomic_add_rel_32 atomic_add_rel_int
145 #define atomic_add_64 atomic_add_long
146 #define atomic_add_acq_64 atomic_add_acq_long
147 #define atomic_add_rel_64 atomic_add_rel_long
149 #define atomic_add_ptr atomic_add_long
150 #define atomic_add_acq_ptr atomic_add_acq_long
151 #define atomic_add_rel_ptr atomic_add_rel_long
153 #define atomic_add_ptr atomic_add_int
154 #define atomic_add_acq_ptr atomic_add_acq_int
155 #define atomic_add_rel_ptr atomic_add_rel_int
158 #undef __atomic_add_long
159 #undef __atomic_add_int
166 #define __atomic_clear_int(p, v, t) \
168 "1: lwarx %0, 0, %2\n" \
169 " andc %0, %0, %3\n" \
170 " stwcx. %0, 0, %2\n" \
172 : "=&r" (t), "=m" (*p) \
173 : "r" (p), "r" (v), "m" (*p) \
175 /* __atomic_clear_int */
178 #define __atomic_clear_long(p, v, t) \
180 "1: ldarx %0, 0, %2\n" \
181 " andc %0, %0, %3\n" \
182 " stdcx. %0, 0, %2\n" \
184 : "=&r" (t), "=m" (*p) \
185 : "r" (p), "r" (v), "m" (*p) \
187 /* __atomic_clear_long */
189 #define __atomic_clear_long(p, v, t) \
191 "1: lwarx %0, 0, %2\n" \
192 " andc %0, %0, %3\n" \
193 " stwcx. %0, 0, %2\n" \
195 : "=&r" (t), "=m" (*p) \
196 : "r" (p), "r" (v), "m" (*p) \
198 /* __atomic_clear_long */
201 #define _ATOMIC_CLEAR(type) \
202 static __inline void \
203 atomic_clear_##type(volatile u_##type *p, u_##type v) { \
205 __atomic_clear_##type(p, v, t); \
208 static __inline void \
209 atomic_clear_acq_##type(volatile u_##type *p, u_##type v) { \
211 __atomic_clear_##type(p, v, t); \
215 static __inline void \
216 atomic_clear_rel_##type(volatile u_##type *p, u_##type v) { \
219 __atomic_clear_##type(p, v, t); \
227 #define atomic_clear_32 atomic_clear_int
228 #define atomic_clear_acq_32 atomic_clear_acq_int
229 #define atomic_clear_rel_32 atomic_clear_rel_int
232 #define atomic_clear_64 atomic_clear_long
233 #define atomic_clear_acq_64 atomic_clear_acq_long
234 #define atomic_clear_rel_64 atomic_clear_rel_long
236 #define atomic_clear_ptr atomic_clear_long
237 #define atomic_clear_acq_ptr atomic_clear_acq_long
238 #define atomic_clear_rel_ptr atomic_clear_rel_long
240 #define atomic_clear_ptr atomic_clear_int
241 #define atomic_clear_acq_ptr atomic_clear_acq_int
242 #define atomic_clear_rel_ptr atomic_clear_rel_int
245 #undef __atomic_clear_long
246 #undef __atomic_clear_int
249 * atomic_cmpset(p, o, n)
251 /* TODO -- see below */
256 /* TODO -- see below */
259 * atomic_readandclear(p)
261 /* TODO -- see below */
268 #define __atomic_set_int(p, v, t) \
270 "1: lwarx %0, 0, %2\n" \
272 " stwcx. %0, 0, %2\n" \
274 : "=&r" (t), "=m" (*p) \
275 : "r" (p), "r" (v), "m" (*p) \
277 /* __atomic_set_int */
280 #define __atomic_set_long(p, v, t) \
282 "1: ldarx %0, 0, %2\n" \
284 " stdcx. %0, 0, %2\n" \
286 : "=&r" (t), "=m" (*p) \
287 : "r" (p), "r" (v), "m" (*p) \
289 /* __atomic_set_long */
291 #define __atomic_set_long(p, v, t) \
293 "1: lwarx %0, 0, %2\n" \
295 " stwcx. %0, 0, %2\n" \
297 : "=&r" (t), "=m" (*p) \
298 : "r" (p), "r" (v), "m" (*p) \
300 /* __atomic_set_long */
303 #define _ATOMIC_SET(type) \
304 static __inline void \
305 atomic_set_##type(volatile u_##type *p, u_##type v) { \
307 __atomic_set_##type(p, v, t); \
310 static __inline void \
311 atomic_set_acq_##type(volatile u_##type *p, u_##type v) { \
313 __atomic_set_##type(p, v, t); \
317 static __inline void \
318 atomic_set_rel_##type(volatile u_##type *p, u_##type v) { \
321 __atomic_set_##type(p, v, t); \
328 #define atomic_set_32 atomic_set_int
329 #define atomic_set_acq_32 atomic_set_acq_int
330 #define atomic_set_rel_32 atomic_set_rel_int
333 #define atomic_set_64 atomic_set_long
334 #define atomic_set_acq_64 atomic_set_acq_long
335 #define atomic_set_rel_64 atomic_set_rel_long
337 #define atomic_set_ptr atomic_set_long
338 #define atomic_set_acq_ptr atomic_set_acq_long
339 #define atomic_set_rel_ptr atomic_set_rel_long
341 #define atomic_set_ptr atomic_set_int
342 #define atomic_set_acq_ptr atomic_set_acq_int
343 #define atomic_set_rel_ptr atomic_set_rel_int
346 #undef __atomic_set_long
347 #undef __atomic_set_int
350 * atomic_subtract(p, v)
354 #define __atomic_subtract_int(p, v, t) \
356 "1: lwarx %0, 0, %2\n" \
357 " subf %0, %3, %0\n" \
358 " stwcx. %0, 0, %2\n" \
360 : "=&r" (t), "=m" (*p) \
361 : "r" (p), "r" (v), "m" (*p) \
363 /* __atomic_subtract_int */
366 #define __atomic_subtract_long(p, v, t) \
368 "1: ldarx %0, 0, %2\n" \
369 " subf %0, %3, %0\n" \
370 " stdcx. %0, 0, %2\n" \
372 : "=&r" (t), "=m" (*p) \
373 : "r" (p), "r" (v), "m" (*p) \
375 /* __atomic_subtract_long */
377 #define __atomic_subtract_long(p, v, t) \
379 "1: lwarx %0, 0, %2\n" \
380 " subf %0, %3, %0\n" \
381 " stwcx. %0, 0, %2\n" \
383 : "=&r" (t), "=m" (*p) \
384 : "r" (p), "r" (v), "m" (*p) \
386 /* __atomic_subtract_long */
389 #define _ATOMIC_SUBTRACT(type) \
390 static __inline void \
391 atomic_subtract_##type(volatile u_##type *p, u_##type v) { \
393 __atomic_subtract_##type(p, v, t); \
396 static __inline void \
397 atomic_subtract_acq_##type(volatile u_##type *p, u_##type v) { \
399 __atomic_subtract_##type(p, v, t); \
403 static __inline void \
404 atomic_subtract_rel_##type(volatile u_##type *p, u_##type v) { \
407 __atomic_subtract_##type(p, v, t); \
409 /* _ATOMIC_SUBTRACT */
411 _ATOMIC_SUBTRACT(int)
412 _ATOMIC_SUBTRACT(long)
414 #define atomic_subtract_32 atomic_subtract_int
415 #define atomic_subtract_acq_32 atomic_subtract_acq_int
416 #define atomic_subtract_rel_32 atomic_subtract_rel_int
419 #define atomic_subtract_64 atomic_subtract_long
420 #define atomic_subtract_acq_64 atomic_subract_acq_long
421 #define atomic_subtract_rel_64 atomic_subtract_rel_long
423 #define atomic_subtract_ptr atomic_subtract_long
424 #define atomic_subtract_acq_ptr atomic_subtract_acq_long
425 #define atomic_subtract_rel_ptr atomic_subtract_rel_long
427 #define atomic_subtract_ptr atomic_subtract_int
428 #define atomic_subtract_acq_ptr atomic_subtract_acq_int
429 #define atomic_subtract_rel_ptr atomic_subtract_rel_int
431 #undef _ATOMIC_SUBTRACT
432 #undef __atomic_subtract_long
433 #undef __atomic_subtract_int
436 * atomic_store_rel(p, v)
438 /* TODO -- see below */
441 * Old/original implementations that still need revisiting.
444 static __inline u_int
445 atomic_readandclear_int(volatile u_int *addr)
450 "\tsync\n" /* drain writes */
451 "1:\tlwarx %0, 0, %3\n\t" /* load old value */
452 "li %1, 0\n\t" /* load new value */
453 "stwcx. %1, 0, %3\n\t" /* attempt to store */
454 "bne- 1b\n\t" /* spin if failed */
455 : "=&r"(result), "=&r"(temp), "=m" (*addr)
456 : "r" (addr), "m" (*addr)
463 static __inline u_long
464 atomic_readandclear_long(volatile u_long *addr)
469 "\tsync\n" /* drain writes */
470 "1:\tldarx %0, 0, %3\n\t" /* load old value */
471 "li %1, 0\n\t" /* load new value */
472 "stdcx. %1, 0, %3\n\t" /* attempt to store */
473 "bne- 1b\n\t" /* spin if failed */
474 : "=&r"(result), "=&r"(temp), "=m" (*addr)
475 : "r" (addr), "m" (*addr)
482 #define atomic_readandclear_32 atomic_readandclear_int
485 #define atomic_readandclear_64 atomic_readandclear_long
487 #define atomic_readandclear_ptr atomic_readandclear_long
489 static __inline u_long
490 atomic_readandclear_long(volatile u_long *addr)
493 return ((u_long)atomic_readandclear_int((volatile u_int *)addr));
496 #define atomic_readandclear_ptr atomic_readandclear_int
500 * We assume that a = b will do atomic loads and stores.
502 #define ATOMIC_STORE_LOAD(TYPE) \
503 static __inline u_##TYPE \
504 atomic_load_acq_##TYPE(volatile u_##TYPE *p) \
513 static __inline void \
514 atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v) \
521 ATOMIC_STORE_LOAD(int)
523 #define atomic_load_acq_32 atomic_load_acq_int
524 #define atomic_store_rel_32 atomic_store_rel_int
527 ATOMIC_STORE_LOAD(long)
529 #define atomic_load_acq_64 atomic_load_acq_long
530 #define atomic_store_rel_64 atomic_store_rel_long
532 #define atomic_load_acq_ptr atomic_load_acq_long
533 #define atomic_store_rel_ptr atomic_store_rel_long
535 static __inline u_long
536 atomic_load_acq_long(volatile u_long *addr)
539 return ((u_long)atomic_load_acq_int((volatile u_int *)addr));
543 atomic_store_rel_long(volatile u_long *addr, u_long val)
546 atomic_store_rel_int((volatile u_int *)addr, (u_int)val);
549 #define atomic_load_acq_ptr atomic_load_acq_int
550 #define atomic_store_rel_ptr atomic_store_rel_int
552 #undef ATOMIC_STORE_LOAD
555 * Atomically compare the value stored at *p with cmpval and if the
556 * two values are equal, update the value of *p with newval. Returns
557 * zero if the compare failed, nonzero otherwise.
560 atomic_cmpset_int(volatile u_int* p, u_int cmpval, u_int newval)
565 "1:\tlwarx %0, 0, %2\n\t" /* load old value */
566 "cmplw %3, %0\n\t" /* compare */
567 "bne 2f\n\t" /* exit if not equal */
568 "stwcx. %4, 0, %2\n\t" /* attempt to store */
569 "bne- 1b\n\t" /* spin if failed */
570 "li %0, 1\n\t" /* success - retval = 1 */
571 "b 3f\n\t" /* we've succeeded */
573 "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
574 "li %0, 0\n\t" /* failure - retval = 0 */
576 : "=&r" (ret), "=m" (*p)
577 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
583 atomic_cmpset_long(volatile u_long* p, u_long cmpval, u_long newval)
589 "1:\tldarx %0, 0, %2\n\t" /* load old value */
590 "cmpld %3, %0\n\t" /* compare */
591 "bne 2f\n\t" /* exit if not equal */
592 "stdcx. %4, 0, %2\n\t" /* attempt to store */
594 "1:\tlwarx %0, 0, %2\n\t" /* load old value */
595 "cmplw %3, %0\n\t" /* compare */
596 "bne 2f\n\t" /* exit if not equal */
597 "stwcx. %4, 0, %2\n\t" /* attempt to store */
599 "bne- 1b\n\t" /* spin if failed */
600 "li %0, 1\n\t" /* success - retval = 1 */
601 "b 3f\n\t" /* we've succeeded */
604 "stdcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
606 "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
608 "li %0, 0\n\t" /* failure - retval = 0 */
610 : "=&r" (ret), "=m" (*p)
611 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
618 atomic_cmpset_acq_int(volatile u_int *p, u_int cmpval, u_int newval)
622 retval = atomic_cmpset_int(p, cmpval, newval);
628 atomic_cmpset_rel_int(volatile u_int *p, u_int cmpval, u_int newval)
631 return (atomic_cmpset_int(p, cmpval, newval));
635 atomic_cmpset_acq_long(volatile u_long *p, u_long cmpval, u_long newval)
639 retval = atomic_cmpset_long(p, cmpval, newval);
645 atomic_cmpset_rel_long(volatile u_long *p, u_long cmpval, u_long newval)
648 return (atomic_cmpset_long(p, cmpval, newval));
651 #define atomic_cmpset_32 atomic_cmpset_int
652 #define atomic_cmpset_acq_32 atomic_cmpset_acq_int
653 #define atomic_cmpset_rel_32 atomic_cmpset_rel_int
656 #define atomic_cmpset_64 atomic_cmpset_long
657 #define atomic_cmpset_acq_64 atomic_cmpset_acq_long
658 #define atomic_cmpset_rel_64 atomic_cmpset_rel_long
660 #define atomic_cmpset_ptr atomic_cmpset_long
661 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_long
662 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_long
664 #define atomic_cmpset_ptr atomic_cmpset_int
665 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_int
666 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_int
670 * Atomically compare the value stored at *p with *cmpval and if the
671 * two values are equal, update the value of *p with newval. Returns
672 * zero if the compare failed and sets *cmpval to the read value from *p,
676 atomic_fcmpset_int(volatile u_int *p, u_int *cmpval, u_int newval)
681 "lwarx %0, 0, %3\n\t" /* load old value */
682 "cmplw %4, %0\n\t" /* compare */
683 "bne 1f\n\t" /* exit if not equal */
684 "stwcx. %5, 0, %3\n\t" /* attempt to store */
685 "bne- 1f\n\t" /* exit if failed */
686 "li %0, 1\n\t" /* success - retval = 1 */
687 "b 2f\n\t" /* we've succeeded */
689 "stwcx. %0, 0, %3\n\t" /* clear reservation (74xx) */
691 "li %0, 0\n\t" /* failure - retval = 0 */
693 : "=&r" (ret), "=m" (*p), "=m" (*cmpval)
694 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
700 atomic_fcmpset_long(volatile u_long *p, u_long *cmpval, u_long newval)
706 "ldarx %0, 0, %3\n\t" /* load old value */
707 "cmpld %4, %0\n\t" /* compare */
708 "bne 1f\n\t" /* exit if not equal */
709 "stdcx. %5, 0, %3\n\t" /* attempt to store */
711 "lwarx %0, 0, %3\n\t" /* load old value */
712 "cmplw %4, %0\n\t" /* compare */
713 "bne 1f\n\t" /* exit if not equal */
714 "stwcx. %5, 0, %3\n\t" /* attempt to store */
716 "bne- 1f\n\t" /* exit if failed */
717 "li %0, 1\n\t" /* success - retval = 1 */
718 "b 2f\n\t" /* we've succeeded */
721 "stdcx. %0, 0, %3\n\t" /* clear reservation (74xx) */
724 "stwcx. %0, 0, %3\n\t" /* clear reservation (74xx) */
727 "li %0, 0\n\t" /* failure - retval = 0 */
729 : "=&r" (ret), "=m" (*p), "=m" (*cmpval)
730 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
737 atomic_fcmpset_acq_int(volatile u_int *p, u_int *cmpval, u_int newval)
741 retval = atomic_fcmpset_int(p, cmpval, newval);
747 atomic_fcmpset_rel_int(volatile u_int *p, u_int *cmpval, u_int newval)
750 return (atomic_fcmpset_int(p, cmpval, newval));
754 atomic_fcmpset_acq_long(volatile u_long *p, u_long *cmpval, u_long newval)
758 retval = atomic_fcmpset_long(p, cmpval, newval);
764 atomic_fcmpset_rel_long(volatile u_long *p, u_long *cmpval, u_long newval)
767 return (atomic_fcmpset_long(p, cmpval, newval));
770 #define atomic_fcmpset_32 atomic_fcmpset_int
771 #define atomic_fcmpset_acq_32 atomic_fcmpset_acq_int
772 #define atomic_fcmpset_rel_32 atomic_fcmpset_rel_int
775 #define atomic_fcmpset_64 atomic_fcmpset_long
776 #define atomic_fcmpset_acq_64 atomic_fcmpset_acq_long
777 #define atomic_fcmpset_rel_64 atomic_fcmpset_rel_long
779 #define atomic_fcmpset_ptr atomic_fcmpset_long
780 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_long
781 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_long
783 #define atomic_fcmpset_ptr atomic_fcmpset_int
784 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_int
785 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_int
788 static __inline u_int
789 atomic_fetchadd_int(volatile u_int *p, u_int v)
795 } while (!atomic_cmpset_int(p, value, value + v));
799 static __inline u_long
800 atomic_fetchadd_long(volatile u_long *p, u_long v)
806 } while (!atomic_cmpset_long(p, value, value + v));
810 static __inline u_int
811 atomic_swap_32(volatile u_int *p, u_int v)
819 : "=&r" (prev), "+m" (*(volatile u_int *)p)
827 static __inline u_long
828 atomic_swap_64(volatile u_long *p, u_long v)
836 : "=&r" (prev), "+m" (*(volatile u_long *)p)
844 #define atomic_fetchadd_32 atomic_fetchadd_int
845 #define atomic_swap_int atomic_swap_32
848 #define atomic_fetchadd_64 atomic_fetchadd_long
849 #define atomic_swap_long atomic_swap_64
850 #define atomic_swap_ptr atomic_swap_64
857 atomic_thread_fence_acq(void)
864 atomic_thread_fence_rel(void)
871 atomic_thread_fence_acq_rel(void)
878 atomic_thread_fence_seq_cst(void)
881 __asm __volatile("sync" : : : "memory");
884 #endif /* ! _MACHINE_ATOMIC_H_ */