atomic.h revision 266408
13263Sdg/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */
26512Sphk
33263Sdg/*-
46512Sphk * Copyright (C) 2003-2004 Olivier Houchard
56512Sphk * Copyright (C) 1994-1997 Mark Brinicombe
63263Sdg * Copyright (C) 1994 Brini
73263Sdg * All rights reserved.
83263Sdg *
93263Sdg * This code is derived from software written for Brini by Mark Brinicombe
103263Sdg *
113263Sdg * Redistribution and use in source and binary forms, with or without
123263Sdg * modification, are permitted provided that the following conditions
133263Sdg * are met:
143264Sdg * 1. Redistributions of source code must retain the above copyright
156512Sphk *    notice, this list of conditions and the following disclaimer.
163263Sdg * 2. Redistributions in binary form must reproduce the above copyright
173263Sdg *    notice, this list of conditions and the following disclaimer in the
183263Sdg *    documentation and/or other materials provided with the distribution.
193263Sdg * 3. All advertising materials mentioning features or use of this software
203263Sdg *    must display the following acknowledgement:
213263Sdg *	This product includes software developed by Brini.
223263Sdg * 4. The name of Brini may not be used to endorse or promote products
233263Sdg *    derived from this software without specific prior written permission.
243263Sdg *
253263Sdg * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
263263Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
273263Sdg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
283263Sdg * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
293263Sdg * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
303263Sdg * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
313263Sdg * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
323263Sdg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
333263Sdg * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
343263Sdg * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
353263Sdg *
363263Sdg * $FreeBSD: stable/10/sys/arm/include/atomic.h 266408 2014-05-18 16:17:13Z ian $
373263Sdg */
383263Sdg
393263Sdg#ifndef	_MACHINE_ATOMIC_H_
403263Sdg#define	_MACHINE_ATOMIC_H_
413263Sdg
423263Sdg#include <sys/types.h>
433263Sdg
443263Sdg#ifndef _KERNEL
453263Sdg#include <machine/sysarch.h>
463263Sdg#else
473263Sdg#include <machine/cpuconf.h>
483263Sdg#endif
493263Sdg
503263Sdg#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
513263Sdg#define isb()  __asm __volatile("isb" : : : "memory")
523263Sdg#define dsb()  __asm __volatile("dsb" : : : "memory")
533263Sdg#define dmb()  __asm __volatile("dmb" : : : "memory")
543263Sdg#elif defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) || \
553263Sdg  defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) || \
563263Sdg  defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)
573263Sdg#define isb()  __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory")
583263Sdg#define dsb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory")
593263Sdg#define dmb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory")
603263Sdg#else
613263Sdg#define isb()  __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory")
623263Sdg#define dsb()  __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory")
633263Sdg#define dmb()  dsb()
643263Sdg#endif
653263Sdg
663263Sdg#define mb()   dmb()
673263Sdg#define wmb()  dmb()
683263Sdg#define rmb()  dmb()
693263Sdg
703263Sdg#ifndef I32_bit
713263Sdg#define I32_bit (1 << 7)        /* IRQ disable */
723263Sdg#endif
733263Sdg#ifndef F32_bit
743263Sdg#define F32_bit (1 << 6)        /* FIQ disable */
753263Sdg#endif
763263Sdg
773263Sdg/*
783263Sdg * It would be nice to use _HAVE_ARMv6_INSTRUCTIONS from machine/asm.h
793263Sdg * here, but that header can't be included here because this is C
803263Sdg * code.  I would like to move the _HAVE_ARMv6_INSTRUCTIONS definition
813263Sdg * out of asm.h so it can be used in both asm and C code. - kientzle@
823263Sdg */
833263Sdg#if defined (__ARM_ARCH_7__) || \
843263Sdg	defined (__ARM_ARCH_7A__)  || \
853263Sdg	defined (__ARM_ARCH_6__)   || \
863263Sdg	defined (__ARM_ARCH_6J__)  || \
873263Sdg	defined (__ARM_ARCH_6K__)  || \
883263Sdg	defined (__ARM_ARCH_6T2__) || \
893263Sdg	defined (__ARM_ARCH_6Z__)  || \
903263Sdg	defined (__ARM_ARCH_6ZK__)
913263Sdgstatic __inline void
923263Sdg__do_dmb(void)
933263Sdg{
943263Sdg
953263Sdg#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
963263Sdg	__asm __volatile("dmb" : : : "memory");
973263Sdg#else
983263Sdg	__asm __volatile("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
993263Sdg#endif
1003263Sdg}
1013263Sdg
1023263Sdg#define ATOMIC_ACQ_REL_LONG(NAME)					\
1033263Sdgstatic __inline void							\
1043263Sdgatomic_##NAME##_acq_long(__volatile u_long *p, u_long v)		\
1053263Sdg{									\
1063263Sdg	atomic_##NAME##_long(p, v);					\
1073263Sdg	__do_dmb();							\
1083263Sdg}									\
1093263Sdg									\
1103263Sdgstatic __inline  void							\
1113263Sdgatomic_##NAME##_rel_long(__volatile u_long *p, u_long v)		\
1123263Sdg{									\
1133263Sdg	__do_dmb();							\
1143263Sdg	atomic_##NAME##_long(p, v);					\
1153263Sdg}
1163263Sdg
1173263Sdg#define	ATOMIC_ACQ_REL(NAME, WIDTH)					\
1183263Sdgstatic __inline  void							\
1193263Sdgatomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
1203263Sdg{									\
1216512Sphk	atomic_##NAME##_##WIDTH(p, v);					\
1223263Sdg	__do_dmb();							\
1233263Sdg}									\
1246512Sphk									\
1256512Sphkstatic __inline  void							\
1266512Sphkatomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
1276512Sphk{									\
1286512Sphk	__do_dmb();							\
1296512Sphk	atomic_##NAME##_##WIDTH(p, v);					\
1306512Sphk}
1316512Sphk
1326512Sphkstatic __inline void
1336512Sphkatomic_set_32(volatile uint32_t *address, uint32_t setmask)
1346512Sphk{
1353263Sdg	uint32_t tmp = 0, tmp2 = 0;
1366512Sphk
1376512Sphk	__asm __volatile("1: ldrex %0, [%2]\n"
1386512Sphk	    		    "orr %0, %0, %3\n"
1393263Sdg			    "strex %1, %0, [%2]\n"
1403263Sdg			    "cmp %1, #0\n"
1413263Sdg	                    "it ne\n"
1426512Sphk			    "bne	1b\n"
1433263Sdg			   : "=&r" (tmp), "+r" (tmp2)
1443263Sdg			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
1453263Sdg
1463263Sdg}
1473263Sdg
1483263Sdgstatic __inline void
1493263Sdgatomic_set_long(volatile u_long *address, u_long setmask)
1503263Sdg{
1513263Sdg	u_long tmp = 0, tmp2 = 0;
1523263Sdg
1533263Sdg	__asm __volatile("1: ldrex %0, [%2]\n"
1543263Sdg	    		    "orr %0, %0, %3\n"
1553263Sdg			    "strex %1, %0, [%2]\n"
1563263Sdg			    "cmp %1, #0\n"
1573263Sdg	                    "it ne\n"
1583263Sdg			    "bne	1b\n"
1593263Sdg			   : "=&r" (tmp), "+r" (tmp2)
1603263Sdg			   , "+r" (address), "+r" (setmask) : : "cc", "memory");
1613263Sdg
1623263Sdg}
1633263Sdg
1643263Sdgstatic __inline void
1653263Sdgatomic_clear_32(volatile uint32_t *address, uint32_t setmask)
1663263Sdg{
1673263Sdg	uint32_t tmp = 0, tmp2 = 0;
1683263Sdg
1696512Sphk	__asm __volatile("1: ldrex %0, [%2]\n"
1703263Sdg	    		    "bic %0, %0, %3\n"
1713263Sdg			    "strex %1, %0, [%2]\n"
1723263Sdg			    "cmp %1, #0\n"
1733263Sdg	                    "it ne\n"
1743263Sdg			    "bne	1b\n"
1753263Sdg			   : "=&r" (tmp), "+r" (tmp2)
1763263Sdg			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
1773263Sdg}
1783263Sdg
1796512Sphkstatic __inline void
1803263Sdgatomic_clear_long(volatile u_long *address, u_long setmask)
1813263Sdg{
1823263Sdg	u_long tmp = 0, tmp2 = 0;
1833263Sdg
1843263Sdg	__asm __volatile("1: ldrex %0, [%2]\n"
1853263Sdg	    		    "bic %0, %0, %3\n"
1866512Sphk			    "strex %1, %0, [%2]\n"
1876512Sphk			    "cmp %1, #0\n"
1883263Sdg	                    "it ne\n"
1896512Sphk			    "bne	1b\n"
1903263Sdg			   : "=&r" (tmp), "+r" (tmp2)
1913263Sdg			   ,"+r" (address), "+r" (setmask) : : "cc", "memory");
192}
193
194static __inline u_int32_t
195atomic_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	                 "itt 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
216static __inline u_long
217atomic_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
238static __inline u_int32_t
239atomic_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
247static __inline u_long
248atomic_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
256static __inline u_int32_t
257atomic_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
264static __inline u_long
265atomic_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
273static __inline void
274atomic_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
288static __inline void
289atomic_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
303static __inline void
304atomic_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
318static __inline void
319atomic_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
333ATOMIC_ACQ_REL(clear, 32)
334ATOMIC_ACQ_REL(add, 32)
335ATOMIC_ACQ_REL(subtract, 32)
336ATOMIC_ACQ_REL(set, 32)
337ATOMIC_ACQ_REL_LONG(clear)
338ATOMIC_ACQ_REL_LONG(add)
339ATOMIC_ACQ_REL_LONG(subtract)
340ATOMIC_ACQ_REL_LONG(set)
341
342#undef ATOMIC_ACQ_REL
343#undef ATOMIC_ACQ_REL_LONG
344
345static __inline uint32_t
346atomic_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_fsxc, %1;"		\
454			: "=r" (cpsr_save), "=r" (tmp)	\
455			: "I" (I32_bit | F32_bit)		\
456		        : "cc" );		\
457		(expr);				\
458		 __asm __volatile(		\
459			"msr  cpsr_fsxc, %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