1 /* $OpenBSD: atomic.h,v 1.12 2014/03/29 18:09:28 guenther Exp $ */
2 /* $NetBSD: atomic.h,v 1.7 2001/12/17 23:34:57 thorpej Exp $ */
3
4 /*-
5 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Misc. `atomic' operations.
36 */
37
38 #ifndef _MACHINE_ATOMIC_H_
39 #define _MACHINE_ATOMIC_H_
40
41 #if defined(_KERNEL)
42
43 /*
44 * atomic_setbits_ulong:
45 *
46 * Atomically set bits in a `unsigned long'.
47 */
48 static __inline void
atomic_setbits_ulong(volatile unsigned long * ulp,unsigned long v)49 atomic_setbits_ulong(volatile unsigned long *ulp, unsigned long v)
50 {
51 unsigned long t0;
52
53 __asm volatile(
54 "# BEGIN atomic_setbits_ulong\n"
55 "1: ldq_l %0, %1 \n"
56 " or %0, %2, %0 \n"
57 " stq_c %0, %1 \n"
58 " beq %0, 2f \n"
59 " mb \n"
60 " br 3f \n"
61 "2: br 1b \n"
62 "3: \n"
63 " # END atomic_setbits_ulong"
64 : "=&r" (t0), "=m" (*ulp)
65 : "r" (v)
66 : "memory");
67 }
68
69 /*
70 * atomic_clearbits_ulong:
71 *
72 * Atomically clear bits in a `unsigned long'.
73 */
74 static __inline void
atomic_clearbits_ulong(volatile unsigned long * ulp,unsigned long v)75 atomic_clearbits_ulong(volatile unsigned long *ulp, unsigned long v)
76 {
77 unsigned long t0;
78
79 __asm volatile(
80 "# BEGIN atomic_clearbits_ulong\n"
81 "1: ldq_l %0, %1 \n"
82 " and %0, %2, %0 \n"
83 " stq_c %0, %1 \n"
84 " beq %0, 2f \n"
85 " mb \n"
86 " br 3f \n"
87 "2: br 1b \n"
88 "3: \n"
89 " # END atomic_clearbits_ulong"
90 : "=&r" (t0), "=m" (*ulp)
91 : "r" (~v)
92 : "memory");
93 }
94
95 /*
96 * atomic_add_ulong:
97 *
98 * Atomically add a value to a `unsigned long'.
99 */
100 static __inline void
atomic_add_ulong(volatile unsigned long * ulp,unsigned long v)101 atomic_add_ulong(volatile unsigned long *ulp, unsigned long v)
102 {
103 unsigned long t0;
104
105 __asm volatile(
106 "# BEGIN atomic_add_ulong\n"
107 "1: ldq_l %0, %1 \n"
108 " addq %0, %2, %0 \n"
109 " stq_c %0, %1 \n"
110 " beq %0, 2f \n"
111 " mb \n"
112 " br 3f \n"
113 "2: br 1b \n"
114 "3: \n"
115 " # END atomic_add_ulong"
116 : "=&r" (t0), "=m" (*ulp)
117 : "r" (v)
118 : "memory");
119 }
120
121 /*
122 * atomic_sub_ulong:
123 *
124 * Atomically subtract a value from a `unsigned long'.
125 */
126 static __inline void
atomic_sub_ulong(volatile unsigned long * ulp,unsigned long v)127 atomic_sub_ulong(volatile unsigned long *ulp, unsigned long v)
128 {
129 unsigned long t0;
130
131 __asm volatile(
132 "# BEGIN atomic_sub_ulong\n"
133 "1: ldq_l %0, %1 \n"
134 " subq %0, %2, %0 \n"
135 " stq_c %0, %1 \n"
136 " beq %0, 2f \n"
137 " mb \n"
138 " br 3f \n"
139 "2: br 1b \n"
140 "3: \n"
141 " # END atomic_sub_ulong"
142 : "=&r" (t0), "=m" (*ulp)
143 : "r" (v)
144 : "memory");
145 }
146
147 /*
148 * atomic_loadlatch_ulong:
149 *
150 * Atomically load and latch a `unsigned long' value.
151 */
152 static __inline unsigned long
atomic_loadlatch_ulong(volatile unsigned long * ulp,unsigned long v)153 atomic_loadlatch_ulong(volatile unsigned long *ulp, unsigned long v)
154 {
155 unsigned long t0, v0;
156
157 __asm volatile(
158 "# BEGIN atomic_loadlatch_ulong\n"
159 "1: mov %3, %0 \n"
160 " ldq_l %1, %2 \n"
161 " stq_c %0, %2 \n"
162 " beq %0, 2f \n"
163 " mb \n"
164 " br 3f \n"
165 "2: br 1b \n"
166 "3: \n"
167 " # END atomic_loadlatch_ulong"
168 : "=&r" (t0), "=r" (v0), "=m" (*ulp)
169 : "r" (v)
170 : "memory");
171
172 return (v0);
173 }
174
175 /*
176 * atomic_setbits_int:
177 *
178 * Atomically set bits in a `unsigned int'.
179 */
180 static __inline void
atomic_setbits_int(volatile unsigned int * uip,unsigned int v)181 atomic_setbits_int(volatile unsigned int *uip, unsigned int v)
182 {
183 unsigned int t0;
184
185 __asm volatile(
186 "# BEGIN atomic_setbits_ulong\n"
187 "1: ldl_l %0, %1 \n"
188 " or %0, %2, %0 \n"
189 " stl_c %0, %1 \n"
190 " beq %0, 2f \n"
191 " mb \n"
192 " br 3f \n"
193 "2: br 1b \n"
194 "3: \n"
195 " # END atomic_setbits_int"
196 : "=&r" (t0), "=m" (*uip)
197 : "r" (v)
198 : "memory");
199 }
200
201 /*
202 * atomic_clearbits_int:
203 *
204 * Atomically clear bits in a `unsigned int'.
205 */
206 static __inline void
atomic_clearbits_int(volatile unsigned int * uip,unsigned int v)207 atomic_clearbits_int(volatile unsigned int *uip, unsigned int v)
208 {
209 unsigned int t0;
210
211 __asm volatile(
212 "# BEGIN atomic_clearbits_int\n"
213 "1: ldl_l %0, %1 \n"
214 " and %0, %2, %0 \n"
215 " stl_c %0, %1 \n"
216 " beq %0, 2f \n"
217 " mb \n"
218 " br 3f \n"
219 "2: br 1b \n"
220 "3: \n"
221 " # END atomic_clearbits_int"
222 : "=&r" (t0), "=m" (*uip)
223 : "r" (~v)
224 : "memory");
225 }
226
227 /*
228 * atomic_add_int:
229 *
230 * Atomically add a value to an `int'.
231 */
232 static __inline void
atomic_add_int(volatile int * ulp,int v)233 atomic_add_int(volatile int *ulp, int v)
234 {
235 unsigned long t0;
236
237 __asm volatile(
238 "# BEGIN atomic_add_int\n"
239 "1: ldl_l %0, %1 \n"
240 " addl %0, %2, %0 \n"
241 " stl_c %0, %1 \n"
242 " beq %0, 2f \n"
243 " mb \n"
244 " br 3f \n"
245 "2: br 1b \n"
246 "3: \n"
247 " # END atomic_add_ulong"
248 : "=&r" (t0), "=m" (*ulp)
249 : "r" (v)
250 : "memory");
251 }
252
253 #endif /* defined(_KERNEL) */
254 #endif /* _MACHINE_ATOMIC_H_ */
255