]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/alpha/include/atomic.h
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / alpha / include / atomic.h
1 /*-
2  * Copyright (c) 1998 Doug Rabson
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 #ifndef _SYS_CDEFS_H_
33 #error this file needs sys/cdefs.h as a prerequisite
34 #endif
35
36 #include <machine/alpha_cpu.h>
37
38 /*
39  * Various simple arithmetic on memory which is atomic in the presence
40  * of interrupts and SMP safe.
41  */
42
43 void atomic_set_8(volatile u_int8_t *, u_int8_t);
44 void atomic_clear_8(volatile u_int8_t *, u_int8_t);
45 void atomic_add_8(volatile u_int8_t *, u_int8_t);
46 void atomic_subtract_8(volatile u_int8_t *, u_int8_t);
47
48 void atomic_set_16(volatile u_int16_t *, u_int16_t);
49 void atomic_clear_16(volatile u_int16_t *, u_int16_t);
50 void atomic_add_16(volatile u_int16_t *, u_int16_t);
51 void atomic_subtract_16(volatile u_int16_t *, u_int16_t);
52
53 static __inline void atomic_set_32(volatile u_int32_t *p, u_int32_t v)
54 {
55         u_int32_t temp;
56
57 #ifdef __GNUCLIKE_ASM
58         __asm __volatile (
59                 "1:\tldl_l %0, %3\n\t"          /* load old value */
60                 "bis %0, %2, %0\n\t"            /* calculate new value */
61                 "stl_c %0, %1\n\t"              /* attempt to store */
62                 "beq %0, 1b\n"                  /* spin if failed */
63                 : "=&r" (temp), "=m" (*p)
64                 : "r" (v), "m" (*p)
65                 : "memory");
66 #endif
67 }
68
69 static __inline void atomic_clear_32(volatile u_int32_t *p, u_int32_t v)
70 {
71         u_int32_t temp;
72
73 #ifdef __GNUCLIKE_ASM
74         __asm __volatile (
75                 "1:\tldl_l %0, %3\n\t"          /* load old value */
76                 "bic %0, %2, %0\n\t"            /* calculate new value */
77                 "stl_c %0, %1\n\t"              /* attempt to store */
78                 "beq %0, 1b\n"                  /* spin if failed */
79                 : "=&r" (temp), "=m" (*p)
80                 : "r" (v), "m" (*p)
81                 : "memory");
82 #endif
83 }
84
85 static __inline void atomic_add_32(volatile u_int32_t *p, u_int32_t v)
86 {
87         u_int32_t temp;
88
89 #ifdef __GNUCLIKE_ASM
90         __asm __volatile (
91                 "1:\tldl_l %0, %3\n\t"          /* load old value */
92                 "addl %0, %2, %0\n\t"           /* calculate new value */
93                 "stl_c %0, %1\n\t"              /* attempt to store */
94                 "beq %0, 1b\n"                  /* spin if failed */
95                 : "=&r" (temp), "=m" (*p)
96                 : "r" (v), "m" (*p)
97                 : "memory");
98 #endif
99 }
100
101 static __inline void atomic_subtract_32(volatile u_int32_t *p, u_int32_t v)
102 {
103         u_int32_t temp;
104
105 #ifdef __GNUCLIKE_ASM
106         __asm __volatile (
107                 "1:\tldl_l %0, %3\n\t"          /* load old value */
108                 "subl %0, %2, %0\n\t"           /* calculate new value */
109                 "stl_c %0, %1\n\t"              /* attempt to store */
110                 "beq %0, 1b\n"                  /* spin if failed */
111                 : "=&r" (temp), "=m" (*p)
112                 : "r" (v), "m" (*p)
113                 : "memory");
114 #endif
115 }
116
117 static __inline u_int32_t atomic_readandclear_32(volatile u_int32_t *addr)
118 {
119         u_int32_t result,temp;
120
121 #ifdef __GNUCLIKE_ASM
122         __asm __volatile (
123                 "wmb\n"                 /* ensure pending writes have drained */
124                 "1:\tldl_l %0,%3\n\t"   /* load current value, asserting lock */
125                 "ldiq %1,0\n\t"         /* value to store */
126                 "stl_c %1,%2\n\t"       /* attempt to store */
127                 "beq %1,1b\n"           /* if the store failed, spin */
128                 : "=&r"(result), "=&r"(temp), "=m" (*addr)
129                 : "m" (*addr)
130                 : "memory");
131 #endif
132
133         return result;
134 }
135
136 static __inline void atomic_set_64(volatile u_int64_t *p, u_int64_t v)
137 {
138         u_int64_t temp;
139
140 #ifdef __GNUCLIKE_ASM
141         __asm __volatile (
142                 "1:\tldq_l %0, %3\n\t"          /* load old value */
143                 "bis %0, %2, %0\n\t"            /* calculate new value */
144                 "stq_c %0, %1\n\t"              /* attempt to store */
145                 "beq %0, 1b\n"                  /* spin if failed */
146                 : "=&r" (temp), "=m" (*p)
147                 : "r" (v), "m" (*p)
148                 : "memory");
149 #endif
150 }
151
152 static __inline void atomic_clear_64(volatile u_int64_t *p, u_int64_t v)
153 {
154         u_int64_t temp;
155
156 #ifdef __GNUCLIKE_ASM
157         __asm __volatile (
158                 "1:\tldq_l %0, %3\n\t"          /* load old value */
159                 "bic %0, %2, %0\n\t"            /* calculate new value */
160                 "stq_c %0, %1\n\t"              /* attempt to store */
161                 "beq %0, 1b\n"                  /* spin if failed */
162                 : "=&r" (temp), "=m" (*p)
163                 : "r" (v), "m" (*p)
164                 : "memory");
165 #endif
166 }
167
168 static __inline void atomic_add_64(volatile u_int64_t *p, u_int64_t v)
169 {
170         u_int64_t temp;
171
172 #ifdef __GNUCLIKE_ASM
173         __asm __volatile (
174                 "1:\tldq_l %0, %3\n\t"          /* load old value */
175                 "addq %0, %2, %0\n\t"           /* calculate new value */
176                 "stq_c %0, %1\n\t"              /* attempt to store */
177                 "beq %0, 1b\n"                  /* spin if failed */
178                 : "=&r" (temp), "=m" (*p)
179                 : "r" (v), "m" (*p)
180                 : "memory");
181 #endif
182 }
183
184 static __inline void atomic_subtract_64(volatile u_int64_t *p, u_int64_t v)
185 {
186         u_int64_t temp;
187
188 #ifdef __GNUCLIKE_ASM
189         __asm __volatile (
190                 "1:\tldq_l %0, %3\n\t"          /* load old value */
191                 "subq %0, %2, %0\n\t"           /* calculate new value */
192                 "stq_c %0, %1\n\t"              /* attempt to store */
193                 "beq %0, 1b\n"                  /* spin if failed */
194                 : "=&r" (temp), "=m" (*p)
195                 : "r" (v), "m" (*p)
196                 : "memory");
197 #endif
198 }
199
200 static __inline u_int64_t atomic_readandclear_64(volatile u_int64_t *addr)
201 {
202         u_int64_t result,temp;
203
204 #ifdef __GNUCLIKE_ASM
205         __asm __volatile (
206                 "wmb\n"                 /* ensure pending writes have drained */
207                 "1:\tldq_l %0,%3\n\t"   /* load current value, asserting lock */
208                 "ldiq %1,0\n\t"         /* value to store */
209                 "stq_c %1,%2\n\t"       /* attempt to store */
210                 "beq %1,1b\n"           /* if the store failed, spin */
211                 : "=&r"(result), "=&r"(temp), "=m" (*addr)
212                 : "m" (*addr)
213                 : "memory");
214 #endif
215
216         return result;
217 }
218
219 #define ATOMIC_ACQ_REL(NAME, WIDTH)                                     \
220 static __inline void                                                    \
221 atomic_##NAME##_acq_##WIDTH(volatile u_int##WIDTH##_t *p, u_int##WIDTH##_t v)\
222 {                                                                       \
223         atomic_##NAME##_##WIDTH(p, v);                                  \
224         alpha_mb();                                                     \
225 }                                                                       \
226                                                                         \
227 static __inline void                                                    \
228 atomic_##NAME##_rel_##WIDTH(volatile u_int##WIDTH##_t *p, u_int##WIDTH##_t v)\
229 {                                                                       \
230         alpha_mb();                                                     \
231         atomic_##NAME##_##WIDTH(p, v);                                  \
232 }
233
234 /* Variants of simple arithmetic with memory barriers. */
235 ATOMIC_ACQ_REL(set, 8)
236 ATOMIC_ACQ_REL(clear, 8)
237 ATOMIC_ACQ_REL(add, 8)
238 ATOMIC_ACQ_REL(subtract, 8)
239 ATOMIC_ACQ_REL(set, 16)
240 ATOMIC_ACQ_REL(clear, 16)
241 ATOMIC_ACQ_REL(add, 16)
242 ATOMIC_ACQ_REL(subtract, 16)
243 ATOMIC_ACQ_REL(set, 32)
244 ATOMIC_ACQ_REL(clear, 32)
245 ATOMIC_ACQ_REL(add, 32)
246 ATOMIC_ACQ_REL(subtract, 32)
247 ATOMIC_ACQ_REL(set, 64)
248 ATOMIC_ACQ_REL(clear, 64)
249 ATOMIC_ACQ_REL(add, 64)
250 ATOMIC_ACQ_REL(subtract, 64)
251
252 #undef ATOMIC_ACQ_REL
253
254 /*
255  * We assume that a = b will do atomic loads and stores.
256  */
257 #define ATOMIC_STORE_LOAD(WIDTH)                        \
258 static __inline u_int##WIDTH##_t                        \
259 atomic_load_acq_##WIDTH(volatile u_int##WIDTH##_t *p)   \
260 {                                                       \
261         u_int##WIDTH##_t v;                             \
262                                                         \
263         v = *p;                                         \
264         alpha_mb();                                     \
265         return (v);                                     \
266 }                                                       \
267                                                         \
268 static __inline void                                    \
269 atomic_store_rel_##WIDTH(volatile u_int##WIDTH##_t *p, u_int##WIDTH##_t v)\
270 {                                                       \
271         alpha_mb();                                     \
272         *p = v;                                         \
273 }
274
275 ATOMIC_STORE_LOAD(32)
276 ATOMIC_STORE_LOAD(64)
277
278 #undef ATOMIC_STORE_LOAD
279
280 /*
281  * Atomically compare the value stored at *p with cmpval and if the
282  * two values are equal, update the value of *p with newval. Returns
283  * zero if the compare failed, nonzero otherwise.
284  */
285 static __inline u_int32_t
286 atomic_cmpset_32(volatile u_int32_t* p, u_int32_t cmpval, u_int32_t newval)
287 {
288         u_int32_t ret;
289
290 #ifdef __GNUCLIKE_ASM
291         __asm __volatile (
292                 "1:\tldl_l %0, %4\n\t"          /* load old value */
293                 "cmpeq %0, %2, %0\n\t"          /* compare */
294                 "beq %0, 2f\n\t"                /* exit if not equal */
295                 "mov %3, %0\n\t"                /* value to store */
296                 "stl_c %0, %1\n\t"              /* attempt to store */
297                 "beq %0, 1b\n\t"                /* if it failed, spin */
298                 "2:\n"
299                 : "=&r" (ret), "=m" (*p)
300                 : "r" ((long)(int)cmpval), "r" (newval), "m" (*p)
301                 : "memory");
302 #endif
303
304         return ret;
305 }
306
307 /*
308  * Atomically compare the value stored at *p with cmpval and if the
309  * two values are equal, update the value of *p with newval. Returns
310  * zero if the compare failed, nonzero otherwise.
311  */
312 static __inline u_int64_t
313 atomic_cmpset_64(volatile u_int64_t* p, u_int64_t cmpval, u_int64_t newval)
314 {
315         u_int64_t ret;
316
317 #ifdef __GNUCLIKE_ASM
318         __asm __volatile (
319                 "1:\tldq_l %0, %4\n\t"          /* load old value */
320                 "cmpeq %0, %2, %0\n\t"          /* compare */
321                 "beq %0, 2f\n\t"                /* exit if not equal */
322                 "mov %3, %0\n\t"                /* value to store */
323                 "stq_c %0, %1\n\t"              /* attempt to store */
324                 "beq %0, 1b\n\t"                /* if it failed, spin */
325                 "2:\n"
326                 : "=&r" (ret), "=m" (*p)
327                 : "r" (cmpval), "r" (newval), "m" (*p)
328                 : "memory");
329 #endif
330
331         return ret;
332 }
333
334 static __inline u_int32_t
335 atomic_cmpset_acq_32(volatile u_int32_t *p, u_int32_t cmpval, u_int32_t newval)
336 {
337         int retval;
338
339         retval = atomic_cmpset_32(p, cmpval, newval);
340         alpha_mb();
341         return (retval);
342 }
343
344 static __inline u_int32_t
345 atomic_cmpset_rel_32(volatile u_int32_t *p, u_int32_t cmpval, u_int32_t newval)
346 {
347         alpha_mb();
348         return (atomic_cmpset_32(p, cmpval, newval));
349 }
350
351 static __inline u_int64_t
352 atomic_cmpset_acq_64(volatile u_int64_t *p, u_int64_t cmpval, u_int64_t newval)
353 {
354         int retval;
355
356         retval = atomic_cmpset_64(p, cmpval, newval);
357         alpha_mb();
358         return (retval);
359 }
360
361 static __inline u_int64_t
362 atomic_cmpset_rel_64(volatile u_int64_t *p, u_int64_t cmpval, u_int64_t newval)
363 {
364         alpha_mb();
365         return (atomic_cmpset_64(p, cmpval, newval));
366 }
367
368 /*
369  * Atomically add the value of v to the integer pointed to by p and return
370  * the previous value of *p.
371  */
372 static __inline u_int
373 atomic_fetchadd_32(volatile u_int32_t *p, u_int32_t v)
374 {
375         u_int32_t value, temp;
376
377 #ifdef __GNUCLIKE_ASM
378         __asm __volatile (
379                 "1:\tldl_l %0, %1\n\t"          /* load old value */
380                 "addl %0, %3, %2\n\t"           /* calculate new value */
381                 "stl_c %2, %1\n\t"              /* attempt to store */
382                 "beq %2, 1b\n"                  /* spin if failed */
383                 : "=&r" (value), "=m" (*p), "=r" (temp)
384                 : "r" (v), "m" (*p));
385 #endif
386         return (value);
387 }
388
389 /* Operations on chars. */
390 #define atomic_set_char         atomic_set_8
391 #define atomic_set_acq_char     atomic_set_acq_8
392 #define atomic_set_rel_char     atomic_set_rel_8
393 #define atomic_clear_char       atomic_clear_8
394 #define atomic_clear_acq_char   atomic_clear_acq_8
395 #define atomic_clear_rel_char   atomic_clear_rel_8
396 #define atomic_add_char         atomic_add_8
397 #define atomic_add_acq_char     atomic_add_acq_8
398 #define atomic_add_rel_char     atomic_add_rel_8
399 #define atomic_subtract_char    atomic_subtract_8
400 #define atomic_subtract_acq_char        atomic_subtract_acq_8
401 #define atomic_subtract_rel_char        atomic_subtract_rel_8
402
403 /* Operations on shorts. */
404 #define atomic_set_short        atomic_set_16
405 #define atomic_set_acq_short    atomic_set_acq_16
406 #define atomic_set_rel_short    atomic_set_rel_16
407 #define atomic_clear_short      atomic_clear_16
408 #define atomic_clear_acq_short  atomic_clear_acq_16
409 #define atomic_clear_rel_short  atomic_clear_rel_16
410 #define atomic_add_short        atomic_add_16
411 #define atomic_add_acq_short    atomic_add_acq_16
412 #define atomic_add_rel_short    atomic_add_rel_16
413 #define atomic_subtract_short   atomic_subtract_16
414 #define atomic_subtract_acq_short       atomic_subtract_acq_16
415 #define atomic_subtract_rel_short       atomic_subtract_rel_16
416
417 /* Operations on ints. */
418 #define atomic_set_int          atomic_set_32
419 #define atomic_set_acq_int      atomic_set_acq_32
420 #define atomic_set_rel_int      atomic_set_rel_32
421 #define atomic_clear_int        atomic_clear_32
422 #define atomic_clear_acq_int    atomic_clear_acq_32
423 #define atomic_clear_rel_int    atomic_clear_rel_32
424 #define atomic_add_int          atomic_add_32
425 #define atomic_add_acq_int      atomic_add_acq_32
426 #define atomic_add_rel_int      atomic_add_rel_32
427 #define atomic_subtract_int     atomic_subtract_32
428 #define atomic_subtract_acq_int atomic_subtract_acq_32
429 #define atomic_subtract_rel_int atomic_subtract_rel_32
430 #define atomic_cmpset_int       atomic_cmpset_32
431 #define atomic_cmpset_acq_int   atomic_cmpset_acq_32
432 #define atomic_cmpset_rel_int   atomic_cmpset_rel_32
433 #define atomic_load_acq_int     atomic_load_acq_32
434 #define atomic_store_rel_int    atomic_store_rel_32
435 #define atomic_readandclear_int atomic_readandclear_32
436 #define atomic_fetchadd_int     atomic_fetchadd_32
437
438 /* Operations on longs. */
439 #define atomic_set_long         atomic_set_64
440 #define atomic_set_acq_long     atomic_set_acq_64
441 #define atomic_set_rel_long     atomic_set_rel_64
442 #define atomic_clear_long       atomic_clear_64
443 #define atomic_clear_acq_long   atomic_clear_acq_64
444 #define atomic_clear_rel_long   atomic_clear_rel_64
445 #define atomic_add_long         atomic_add_64
446 #define atomic_add_acq_long     atomic_add_acq_64
447 #define atomic_add_rel_long     atomic_add_rel_64
448 #define atomic_subtract_long    atomic_subtract_64
449 #define atomic_subtract_acq_long        atomic_subtract_acq_64
450 #define atomic_subtract_rel_long        atomic_subtract_rel_64
451 #define atomic_cmpset_long      atomic_cmpset_64
452 #define atomic_cmpset_acq_long  atomic_cmpset_acq_64
453 #define atomic_cmpset_rel_long  atomic_cmpset_rel_64
454 #define atomic_load_acq_long    atomic_load_acq_64
455 #define atomic_store_rel_long   atomic_store_rel_64
456 #define atomic_readandclear_long        atomic_readandclear_64
457
458 /* Operations on pointers. */
459 #define atomic_set_ptr          atomic_set_64
460 #define atomic_set_acq_ptr      atomic_set_acq_64
461 #define atomic_set_rel_ptr      atomic_set_rel_64
462 #define atomic_clear_ptr        atomic_clear_64
463 #define atomic_clear_acq_ptr    atomic_clear_acq_64
464 #define atomic_clear_rel_ptr    atomic_clear_rel_64
465 #define atomic_add_ptr          atomic_add_64
466 #define atomic_add_acq_ptr      atomic_add_acq_64
467 #define atomic_add_rel_ptr      atomic_add_rel_64
468 #define atomic_subtract_ptr     atomic_subtract_64
469 #define atomic_subtract_acq_ptr atomic_subtract_acq_64
470 #define atomic_subtract_rel_ptr atomic_subtract_rel_64
471 #define atomic_cmpset_ptr       atomic_cmpset_64
472 #define atomic_cmpset_acq_ptr   atomic_cmpset_acq_64
473 #define atomic_cmpset_rel_ptr   atomic_cmpset_rel_64
474 #define atomic_load_acq_ptr     atomic_load_acq_64
475 #define atomic_store_rel_ptr    atomic_store_rel_64
476 #define atomic_readandclear_ptr atomic_readandclear_64
477
478 #endif /* ! _MACHINE_ATOMIC_H_ */