atomic.h revision 144761
1129198Scognet/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (C) 2003-2004 Olivier Houchard
5129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe
6129198Scognet * Copyright (C) 1994 Brini
7129198Scognet * All rights reserved.
8129198Scognet *
9129198Scognet * This code is derived from software written for Brini by Mark Brinicombe
10129198Scognet *
11129198Scognet * Redistribution and use in source and binary forms, with or without
12129198Scognet * modification, are permitted provided that the following conditions
13129198Scognet * are met:
14129198Scognet * 1. Redistributions of source code must retain the above copyright
15129198Scognet *    notice, this list of conditions and the following disclaimer.
16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
17129198Scognet *    notice, this list of conditions and the following disclaimer in the
18129198Scognet *    documentation and/or other materials provided with the distribution.
19129198Scognet * 3. All advertising materials mentioning features or use of this software
20129198Scognet *    must display the following acknowledgement:
21129198Scognet *	This product includes software developed by Brini.
22129198Scognet * 4. The name of Brini may not be used to endorse or promote products
23129198Scognet *    derived from this software without specific prior written permission.
24129198Scognet *
25129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
26129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35129198Scognet *
36129198Scognet * $FreeBSD: head/sys/arm/include/atomic.h 144761 2005-04-07 22:03:04Z cognet $
37129198Scognet */
38129198Scognet
39129198Scognet#ifndef	_MACHINE_ATOMIC_H_
40129198Scognet#define	_MACHINE_ATOMIC_H_
41129198Scognet
42129198Scognet
43129198Scognet
44129198Scognet#ifndef _LOCORE
45129198Scognet
46129198Scognet#include <sys/types.h>
47129198Scognet
48129198Scognet#ifndef I32_bit
49129198Scognet#define I32_bit (1 << 7)        /* IRQ disable */
50129198Scognet#endif
51129198Scognet#ifndef F32_bit
52129198Scognet#define F32_bit (1 << 6)        /* FIQ disable */
53129198Scognet#endif
54129198Scognet
55129198Scognet#define __with_interrupts_disabled(expr) \
56129198Scognet	do {						\
57129198Scognet		u_int cpsr_save, tmp;			\
58129198Scognet							\
59129198Scognet		__asm __volatile(			\
60129198Scognet			"mrs  %0, cpsr;"		\
61129198Scognet			"orr  %1, %0, %2;"		\
62129198Scognet			"msr  cpsr_all, %1;"		\
63129198Scognet			: "=r" (cpsr_save), "=r" (tmp)	\
64129198Scognet			: "I" (I32_bit)		\
65129198Scognet		        : "cc" );		\
66129198Scognet		(expr);				\
67129198Scognet		 __asm __volatile(		\
68129198Scognet			"msr  cpsr_all, %0"	\
69129198Scognet			: /* no output */	\
70129198Scognet			: "r" (cpsr_save)	\
71129198Scognet			: "cc" );		\
72129198Scognet	} while(0)
73129198Scognet
74144761Scognet#define ARM_RAS_START	0xe0000004
75144761Scognet#define ARM_RAS_END	0xe0000008
76144761Scognet
77137222Scognetstatic __inline uint32_t
78137222Scognet__swp(uint32_t val, volatile uint32_t *ptr)
79129198Scognet{
80137222Scognet	__asm __volatile("swp	%0, %1, [%2]"
81139021Scognet	    : "=&r" (val) : "r" (val) , "r" (ptr) : "memory");
82137222Scognet	return (val);
83129198Scognet}
84129198Scognet
85137222Scognet
86144761Scognet#ifdef _KERNEL
87129198Scognetstatic __inline void
88137222Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask)
89129198Scognet{
90144761Scognet	__with_interrupts_disabled(*address |= setmask);
91129198Scognet}
92129198Scognet
93129198Scognetstatic __inline void
94129198Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
95129198Scognet{
96144761Scognet	__with_interrupts_disabled(*address &= ~clearmask);
97129198Scognet}
98129198Scognet
99144761Scognetstatic __inline u_int32_t
100144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
101129198Scognet{
102144761Scognet	int ret;
103144761Scognet
104144761Scognet	__with_interrupts_disabled(
105144761Scognet	 {
106144761Scognet	    	if (*p == cmpval) {
107144761Scognet			*p = newval;
108144761Scognet			ret = 1;
109144761Scognet		} else {
110144761Scognet			ret = 0;
111144761Scognet		}
112144761Scognet	});
113144761Scognet	return (ret);
114129198Scognet}
115129198Scognet
116129198Scognetstatic __inline void
117144761Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val)
118129198Scognet{
119144761Scognet	__with_interrupts_disabled(*p += val);
120129198Scognet}
121129198Scognet
122144761Scognetstatic __inline void
123144761Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
124129198Scognet{
125144761Scognet	__with_interrupts_disabled(*p -= val);
126129198Scognet}
127129198Scognet
128144761Scognet#else /* !_KERNEL */
129144761Scognet
130129198Scognetstatic __inline u_int32_t
131144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
132129198Scognet{
133144761Scognet	register int done, ras_start;
134144761Scognet
135144761Scognet	__asm __volatile("1:\n"
136144761Scognet	    "mov	%0, #0xe0000008\n"
137144761Scognet	    "adr	%1, 2f\n"
138144761Scognet	    "str	%1, [%0]\n"
139144761Scognet	    "adr	%1, 1b\n"
140144761Scognet	    "mov	%0, #0xe0000004\n"
141144761Scognet	    "str	%1, [%0]\n"
142144761Scognet	    "ldr	%1, [%2]\n"
143144761Scognet	    "cmp	%1, %3\n"
144144761Scognet	    "streq	%4, [%2]\n"
145144761Scognet	    "2:\n"
146144761Scognet	    "moveq	%1, #1\n"
147144761Scognet	    "movne	%1, #0\n"
148144761Scognet	    : "=r" (ras_start), "=r" (done)
149144761Scognet	    ,"+r" (p), "+r" (cmpval), "+r" (newval));
150137282Scognet	return (done);
151129198Scognet}
152129198Scognet
153129198Scognetstatic __inline void
154129198Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val)
155129198Scognet{
156144761Scognet	int ras_start, start;
157144761Scognet
158144761Scognet	__asm __volatile("1:\n"
159144761Scognet	    "mov	%0, #0xe0000008\n"
160144761Scognet	    "adr	%1, 2f\n"
161144761Scognet	    "str	%1, [%0]\n"
162144761Scognet	    "adr	%1, 1b\n"
163144761Scognet	    "mov	%0, #0xe0000004\n"
164144761Scognet	    "str	%1, [%0]\n"
165144761Scognet	    "ldr	%1, [%2]\n"
166144761Scognet	    "add	%1, %1, %3\n"
167144761Scognet	    "str	%1, [%2]\n"
168144761Scognet	    "2:\n"
169144761Scognet	    : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val));
170129198Scognet}
171129198Scognet
172129198Scognetstatic __inline void
173129198Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
174129198Scognet{
175144761Scognet	int ras_start, start;
176144761Scognet
177144761Scognet	__asm __volatile("1:\n"
178144761Scognet	    "mov	%0, #0xe0000008\n"
179144761Scognet	    "adr	%1, 2f\n"
180144761Scognet	    "str	%1, [%0]\n"
181144761Scognet	    "adr	%1, 1b\n"
182144761Scognet	    "mov	%0, #0xe0000004\n"
183144761Scognet	    "str	%1, [%0]\n"
184144761Scognet	    "ldr	%1, [%2]\n"
185144761Scognet	    "sub	%1, %1, %3\n"
186144761Scognet	    "str	%1, [%2]\n"
187144761Scognet	    "2:\n"
188144761Scognet	    : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val));
189129198Scognet}
190129198Scognet
191144761Scognetstatic __inline void
192144761Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask)
193144761Scognet{
194144761Scognet	int ras_start, start;
195144761Scognet
196144761Scognet	__asm __volatile("1:\n"
197144761Scognet	    "mov	%0, #0xe0000008\n"
198144761Scognet	    "adr	%1, 2f\n"
199144761Scognet	    "str	%1, [%0]\n"
200144761Scognet	    "adr	%1, 1b\n"
201144761Scognet	    "mov	%0, #0xe0000004\n"
202144761Scognet	    "str	%1, [%0]\n"
203144761Scognet	    "ldr	%1, [%2]\n"
204144761Scognet	    "orr	%1, %1, %3\n"
205144761Scognet	    "str	%1, [%2]\n"
206144761Scognet	    "2:\n"
207144761Scognet	    : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask));
208144761Scognet}
209144761Scognet
210144761Scognetstatic __inline void
211144761Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
212144761Scognet{
213144761Scognet	int ras_start, start;
214144761Scognet
215144761Scognet	__asm __volatile("1:\n"
216144761Scognet	    "mov	%0, #0xe0000008\n"
217144761Scognet	    "adr	%1, 2f\n"
218144761Scognet	    "str	%1, [%0]\n"
219144761Scognet	    "adr	%1, 1b\n"
220144761Scognet	    "mov	%0, #0xe0000004\n"
221144761Scognet	    "str	%1, [%0]\n"
222144761Scognet	    "ldr	%1, [%2]\n"
223144761Scognet	    "bic	%1, %1, %3\n"
224144761Scognet	    "str	%1, [%2]\n"
225144761Scognet	    "2:\n"
226144761Scognet	    : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask));
227144761Scognet
228144761Scognet}
229144761Scognet#endif /* _KERNEL */
230144761Scognet
231144761Scognetstatic __inline int
232144761Scognetatomic_load_32(volatile uint32_t *v)
233144761Scognet{
234144761Scognet
235144761Scognet	return (*v);
236144761Scognet}
237144761Scognet
238144761Scognetstatic __inline void
239144761Scognetatomic_store_32(volatile uint32_t *dst, uint32_t src)
240144761Scognet{
241144761Scognet	*dst = src;
242144761Scognet}
243144761Scognet
244144761Scognetstatic __inline uint32_t
245144761Scognetatomic_readandclear_32(volatile u_int32_t *p)
246144761Scognet{
247144761Scognet
248144761Scognet	return (__swp(0, p));
249144761Scognet}
250144761Scognet
251137222Scognet#undef __with_interrupts_disabled
252129198Scognet
253137222Scognet#endif /* _LOCORE */
254129198Scognet
255129198Scognet
256137222Scognet#define atomic_set_rel_int		atomic_set_32
257137222Scognet#define atomic_set_int			atomic_set_32
258137222Scognet#define atomic_readandclear_int		atomic_readandclear_32
259137222Scognet#define atomic_clear_int		atomic_clear_32
260137222Scognet#define atomic_subtract_int		atomic_subtract_32
261137222Scognet#define atomic_subtract_rel_int		atomic_subtract_32
262137222Scognet#define atomic_subtract_acq_int		atomic_subtract_32
263137222Scognet#define atomic_add_int			atomic_add_32
264137222Scognet#define atomic_add_rel_int		atomic_add_32
265137222Scognet#define atomic_add_acq_int		atomic_add_32
266137222Scognet#define atomic_cmpset_int		atomic_cmpset_32
267137222Scognet#define atomic_cmpset_rel_int		atomic_cmpset_32
268137222Scognet#define atomic_cmpset_rel_ptr		atomic_cmpset_ptr
269137222Scognet#define atomic_cmpset_acq_int		atomic_cmpset_32
270137222Scognet#define atomic_cmpset_acq_ptr		atomic_cmpset_ptr
271137222Scognet#define atomic_store_rel_ptr		atomic_store_ptr
272137222Scognet#define atomic_store_rel_int		atomic_store_32
273137222Scognet#define atomic_cmpset_rel_32		atomic_cmpset_32
274137222Scognet#define atomic_smpset_rel_ptr		atomic_cmpset_ptr
275137222Scognet#define atomic_load_acq_int		atomic_load_32
276137222Scognet#define atomic_clear_ptr(ptr, bit)	atomic_clear_32( \
277137222Scognet    (volatile uint32_t *)ptr, (uint32_t)bit)
278137222Scognet#define atomic_store_ptr(ptr, bit)	atomic_store_32( \
279137222Scognet    (volatile uint32_t *)ptr, (uint32_t)bit)
280137222Scognet#define atomic_cmpset_ptr(dst, exp, s)	atomic_cmpset_32( \
281137222Scognet    (volatile uint32_t *)dst, (uint32_t)exp, (uint32_t)s)
282137222Scognet#define atomic_set_ptr(ptr, src)	atomic_set_32( \
283137222Scognet    (volatile uint32_t *)ptr,  (uint32_t)src)
284129198Scognet
285129198Scognet#endif /* _MACHINE_ATOMIC_H_ */
286