atomic.h revision 257189
1187277Sdas/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */
2187277Sdas
3187277Sdas/*-
4187277Sdas * Copyright (C) 2003-2004 Olivier Houchard
5187277Sdas * Copyright (C) 1994-1997 Mark Brinicombe
6187277Sdas * Copyright (C) 1994 Brini
7187277Sdas * All rights reserved.
8187277Sdas *
9187277Sdas * This code is derived from software written for Brini by Mark Brinicombe
10187277Sdas *
11187277Sdas * Redistribution and use in source and binary forms, with or without
12187277Sdas * modification, are permitted provided that the following conditions
13187277Sdas * are met:
14187277Sdas * 1. Redistributions of source code must retain the above copyright
15187277Sdas *    notice, this list of conditions and the following disclaimer.
16187277Sdas * 2. Redistributions in binary form must reproduce the above copyright
17187277Sdas *    notice, this list of conditions and the following disclaimer in the
18187277Sdas *    documentation and/or other materials provided with the distribution.
19187277Sdas * 3. All advertising materials mentioning features or use of this software
20187277Sdas *    must display the following acknowledgement:
21187277Sdas *	This product includes software developed by Brini.
22187277Sdas * 4. The name of Brini may not be used to endorse or promote products
23187277Sdas *    derived from this software without specific prior written permission.
24187277Sdas *
25187277Sdas * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
26187277Sdas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27187277Sdas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28187277Sdas * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29187277Sdas * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30187277Sdas * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31187277Sdas * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32187277Sdas * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33187277Sdas * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34187277Sdas * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35187277Sdas *
36187277Sdas * $FreeBSD: head/sys/arm/include/atomic.h 257189 2013-10-26 19:09:56Z andrew $
37187277Sdas */
38187277Sdas
39187277Sdas#ifndef	_MACHINE_ATOMIC_H_
40187284Sdas#define	_MACHINE_ATOMIC_H_
41187284Sdas
42187284Sdas#include <sys/types.h>
43187284Sdas
44187284Sdas#ifndef _KERNEL
45187284Sdas#include <machine/sysarch.h>
46187284Sdas#else
47187284Sdas#include <machine/cpuconf.h>
48187284Sdas#endif
49187284Sdas
50187284Sdas#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
51187284Sdas#define isb()  __asm __volatile("isb" : : : "memory")
52187284Sdas#define dsb()  __asm __volatile("dsb" : : : "memory")
53187284Sdas#define dmb()  __asm __volatile("dmb" : : : "memory")
54187284Sdas#elif defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) || \
55187284Sdas  defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) || \
56187284Sdas  defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)
57187284Sdas#define isb()  __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory")
58187284Sdas#define dsb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory")
59187284Sdas#define dmb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory")
60187284Sdas#else
61187284Sdas#define isb()
62187277Sdas#define dsb()
63187277Sdas#define dmb()
64187277Sdas#endif
65187277Sdas
66187277Sdas#define mb()   dmb()
67187277Sdas#define wmb()  dmb()
68187277Sdas#define rmb()  dmb()
69187277Sdas
70187277Sdas#ifndef I32_bit
71187277Sdas#define I32_bit (1 << 7)        /* IRQ disable */
72187277Sdas#endif
73187354Sdas#ifndef F32_bit
74187277Sdas#define F32_bit (1 << 6)        /* FIQ disable */
75187277Sdas#endif
76187277Sdas
77187277Sdas/*
78187277Sdas * It would be nice to use _HAVE_ARMv6_INSTRUCTIONS from machine/asm.h
79187277Sdas * here, but that header can't be included here because this is C
80187277Sdas * code.  I would like to move the _HAVE_ARMv6_INSTRUCTIONS definition
81187277Sdas * out of asm.h so it can be used in both asm and C code. - kientzle@
82187277Sdas */
83187277Sdas#if defined (__ARM_ARCH_7__) || \
84187277Sdas	defined (__ARM_ARCH_7A__)  || \
85187277Sdas	defined (__ARM_ARCH_6__)   || \
86187277Sdas	defined (__ARM_ARCH_6J__)  || \
87187354Sdas	defined (__ARM_ARCH_6K__)  || \
88187354Sdas	defined (__ARM_ARCH_6T2__) || \
89187277Sdas	defined (__ARM_ARCH_6Z__)  || \
90187354Sdas	defined (__ARM_ARCH_6ZK__)
91187277Sdasstatic __inline void
92187354Sdas__do_dmb(void)
93187354Sdas{
94187277Sdas
95187277Sdas#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
96187277Sdas	__asm __volatile("dmb" : : : "memory");
97187277Sdas#else
98187277Sdas	__asm __volatile("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
99187277Sdas#endif
100187277Sdas}
101187277Sdas
102187277Sdas#define ATOMIC_ACQ_REL_LONG(NAME)					\
103187277Sdasstatic __inline void							\
104187277Sdasatomic_##NAME##_acq_long(__volatile u_long *p, u_long v)		\
105187277Sdas{									\
106187277Sdas	atomic_##NAME##_long(p, v);					\
107187277Sdas	__do_dmb();							\
108187277Sdas}									\
109187277Sdas									\
110187277Sdasstatic __inline  void							\
111187277Sdasatomic_##NAME##_rel_long(__volatile u_long *p, u_long v)		\
112187277Sdas{									\
113187277Sdas	__do_dmb();							\
114187354Sdas	atomic_##NAME##_long(p, v);					\
115187277Sdas}
116187354Sdas
117187354Sdas#define	ATOMIC_ACQ_REL(NAME, WIDTH)					\
118187354Sdasstatic __inline  void							\
119187277Sdasatomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
120187354Sdas{									\
121187277Sdas	atomic_##NAME##_##WIDTH(p, v);					\
122187277Sdas	__do_dmb();							\
123187277Sdas}									\
124187277Sdas									\
125187277Sdasstatic __inline  void							\
126187277Sdasatomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
127187277Sdas{									\
128187277Sdas	__do_dmb();							\
129187277Sdas	atomic_##NAME##_##WIDTH(p, v);					\
130187277Sdas}
131187277Sdas
132187277Sdasstatic __inline void
133187277Sdasatomic_set_32(volatile uint32_t *address, uint32_t setmask)
134187277Sdas{
135187277Sdas	uint32_t tmp = 0, tmp2 = 0;
136187277Sdas
137187277Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
138187354Sdas	    		    "orr %0, %0, %3\n"
139187354Sdas			    "strex %1, %0, [%2]\n"
140187354Sdas			    "cmp %1, #0\n"
141187354Sdas	                    "it ne\n"
142187354Sdas			    "bne	1b\n"
143187354Sdas			   : "=&r" (tmp), "+r" (tmp2)
144187354Sdas			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
145187277Sdas
146187277Sdas}
147187277Sdas
148187277Sdasstatic __inline void
149187277Sdasatomic_set_long(volatile u_long *address, u_long setmask)
150187277Sdas{
151187277Sdas	u_long tmp = 0, tmp2 = 0;
152187277Sdas
153187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
154187284Sdas	    		    "orr %0, %0, %3\n"
155187284Sdas			    "strex %1, %0, [%2]\n"
156187284Sdas			    "cmp %1, #0\n"
157187284Sdas	                    "it ne\n"
158187284Sdas			    "bne	1b\n"
159187284Sdas			   : "=&r" (tmp), "+r" (tmp2)
160187284Sdas			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
161187284Sdas
162187284Sdas}
163187284Sdas
164187284Sdasstatic __inline void
165187284Sdasatomic_clear_32(volatile uint32_t *address, uint32_t setmask)
166187284Sdas{
167187284Sdas	uint32_t tmp = 0, tmp2 = 0;
168187284Sdas
169187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
170187284Sdas	    		    "bic %0, %0, %3\n"
171187284Sdas			    "strex %1, %0, [%2]\n"
172187284Sdas			    "cmp %1, #0\n"
173187284Sdas	                    "it ne\n"
174187284Sdas			    "bne	1b\n"
175187284Sdas			   : "=&r" (tmp), "+r" (tmp2)
176187284Sdas			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
177187284Sdas}
178187284Sdas
179187284Sdasstatic __inline void
180187284Sdasatomic_clear_long(volatile u_long *address, u_long setmask)
181187284Sdas{
182187284Sdas	u_long tmp = 0, tmp2 = 0;
183187284Sdas
184187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
185187284Sdas	    		    "bic %0, %0, %3\n"
186187284Sdas			    "strex %1, %0, [%2]\n"
187187284Sdas			    "cmp %1, #0\n"
188187284Sdas	                    "it ne\n"
189187284Sdas			    "bne	1b\n"
190187284Sdas			   : "=&r" (tmp), "+r" (tmp2)
191187284Sdas			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
192187284Sdas}
193187284Sdas
194187284Sdasstatic __inline u_int32_t
195187284Sdasatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
196187284Sdas{
197187284Sdas	uint32_t ret;
198187284Sdas
199187284Sdas	__asm __volatile("1: ldrex %0, [%1]\n"
200187284Sdas	                 "cmp %0, %2\n"
201187284Sdas	                 "itt ne\n"
202187284Sdas			 "movne %0, #0\n"
203187284Sdas			 "bne 2f\n"
204187284Sdas			 "strex %0, %3, [%1]\n"
205187284Sdas			 "cmp %0, #0\n"
206187284Sdas	                 "ite eq\n"
207187284Sdas			 "moveq %0, #1\n"
208187284Sdas			 "bne	1b\n"
209187284Sdas			 "2:"
210187284Sdas			 : "=&r" (ret)
211187284Sdas			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "cc",
212187284Sdas			 "memory");
213187284Sdas	return (ret);
214187284Sdas}
215187284Sdas
216187284Sdasstatic __inline u_long
217187284Sdasatomic_cmpset_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
218187284Sdas{
219187284Sdas	u_long ret;
220187284Sdas
221187284Sdas	__asm __volatile("1: ldrex %0, [%1]\n"
222187284Sdas	                 "cmp %0, %2\n"
223187284Sdas	                 "itt ne\n"
224187284Sdas			 "movne %0, #0\n"
225187284Sdas			 "bne 2f\n"
226187284Sdas			 "strex %0, %3, [%1]\n"
227187284Sdas			 "cmp %0, #0\n"
228187284Sdas	                 "ite eq\n"
229187284Sdas			 "moveq %0, #1\n"
230187284Sdas			 "bne	1b\n"
231187284Sdas			 "2:"
232187284Sdas			 : "=&r" (ret)
233187284Sdas			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "cc",
234187284Sdas			 "memory");
235187284Sdas	return (ret);
236187284Sdas}
237187284Sdas
238187284Sdasstatic __inline u_int32_t
239187284Sdasatomic_cmpset_acq_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
240187284Sdas{
241187284Sdas	u_int32_t ret = atomic_cmpset_32(p, cmpval, newval);
242187284Sdas
243187284Sdas	__do_dmb();
244187284Sdas	return (ret);
245187284Sdas}
246187284Sdas
247187284Sdasstatic __inline u_long
248187284Sdasatomic_cmpset_acq_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
249187284Sdas{
250187284Sdas	u_long ret = atomic_cmpset_long(p, cmpval, newval);
251187284Sdas
252187284Sdas	__do_dmb();
253187284Sdas	return (ret);
254187284Sdas}
255187284Sdas
256187284Sdasstatic __inline u_int32_t
257187284Sdasatomic_cmpset_rel_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
258187284Sdas{
259187284Sdas
260187284Sdas	__do_dmb();
261187284Sdas	return (atomic_cmpset_32(p, cmpval, newval));
262187284Sdas}
263187284Sdas
264187284Sdasstatic __inline u_long
265187284Sdasatomic_cmpset_rel_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
266187284Sdas{
267187284Sdas
268187284Sdas	__do_dmb();
269187284Sdas	return (atomic_cmpset_long(p, cmpval, newval));
270187284Sdas}
271187284Sdas
272187284Sdas
273187284Sdasstatic __inline void
274187284Sdasatomic_add_32(volatile u_int32_t *p, u_int32_t val)
275187284Sdas{
276187284Sdas	uint32_t tmp = 0, tmp2 = 0;
277187284Sdas
278187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
279187284Sdas	    		    "add %0, %0, %3\n"
280187284Sdas			    "strex %1, %0, [%2]\n"
281187284Sdas			    "cmp %1, #0\n"
282187284Sdas	                    "it ne\n"
283187284Sdas			    "bne	1b\n"
284187284Sdas			    : "=&r" (tmp), "+r" (tmp2)
285187284Sdas			    ,"+r" (p), "+r" (val) : : "cc", "memory");
286187284Sdas}
287187284Sdas
288187284Sdasstatic __inline void
289187284Sdasatomic_add_long(volatile u_long *p, u_long val)
290187284Sdas{
291187284Sdas	u_long tmp = 0, tmp2 = 0;
292187284Sdas
293187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
294187284Sdas	    		    "add %0, %0, %3\n"
295187284Sdas			    "strex %1, %0, [%2]\n"
296187284Sdas			    "cmp %1, #0\n"
297187284Sdas	                    "it ne\n"
298187284Sdas			    "bne	1b\n"
299187284Sdas			    : "=&r" (tmp), "+r" (tmp2)
300187284Sdas			    ,"+r" (p), "+r" (val) : : "cc", "memory");
301187284Sdas}
302187284Sdas
303187284Sdasstatic __inline void
304187284Sdasatomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
305187284Sdas{
306187284Sdas	uint32_t tmp = 0, tmp2 = 0;
307187284Sdas
308187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
309187284Sdas	    		    "sub %0, %0, %3\n"
310187284Sdas			    "strex %1, %0, [%2]\n"
311187284Sdas			    "cmp %1, #0\n"
312187284Sdas	                    "it ne\n"
313187284Sdas			    "bne	1b\n"
314187284Sdas			    : "=&r" (tmp), "+r" (tmp2)
315187284Sdas			    ,"+r" (p), "+r" (val) : : "cc", "memory");
316187284Sdas}
317187284Sdas
318187284Sdasstatic __inline void
319187284Sdasatomic_subtract_long(volatile u_long *p, u_long val)
320187284Sdas{
321187284Sdas	u_long tmp = 0, tmp2 = 0;
322187284Sdas
323187284Sdas	__asm __volatile("1: ldrex %0, [%2]\n"
324187284Sdas	    		    "sub %0, %0, %3\n"
325187284Sdas			    "strex %1, %0, [%2]\n"
326187284Sdas			    "cmp %1, #0\n"
327187284Sdas	                    "it ne\n"
328187284Sdas			    "bne	1b\n"
329187284Sdas			    : "=&r" (tmp), "+r" (tmp2)
330187284Sdas			    ,"+r" (p), "+r" (val) : : "cc", "memory");
331187284Sdas}
332187284Sdas
333187284SdasATOMIC_ACQ_REL(clear, 32)
334187284SdasATOMIC_ACQ_REL(add, 32)
335187284SdasATOMIC_ACQ_REL(subtract, 32)
336187284SdasATOMIC_ACQ_REL(set, 32)
337187284SdasATOMIC_ACQ_REL_LONG(clear)
338187284SdasATOMIC_ACQ_REL_LONG(add)
339187284SdasATOMIC_ACQ_REL_LONG(subtract)
340187284SdasATOMIC_ACQ_REL_LONG(set)
341187284Sdas
342187284Sdas#undef ATOMIC_ACQ_REL
343187284Sdas#undef ATOMIC_ACQ_REL_LONG
344187284Sdas
345187284Sdasstatic __inline uint32_t
346187284Sdasatomic_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
361static __inline uint32_t
362atomic_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
377static __inline uint32_t
378atomic_load_acq_32(volatile uint32_t *p)
379{
380	uint32_t v;
381
382	v = *p;
383	__do_dmb();
384	return (v);
385}
386
387static __inline void
388atomic_store_rel_32(volatile uint32_t *p, uint32_t v)
389{
390
391	__do_dmb();
392	*p = v;
393}
394
395static __inline u_long
396atomic_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
411static __inline u_long
412atomic_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
427static __inline u_long
428atomic_load_acq_long(volatile u_long *p)
429{
430	u_long v;
431
432	v = *p;
433	__do_dmb();
434	return (v);
435}
436
437static __inline void
438atomic_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
465static __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
477static __inline void
478atomic_set_32(volatile uint32_t *address, uint32_t setmask)
479{
480	__with_interrupts_disabled(*address |= setmask);
481}
482
483static __inline void
484atomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
485{
486	__with_interrupts_disabled(*address &= ~clearmask);
487}
488
489static __inline u_int32_t
490atomic_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
506static __inline void
507atomic_add_32(volatile u_int32_t *p, u_int32_t val)
508{
509	__with_interrupts_disabled(*p += val);
510}
511
512static __inline void
513atomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
514{
515	__with_interrupts_disabled(*p -= val);
516}
517
518static __inline uint32_t
519atomic_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
533static __inline u_int32_t
534atomic_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
558static __inline void
559atomic_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
580static __inline void
581atomic_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
603static __inline void
604atomic_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
626static __inline void
627atomic_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
649static __inline uint32_t
650atomic_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
676static __inline uint32_t
677atomic_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
710static __inline void
711atomic_add_long(volatile u_long *p, u_long v)
712{
713
714	atomic_add_32((volatile uint32_t *)p, v);
715}
716
717static __inline void
718atomic_clear_long(volatile u_long *p, u_long v)
719{
720
721	atomic_clear_32((volatile uint32_t *)p, v);
722}
723
724static __inline int
725atomic_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
731static __inline u_long
732atomic_fetchadd_long(volatile u_long *p, u_long v)
733{
734
735	return (atomic_fetchadd_32((volatile uint32_t *)p, v));
736}
737
738static __inline void
739atomic_readandclear_long(volatile u_long *p)
740{
741
742	atomic_readandclear_32((volatile uint32_t *)p);
743}
744
745static __inline void
746atomic_set_long(volatile u_long *p, u_long v)
747{
748
749	atomic_set_32((volatile uint32_t *)p, v);
750}
751
752static __inline void
753atomic_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
763static __inline int
764atomic_load_32(volatile uint32_t *v)
765{
766
767	return (*v);
768}
769
770static __inline void
771atomic_store_32(volatile uint32_t *dst, uint32_t src)
772{
773	*dst = src;
774}
775
776static __inline int
777atomic_load_long(volatile u_long *v)
778{
779
780	return (*v);
781}
782
783static __inline void
784atomic_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