xref: /freebsd/sys/arm/include/atomic.h (revision 0a10f22a30d61a6f32777a236a82d461129538cc)
1 /* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */
2 
3 /*-
4  * Copyright (C) 2003-2004 Olivier Houchard
5  * Copyright (C) 1994-1997 Mark Brinicombe
6  * Copyright (C) 1994 Brini
7  * All rights reserved.
8  *
9  * This code is derived from software written for Brini by Mark Brinicombe
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by Brini.
22  * 4. The name of Brini may not be used to endorse or promote products
23  *    derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $FreeBSD$
37  */
38 
39 #ifndef	_MACHINE_ATOMIC_H_
40 #define	_MACHINE_ATOMIC_H_
41 
42 #include <sys/types.h>
43 
44 #ifndef _KERNEL
45 #include <machine/sysarch.h>
46 #else
47 #include <machine/cpuconf.h>
48 #endif
49 
50 #if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
51 #define isb()  __asm __volatile("isb" : : : "memory")
52 #define dsb()  __asm __volatile("dsb" : : : "memory")
53 #define dmb()  __asm __volatile("dmb" : : : "memory")
54 #elif defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) || \
55   defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) || \
56   defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)
57 #define isb()  __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory")
58 #define dsb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory")
59 #define dmb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory")
60 #else
61 #define isb()
62 #define dsb()
63 #define dmb()
64 #endif
65 
66 #define mb()   dmb()
67 #define wmb()  dmb()
68 #define rmb()  dmb()
69 
70 #ifndef I32_bit
71 #define I32_bit (1 << 7)        /* IRQ disable */
72 #endif
73 #ifndef F32_bit
74 #define F32_bit (1 << 6)        /* FIQ disable */
75 #endif
76 
77 /*
78  * It would be nice to use _HAVE_ARMv6_INSTRUCTIONS from machine/asm.h
79  * here, but that header can't be included here because this is C
80  * code.  I would like to move the _HAVE_ARMv6_INSTRUCTIONS definition
81  * out of asm.h so it can be used in both asm and C code. - kientzle@
82  */
83 #if defined (__ARM_ARCH_7__) || \
84 	defined (__ARM_ARCH_7A__)  || \
85 	defined (__ARM_ARCH_6__)   || \
86 	defined (__ARM_ARCH_6J__)  || \
87 	defined (__ARM_ARCH_6K__)  || \
88 	defined (__ARM_ARCH_6T2__) || \
89 	defined (__ARM_ARCH_6Z__)  || \
90 	defined (__ARM_ARCH_6ZK__)
91 static __inline void
92 __do_dmb(void)
93 {
94 
95 #if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
96 	__asm __volatile("dmb" : : : "memory");
97 #else
98 	__asm __volatile("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
99 #endif
100 }
101 
102 #define ATOMIC_ACQ_REL_LONG(NAME)					\
103 static __inline void							\
104 atomic_##NAME##_acq_long(__volatile u_long *p, u_long v)		\
105 {									\
106 	atomic_##NAME##_long(p, v);					\
107 	__do_dmb();							\
108 }									\
109 									\
110 static __inline  void							\
111 atomic_##NAME##_rel_long(__volatile u_long *p, u_long v)		\
112 {									\
113 	__do_dmb();							\
114 	atomic_##NAME##_long(p, v);					\
115 }
116 
117 #define	ATOMIC_ACQ_REL(NAME, WIDTH)					\
118 static __inline  void							\
119 atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
120 {									\
121 	atomic_##NAME##_##WIDTH(p, v);					\
122 	__do_dmb();							\
123 }									\
124 									\
125 static __inline  void							\
126 atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
127 {									\
128 	__do_dmb();							\
129 	atomic_##NAME##_##WIDTH(p, v);					\
130 }
131 
132 static __inline void
133 atomic_set_32(volatile uint32_t *address, uint32_t setmask)
134 {
135 	uint32_t tmp = 0, tmp2 = 0;
136 
137 	__asm __volatile("1: ldrex %0, [%2]\n"
138 	    		    "orr %0, %0, %3\n"
139 			    "strex %1, %0, [%2]\n"
140 			    "cmp %1, #0\n"
141 	                    "it ne\n"
142 			    "bne	1b\n"
143 			   : "=&r" (tmp), "+r" (tmp2)
144 			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
145 
146 }
147 
148 static __inline void
149 atomic_set_long(volatile u_long *address, u_long setmask)
150 {
151 	u_long tmp = 0, tmp2 = 0;
152 
153 	__asm __volatile("1: ldrex %0, [%2]\n"
154 	    		    "orr %0, %0, %3\n"
155 			    "strex %1, %0, [%2]\n"
156 			    "cmp %1, #0\n"
157 	                    "it ne\n"
158 			    "bne	1b\n"
159 			   : "=&r" (tmp), "+r" (tmp2)
160 			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
161 
162 }
163 
164 static __inline void
165 atomic_clear_32(volatile uint32_t *address, uint32_t setmask)
166 {
167 	uint32_t tmp = 0, tmp2 = 0;
168 
169 	__asm __volatile("1: ldrex %0, [%2]\n"
170 	    		    "bic %0, %0, %3\n"
171 			    "strex %1, %0, [%2]\n"
172 			    "cmp %1, #0\n"
173 	                    "it ne\n"
174 			    "bne	1b\n"
175 			   : "=&r" (tmp), "+r" (tmp2)
176 			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
177 }
178 
179 static __inline void
180 atomic_clear_long(volatile u_long *address, u_long setmask)
181 {
182 	u_long tmp = 0, tmp2 = 0;
183 
184 	__asm __volatile("1: ldrex %0, [%2]\n"
185 	    		    "bic %0, %0, %3\n"
186 			    "strex %1, %0, [%2]\n"
187 			    "cmp %1, #0\n"
188 	                    "it ne\n"
189 			    "bne	1b\n"
190 			   : "=&r" (tmp), "+r" (tmp2)
191 			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
192 }
193 
194 static __inline u_int32_t
195 atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
196 {
197 	uint32_t ret;
198 
199 	__asm __volatile("1: ldrex %0, [%1]\n"
200 	                 "cmp %0, %2\n"
201 	                 "it ne\n"
202 			 "movne %0, #0\n"
203 			 "bne 2f\n"
204 			 "strex %0, %3, [%1]\n"
205 			 "cmp %0, #0\n"
206 	                 "ite eq\n"
207 			 "moveq %0, #1\n"
208 			 "bne	1b\n"
209 			 "2:"
210 			 : "=&r" (ret)
211 			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "cc",
212 			 "memory");
213 	return (ret);
214 }
215 
216 static __inline u_long
217 atomic_cmpset_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
218 {
219 	u_long ret;
220 
221 	__asm __volatile("1: ldrex %0, [%1]\n"
222 	                 "cmp %0, %2\n"
223 	                 "itt ne\n"
224 			 "movne %0, #0\n"
225 			 "bne 2f\n"
226 			 "strex %0, %3, [%1]\n"
227 			 "cmp %0, #0\n"
228 	                 "ite eq\n"
229 			 "moveq %0, #1\n"
230 			 "bne	1b\n"
231 			 "2:"
232 			 : "=&r" (ret)
233 			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "cc",
234 			 "memory");
235 	return (ret);
236 }
237 
238 static __inline u_int32_t
239 atomic_cmpset_acq_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
240 {
241 	u_int32_t ret = atomic_cmpset_32(p, cmpval, newval);
242 
243 	__do_dmb();
244 	return (ret);
245 }
246 
247 static __inline u_long
248 atomic_cmpset_acq_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
249 {
250 	u_long ret = atomic_cmpset_long(p, cmpval, newval);
251 
252 	__do_dmb();
253 	return (ret);
254 }
255 
256 static __inline u_int32_t
257 atomic_cmpset_rel_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
258 {
259 
260 	__do_dmb();
261 	return (atomic_cmpset_32(p, cmpval, newval));
262 }
263 
264 static __inline u_long
265 atomic_cmpset_rel_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
266 {
267 
268 	__do_dmb();
269 	return (atomic_cmpset_long(p, cmpval, newval));
270 }
271 
272 
273 static __inline void
274 atomic_add_32(volatile u_int32_t *p, u_int32_t val)
275 {
276 	uint32_t tmp = 0, tmp2 = 0;
277 
278 	__asm __volatile("1: ldrex %0, [%2]\n"
279 	    		    "add %0, %0, %3\n"
280 			    "strex %1, %0, [%2]\n"
281 			    "cmp %1, #0\n"
282 	                    "it ne\n"
283 			    "bne	1b\n"
284 			    : "=&r" (tmp), "+r" (tmp2)
285 			    ,"+r" (p), "+r" (val) : : "cc", "memory");
286 }
287 
288 static __inline void
289 atomic_add_long(volatile u_long *p, u_long val)
290 {
291 	u_long tmp = 0, tmp2 = 0;
292 
293 	__asm __volatile("1: ldrex %0, [%2]\n"
294 	    		    "add %0, %0, %3\n"
295 			    "strex %1, %0, [%2]\n"
296 			    "cmp %1, #0\n"
297 	                    "it ne\n"
298 			    "bne	1b\n"
299 			    : "=&r" (tmp), "+r" (tmp2)
300 			    ,"+r" (p), "+r" (val) : : "cc", "memory");
301 }
302 
303 static __inline void
304 atomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
305 {
306 	uint32_t tmp = 0, tmp2 = 0;
307 
308 	__asm __volatile("1: ldrex %0, [%2]\n"
309 	    		    "sub %0, %0, %3\n"
310 			    "strex %1, %0, [%2]\n"
311 			    "cmp %1, #0\n"
312 	                    "it ne\n"
313 			    "bne	1b\n"
314 			    : "=&r" (tmp), "+r" (tmp2)
315 			    ,"+r" (p), "+r" (val) : : "cc", "memory");
316 }
317 
318 static __inline void
319 atomic_subtract_long(volatile u_long *p, u_long val)
320 {
321 	u_long tmp = 0, tmp2 = 0;
322 
323 	__asm __volatile("1: ldrex %0, [%2]\n"
324 	    		    "sub %0, %0, %3\n"
325 			    "strex %1, %0, [%2]\n"
326 			    "cmp %1, #0\n"
327 	                    "it ne\n"
328 			    "bne	1b\n"
329 			    : "=&r" (tmp), "+r" (tmp2)
330 			    ,"+r" (p), "+r" (val) : : "cc", "memory");
331 }
332 
333 ATOMIC_ACQ_REL(clear, 32)
334 ATOMIC_ACQ_REL(add, 32)
335 ATOMIC_ACQ_REL(subtract, 32)
336 ATOMIC_ACQ_REL(set, 32)
337 ATOMIC_ACQ_REL_LONG(clear)
338 ATOMIC_ACQ_REL_LONG(add)
339 ATOMIC_ACQ_REL_LONG(subtract)
340 ATOMIC_ACQ_REL_LONG(set)
341 
342 #undef ATOMIC_ACQ_REL
343 #undef ATOMIC_ACQ_REL_LONG
344 
345 static __inline uint32_t
346 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
347 {
348 	uint32_t tmp = 0, tmp2 = 0, ret = 0;
349 
350 	__asm __volatile("1: ldrex %0, [%3]\n"
351 	    		    "add %1, %0, %4\n"
352 			    "strex %2, %1, [%3]\n"
353 			    "cmp %2, #0\n"
354 	                    "it ne\n"
355 			    "bne	1b\n"
356 			   : "+r" (ret), "=&r" (tmp), "+r" (tmp2)
357 			   ,"+r" (p), "+r" (val) : : "cc", "memory");
358 	return (ret);
359 }
360 
361 static __inline uint32_t
362 atomic_readandclear_32(volatile u_int32_t *p)
363 {
364 	uint32_t ret, tmp = 0, tmp2 = 0;
365 
366 	__asm __volatile("1: ldrex %0, [%3]\n"
367 	    		 "mov %1, #0\n"
368 			 "strex %2, %1, [%3]\n"
369 			 "cmp %2, #0\n"
370 	                 "it ne\n"
371 			 "bne 1b\n"
372 			 : "=r" (ret), "=&r" (tmp), "+r" (tmp2)
373 			 ,"+r" (p) : : "cc", "memory");
374 	return (ret);
375 }
376 
377 static __inline uint32_t
378 atomic_load_acq_32(volatile uint32_t *p)
379 {
380 	uint32_t v;
381 
382 	v = *p;
383 	__do_dmb();
384 	return (v);
385 }
386 
387 static __inline void
388 atomic_store_rel_32(volatile uint32_t *p, uint32_t v)
389 {
390 
391 	__do_dmb();
392 	*p = v;
393 }
394 
395 static __inline u_long
396 atomic_fetchadd_long(volatile u_long *p, u_long val)
397 {
398 	u_long tmp = 0, tmp2 = 0, ret = 0;
399 
400 	__asm __volatile("1: ldrex %0, [%3]\n"
401 	    		    "add %1, %0, %4\n"
402 			    "strex %2, %1, [%3]\n"
403 			    "cmp %2, #0\n"
404 	                    "it ne\n"
405 			    "bne	1b\n"
406 			   : "+r" (ret), "=&r" (tmp), "+r" (tmp2)
407 			   ,"+r" (p), "+r" (val) : : "cc", "memory");
408 	return (ret);
409 }
410 
411 static __inline u_long
412 atomic_readandclear_long(volatile u_long *p)
413 {
414 	u_long ret, tmp = 0, tmp2 = 0;
415 
416 	__asm __volatile("1: ldrex %0, [%3]\n"
417 	    		 "mov %1, #0\n"
418 			 "strex %2, %1, [%3]\n"
419 			 "cmp %2, #0\n"
420 	                 "it ne\n"
421 			 "bne 1b\n"
422 			 : "=r" (ret), "=&r" (tmp), "+r" (tmp2)
423 			 ,"+r" (p) : : "cc", "memory");
424 	return (ret);
425 }
426 
427 static __inline u_long
428 atomic_load_acq_long(volatile u_long *p)
429 {
430 	u_long v;
431 
432 	v = *p;
433 	__do_dmb();
434 	return (v);
435 }
436 
437 static __inline void
438 atomic_store_rel_long(volatile u_long *p, u_long v)
439 {
440 
441 	__do_dmb();
442 	*p = v;
443 }
444 #else /* < armv6 */
445 
446 #define __with_interrupts_disabled(expr) \
447 	do {						\
448 		u_int cpsr_save, tmp;			\
449 							\
450 		__asm __volatile(			\
451 			"mrs  %0, cpsr;"		\
452 			"orr  %1, %0, %2;"		\
453 			"msr  cpsr_all, %1;"		\
454 			: "=r" (cpsr_save), "=r" (tmp)	\
455 			: "I" (I32_bit | F32_bit)		\
456 		        : "cc" );		\
457 		(expr);				\
458 		 __asm __volatile(		\
459 			"msr  cpsr_all, %0"	\
460 			: /* no output */	\
461 			: "r" (cpsr_save)	\
462 			: "cc" );		\
463 	} while(0)
464 
465 static __inline uint32_t
466 __swp(uint32_t val, volatile uint32_t *ptr)
467 {
468 	__asm __volatile("swp	%0, %2, [%3]"
469 	    : "=&r" (val), "=m" (*ptr)
470 	    : "r" (val), "r" (ptr), "m" (*ptr)
471 	    : "memory");
472 	return (val);
473 }
474 
475 
476 #ifdef _KERNEL
477 static __inline void
478 atomic_set_32(volatile uint32_t *address, uint32_t setmask)
479 {
480 	__with_interrupts_disabled(*address |= setmask);
481 }
482 
483 static __inline void
484 atomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
485 {
486 	__with_interrupts_disabled(*address &= ~clearmask);
487 }
488 
489 static __inline u_int32_t
490 atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
491 {
492 	int ret;
493 
494 	__with_interrupts_disabled(
495 	 {
496 	    	if (*p == cmpval) {
497 			*p = newval;
498 			ret = 1;
499 		} else {
500 			ret = 0;
501 		}
502 	});
503 	return (ret);
504 }
505 
506 static __inline void
507 atomic_add_32(volatile u_int32_t *p, u_int32_t val)
508 {
509 	__with_interrupts_disabled(*p += val);
510 }
511 
512 static __inline void
513 atomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
514 {
515 	__with_interrupts_disabled(*p -= val);
516 }
517 
518 static __inline uint32_t
519 atomic_fetchadd_32(volatile uint32_t *p, uint32_t v)
520 {
521 	uint32_t value;
522 
523 	__with_interrupts_disabled(
524 	{
525 	    	value = *p;
526 		*p += v;
527 	});
528 	return (value);
529 }
530 
531 #else /* !_KERNEL */
532 
533 static __inline u_int32_t
534 atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
535 {
536 	register int done, ras_start = ARM_RAS_START;
537 
538 	__asm __volatile("1:\n"
539 	    "adr	%1, 1b\n"
540 	    "str	%1, [%0]\n"
541 	    "adr	%1, 2f\n"
542 	    "str	%1, [%0, #4]\n"
543 	    "ldr	%1, [%2]\n"
544 	    "cmp	%1, %3\n"
545 	    "streq	%4, [%2]\n"
546 	    "2:\n"
547 	    "mov	%1, #0\n"
548 	    "str	%1, [%0]\n"
549 	    "mov	%1, #0xffffffff\n"
550 	    "str	%1, [%0, #4]\n"
551 	    "moveq	%1, #1\n"
552 	    "movne	%1, #0\n"
553 	    : "+r" (ras_start), "=r" (done)
554 	    ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "cc", "memory");
555 	return (done);
556 }
557 
558 static __inline void
559 atomic_add_32(volatile u_int32_t *p, u_int32_t val)
560 {
561 	int start, ras_start = ARM_RAS_START;
562 
563 	__asm __volatile("1:\n"
564 	    "adr	%1, 1b\n"
565 	    "str	%1, [%0]\n"
566 	    "adr	%1, 2f\n"
567 	    "str	%1, [%0, #4]\n"
568 	    "ldr	%1, [%2]\n"
569 	    "add	%1, %1, %3\n"
570 	    "str	%1, [%2]\n"
571 	    "2:\n"
572 	    "mov	%1, #0\n"
573 	    "str	%1, [%0]\n"
574 	    "mov	%1, #0xffffffff\n"
575 	    "str	%1, [%0, #4]\n"
576 	    : "+r" (ras_start), "=r" (start), "+r" (p), "+r" (val)
577 	    : : "memory");
578 }
579 
580 static __inline void
581 atomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
582 {
583 	int start, ras_start = ARM_RAS_START;
584 
585 	__asm __volatile("1:\n"
586 	    "adr	%1, 1b\n"
587 	    "str	%1, [%0]\n"
588 	    "adr	%1, 2f\n"
589 	    "str	%1, [%0, #4]\n"
590 	    "ldr	%1, [%2]\n"
591 	    "sub	%1, %1, %3\n"
592 	    "str	%1, [%2]\n"
593 	    "2:\n"
594 	    "mov	%1, #0\n"
595 	    "str	%1, [%0]\n"
596 	    "mov	%1, #0xffffffff\n"
597 	    "str	%1, [%0, #4]\n"
598 
599 	    : "+r" (ras_start), "=r" (start), "+r" (p), "+r" (val)
600 	    : : "memory");
601 }
602 
603 static __inline void
604 atomic_set_32(volatile uint32_t *address, uint32_t setmask)
605 {
606 	int start, ras_start = ARM_RAS_START;
607 
608 	__asm __volatile("1:\n"
609 	    "adr	%1, 1b\n"
610 	    "str	%1, [%0]\n"
611 	    "adr	%1, 2f\n"
612 	    "str	%1, [%0, #4]\n"
613 	    "ldr	%1, [%2]\n"
614 	    "orr	%1, %1, %3\n"
615 	    "str	%1, [%2]\n"
616 	    "2:\n"
617 	    "mov	%1, #0\n"
618 	    "str	%1, [%0]\n"
619 	    "mov	%1, #0xffffffff\n"
620 	    "str	%1, [%0, #4]\n"
621 
622 	    : "+r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask)
623 	    : : "memory");
624 }
625 
626 static __inline void
627 atomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
628 {
629 	int start, ras_start = ARM_RAS_START;
630 
631 	__asm __volatile("1:\n"
632 	    "adr	%1, 1b\n"
633 	    "str	%1, [%0]\n"
634 	    "adr	%1, 2f\n"
635 	    "str	%1, [%0, #4]\n"
636 	    "ldr	%1, [%2]\n"
637 	    "bic	%1, %1, %3\n"
638 	    "str	%1, [%2]\n"
639 	    "2:\n"
640 	    "mov	%1, #0\n"
641 	    "str	%1, [%0]\n"
642 	    "mov	%1, #0xffffffff\n"
643 	    "str	%1, [%0, #4]\n"
644 	    : "+r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask)
645 	    : : "memory");
646 
647 }
648 
649 static __inline uint32_t
650 atomic_fetchadd_32(volatile uint32_t *p, uint32_t v)
651 {
652 	uint32_t start, tmp, ras_start = ARM_RAS_START;
653 
654 	__asm __volatile("1:\n"
655 	    "adr	%1, 1b\n"
656 	    "str	%1, [%0]\n"
657 	    "adr	%1, 2f\n"
658 	    "str	%1, [%0, #4]\n"
659 	    "ldr	%1, [%3]\n"
660 	    "mov	%2, %1\n"
661 	    "add	%2, %2, %4\n"
662 	    "str	%2, [%3]\n"
663 	    "2:\n"
664 	    "mov	%2, #0\n"
665 	    "str	%2, [%0]\n"
666 	    "mov	%2, #0xffffffff\n"
667 	    "str	%2, [%0, #4]\n"
668 	    : "+r" (ras_start), "=r" (start), "=r" (tmp), "+r" (p), "+r" (v)
669 	    : : "memory");
670 	return (start);
671 }
672 
673 #endif /* _KERNEL */
674 
675 
676 static __inline uint32_t
677 atomic_readandclear_32(volatile u_int32_t *p)
678 {
679 
680 	return (__swp(0, p));
681 }
682 
683 #define atomic_cmpset_rel_32	atomic_cmpset_32
684 #define atomic_cmpset_acq_32	atomic_cmpset_32
685 #define atomic_set_rel_32	atomic_set_32
686 #define atomic_set_acq_32	atomic_set_32
687 #define atomic_clear_rel_32	atomic_clear_32
688 #define atomic_clear_acq_32	atomic_clear_32
689 #define atomic_add_rel_32	atomic_add_32
690 #define atomic_add_acq_32	atomic_add_32
691 #define atomic_subtract_rel_32	atomic_subtract_32
692 #define atomic_subtract_acq_32	atomic_subtract_32
693 #define atomic_store_rel_32	atomic_store_32
694 #define atomic_store_rel_long	atomic_store_long
695 #define atomic_load_acq_32	atomic_load_32
696 #define atomic_load_acq_long	atomic_load_long
697 #define atomic_add_acq_long		atomic_add_long
698 #define atomic_add_rel_long		atomic_add_long
699 #define atomic_subtract_acq_long	atomic_subtract_long
700 #define atomic_subtract_rel_long	atomic_subtract_long
701 #define atomic_clear_acq_long		atomic_clear_long
702 #define atomic_clear_rel_long		atomic_clear_long
703 #define atomic_set_acq_long		atomic_set_long
704 #define atomic_set_rel_long		atomic_set_long
705 #define atomic_cmpset_acq_long		atomic_cmpset_long
706 #define atomic_cmpset_rel_long		atomic_cmpset_long
707 #define atomic_load_acq_long		atomic_load_long
708 #undef __with_interrupts_disabled
709 
710 static __inline void
711 atomic_add_long(volatile u_long *p, u_long v)
712 {
713 
714 	atomic_add_32((volatile uint32_t *)p, v);
715 }
716 
717 static __inline void
718 atomic_clear_long(volatile u_long *p, u_long v)
719 {
720 
721 	atomic_clear_32((volatile uint32_t *)p, v);
722 }
723 
724 static __inline int
725 atomic_cmpset_long(volatile u_long *dst, u_long old, u_long newe)
726 {
727 
728 	return (atomic_cmpset_32((volatile uint32_t *)dst, old, newe));
729 }
730 
731 static __inline u_long
732 atomic_fetchadd_long(volatile u_long *p, u_long v)
733 {
734 
735 	return (atomic_fetchadd_32((volatile uint32_t *)p, v));
736 }
737 
738 static __inline void
739 atomic_readandclear_long(volatile u_long *p)
740 {
741 
742 	atomic_readandclear_32((volatile uint32_t *)p);
743 }
744 
745 static __inline void
746 atomic_set_long(volatile u_long *p, u_long v)
747 {
748 
749 	atomic_set_32((volatile uint32_t *)p, v);
750 }
751 
752 static __inline void
753 atomic_subtract_long(volatile u_long *p, u_long v)
754 {
755 
756 	atomic_subtract_32((volatile uint32_t *)p, v);
757 }
758 
759 
760 
761 #endif /* Arch >= v6 */
762 
763 static __inline int
764 atomic_load_32(volatile uint32_t *v)
765 {
766 
767 	return (*v);
768 }
769 
770 static __inline void
771 atomic_store_32(volatile uint32_t *dst, uint32_t src)
772 {
773 	*dst = src;
774 }
775 
776 static __inline int
777 atomic_load_long(volatile u_long *v)
778 {
779 
780 	return (*v);
781 }
782 
783 static __inline void
784 atomic_store_long(volatile u_long *dst, u_long src)
785 {
786 	*dst = src;
787 }
788 
789 #define atomic_clear_ptr		atomic_clear_32
790 #define atomic_set_ptr			atomic_set_32
791 #define atomic_cmpset_ptr		atomic_cmpset_32
792 #define atomic_cmpset_rel_ptr		atomic_cmpset_rel_32
793 #define atomic_cmpset_acq_ptr		atomic_cmpset_acq_32
794 #define atomic_store_ptr		atomic_store_32
795 #define atomic_store_rel_ptr		atomic_store_rel_32
796 
797 #define atomic_add_int			atomic_add_32
798 #define atomic_add_acq_int		atomic_add_acq_32
799 #define atomic_add_rel_int		atomic_add_rel_32
800 #define atomic_subtract_int		atomic_subtract_32
801 #define atomic_subtract_acq_int		atomic_subtract_acq_32
802 #define atomic_subtract_rel_int		atomic_subtract_rel_32
803 #define atomic_clear_int		atomic_clear_32
804 #define atomic_clear_acq_int		atomic_clear_acq_32
805 #define atomic_clear_rel_int		atomic_clear_rel_32
806 #define atomic_set_int			atomic_set_32
807 #define atomic_set_acq_int		atomic_set_acq_32
808 #define atomic_set_rel_int		atomic_set_rel_32
809 #define atomic_cmpset_int		atomic_cmpset_32
810 #define atomic_cmpset_acq_int		atomic_cmpset_acq_32
811 #define atomic_cmpset_rel_int		atomic_cmpset_rel_32
812 #define atomic_fetchadd_int		atomic_fetchadd_32
813 #define atomic_readandclear_int		atomic_readandclear_32
814 #define atomic_load_acq_int		atomic_load_acq_32
815 #define atomic_store_rel_int		atomic_store_rel_32
816 
817 #endif /* _MACHINE_ATOMIC_H_ */
818