xref: /netbsd-src/common/lib/libc/arch/aarch64/atomic/atomic_op_asm.h (revision 65d55bcee11074a60f607dc60b9f22435ed97771)
1 /* $NetBSD: atomic_op_asm.h,v 1.6 2021/07/29 10:29:05 skrll Exp $ */
2 
3 /*-
4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas of 3am Software Foundry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef _ATOMIC_OP_ASM_H_
33 #define	_ATOMIC_OP_ASM_H_
34 
35 #include <machine/asm.h>
36 
37 #define	ATOMIC_OP8(OP, INSN)						\
38 ENTRY_NP(_atomic_##OP##_8)						;\
39 	mov	x4, x0							;\
40 1:	ldxrb	w0, [x4]		/* load old value */		;\
41 	INSN	w2, w0, w1		/* calculate new value */	;\
42 	stxrb	w3, w2, [x4]		/* try to store */		;\
43 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
44 	ret				/* return old value */		;\
45 END(_atomic_##OP##_8)
46 
47 #define	SYNC_FETCH_OP8(OP, INSN)					\
48 ENTRY_NP(__sync_fetch_and_##OP##_1)					;\
49 	mov	x4, x0							;\
50 	dmb	ish							;\
51 1:	ldxrb	w0, [x4]		/* load old value */		;\
52 	INSN	w2, w0, w1		/* calculate new value */	;\
53 	stxrb	w3, w2, [x4]		/* try to store */		;\
54 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
55 	dmb	ish							;\
56 	ret				/* return old value */		;\
57 END(__sync_fetch_and_##OP##_1)
58 
59 #define	ATOMIC_OP8_NV(OP, INSN)						\
60 ENTRY_NP(_atomic_##OP##_8_nv)						;\
61 	mov	x4, x0			/* need x0 for return value */	;\
62 1:	ldxrb	w0, [x4]		/* load old value */		;\
63 	INSN	w0, w0, w1		/* calc new (return) value */	;\
64 	stxrb	w3, w0, [x4]		/* try to store */		;\
65 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
66 	ret				/* return new value */		;\
67 END(_atomic_##OP##_8_nv)
68 
69 #define	SYNC_OP8_FETCH(OP, INSN)					\
70 ENTRY_NP(__sync_##OP##_and_fetch_1)					;\
71 	mov	x4, x0			/* need x0 for return value */	;\
72 	dmb	ish							;\
73 1:	ldxrb	w0, [x4]		/* load old value */		;\
74 	INSN	w0, w0, w1		/* calc new (return) value */	;\
75 	stxrb	w3, w0, [x4]		/* try to store */		;\
76 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
77 	dmb	ish							;\
78 	ret				/* return new value */		;\
79 END(__sync_##OP##_and_fetch_1)
80 
81 #define	ATOMIC_OP16(OP, INSN)						\
82 ENTRY_NP(_atomic_##OP##_16)						;\
83 	mov	x4, x0							;\
84 1:	ldxrh	w0, [x4]		/* load old value */		;\
85 	INSN	w2, w0, w1		/* calculate new value */	;\
86 	stxrh	w3, w2, [x4]		/* try to store */		;\
87 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
88 	ret				/* return old value */		;\
89 END(_atomic_##OP##_16)
90 
91 #define	SYNC_FETCH_OP16(OP, INSN)					\
92 ENTRY_NP(__sync_fetch_and_##OP##_2)					;\
93 	mov	x4, x0							;\
94 	dmb	ish							;\
95 1:	ldxrh	w0, [x4]		/* load old value */		;\
96 	INSN	w2, w0, w1		/* calculate new value */	;\
97 	stxrh	w3, w2, [x4]		/* try to store */		;\
98 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
99 	dmb	ish							;\
100 	ret				/* return old value */		;\
101 END(__sync_fetch_and_##OP##_2)
102 
103 #define	ATOMIC_OP16_NV(OP, INSN)					\
104 ENTRY_NP(_atomic_##OP##_16_nv)						;\
105 	mov	x4, x0			/* need x0 for return value */	;\
106 1:	ldxrh	w0, [x4]		/* load old value */		;\
107 	INSN	w0, w0, w1		/* calc new (return) value */	;\
108 	stxrh	w3, w0, [x4]		/* try to store */		;\
109 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
110 	ret				/* return new value */		;\
111 END(_atomic_##OP##_16_nv)
112 
113 #define	SYNC_OP16_FETCH(OP, INSN)					\
114 ENTRY_NP(__sync__##OP##_and_fetch_2)					;\
115 	mov	x4, x0			/* need x0 for return value */	;\
116 	dmb	ish							;\
117 1:	ldxrh	w0, [x4]		/* load old value */		;\
118 	INSN	w0, w0, w1		/* calc new (return) value */	;\
119 	stxrh	w3, w0, [x4]		/* try to store */		;\
120 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
121 	dmb	ish							;\
122 	ret				/* return new value */		;\
123 END(__sync__##OP##_and_fetch_2)
124 
125 #define	ATOMIC_OP32(OP, INSN)						\
126 ENTRY_NP(_atomic_##OP##_32)						;\
127 	mov	x4, x0							;\
128 1:	ldxr	w0, [x4]		/* load old value */		;\
129 	INSN	w2, w0, w1		/* calculate new value */	;\
130 	stxr	w3, w2, [x4]		/* try to store */		;\
131 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
132 	ret				/* return old value */		;\
133 END(_atomic_##OP##_32)
134 
135 #define	SYNC_FETCH_OP32(OP, INSN)					\
136 ENTRY_NP(__sync_fetch_and_##OP##_4)					;\
137 	mov	x4, x0							;\
138 	dmb	ish							;\
139 1:	ldxr	w0, [x4]		/* load old value */		;\
140 	INSN	w2, w0, w1		/* calculate new value */	;\
141 	stxr	w3, w2, [x4]		/* try to store */		;\
142 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
143 	dmb	ish							;\
144 	ret				/* return old value */		;\
145 END(__sync_fetch_and_##OP##_4)
146 
147 #define	ATOMIC_OP32_NV(OP, INSN)					\
148 ENTRY_NP(_atomic_##OP##_32_nv)						;\
149 	mov	x4, x0			/* need x0 for return value */	;\
150 1:	ldxr	w0, [x4]		/* load old value */		;\
151 	INSN	w0, w0, w1		/* calc new (return) value */	;\
152 	stxr	w3, w0, [x4]		/* try to store */		;\
153 	cbnz	w3, 1b			/*   succeed? no, try again? */	;\
154 	ret				/* return new value */		;\
155 END(_atomic_##OP##_32_nv)
156 
157 #define	SYNC_OP32_FETCH(OP, INSN)					\
158 ENTRY_NP(__sync__##OP##_and_fetch_4)					;\
159 	mov	x4, x0			/* need x0 for return value */	;\
160 	dmb	ish							;\
161 1:	ldxr	w0, [x4]		/* load old value */		;\
162 	INSN	w0, w0, w1		/* calc new (return) value */	;\
163 	stxr	w3, w0, [x4]		/* try to store */		;\
164 	cbnz	w3, 1b			/*   succeed? no, try again? */	;\
165 	dmb	ish							;\
166 	ret				/* return new value */		;\
167 END(__sync__##OP##_and_fetch_4)
168 
169 #define	ATOMIC_OP64(OP, INSN)						\
170 ENTRY_NP(_atomic_##OP##_64)						;\
171 	mov	x4, x0							;\
172 1:	ldxr	x0, [x4]		/* load old value */		;\
173 	INSN	x2, x0, x1		/* calculate new value */	;\
174 	stxr	w3, x2, [x4]		/* try to store */		;\
175 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
176 	ret				/* return old value */		;\
177 END(_atomic_##OP##_64)
178 
179 #define	SYNC_FETCH_OP64(OP, INSN)					\
180 ENTRY_NP(__sync_fetch_and_##OP##_8)					;\
181 	mov	x4, x0							;\
182 	dmb	ish							;\
183 1:	ldxr	x0, [x4]		/* load old value */		;\
184 	INSN	x2, x0, x1		/* calculate new value */	;\
185 	stxr	w3, x2, [x4]		/* try to store */		;\
186 	cbnz	w3, 1b			/*   succeed? no, try again */	;\
187 	dmb	ish							;\
188 	ret				/* return old value */		;\
189 END(__sync_fetch_and_##OP##_8)
190 
191 #define	ATOMIC_OP64_NV(OP, INSN)					\
192 ENTRY_NP(_atomic_##OP##_64_nv)						;\
193 	mov	x4, x0			/* need x0 for return value */	;\
194 1:	ldxr	x0, [x4]		/* load old value */		;\
195 	INSN	x0, x0, x1		/* calc new (return) value */	;\
196 	stxr	w3, x0, [x4]		/* try to store */		;\
197 	cbnz	w3, 1b			/*   succeed? no, try again? */	;\
198 	ret				/* return new value */		;\
199 END(_atomic_##OP##_64_nv)
200 
201 #define	SYNC_OP64_FETCH(OP, INSN)					\
202 ENTRY_NP(__sync_##OP##_and_fetch_8)					;\
203 	mov	x4, x0			/* need x0 for return value */	;\
204 	dmb	ish							;\
205 1:	ldxr	x0, [x4]		/* load old value */		;\
206 	INSN	x0, x0, x1		/* calc new (return) value */	;\
207 	stxr	w3, x0, [x4]		/* try to store */		;\
208 	cbnz	w3, 1b			/*   succeed? no, try again? */	;\
209 	dmb	ish							;\
210 	ret				/* return new value */		;\
211 END(__sync_##OP##_and_fetch_8)
212 
213 #if defined(_KERNEL)
214 
215 #define	ATOMIC_OP_ALIAS(a,s)	STRONG_ALIAS(a,s)
216 
217 #else /* _KERNEL */
218 
219 #define	ATOMIC_OP_ALIAS(a,s)	WEAK_ALIAS(a,s)
220 
221 #endif /* _KERNEL */
222 
223 #endif /* _ATOMIC_OP_ASM_H_ */
224