atomic.h revision 165786
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 165786 2007-01-05 02:50:27Z ticso $
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)	\
64157725Scognet			: "I" (I32_bit | F32_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{
80148453Sjhb	__asm __volatile("swp	%0, %2, [%3]"
81148453Sjhb	    : "=&r" (val), "=m" (*ptr)
82151340Sjhb	    : "r" (val), "r" (ptr), "m" (*ptr)
83148453Sjhb	    : "memory");
84137222Scognet	return (val);
85129198Scognet}
86129198Scognet
87137222Scognet
88144761Scognet#ifdef _KERNEL
89129198Scognetstatic __inline void
90137222Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask)
91129198Scognet{
92144761Scognet	__with_interrupts_disabled(*address |= setmask);
93129198Scognet}
94129198Scognet
95129198Scognetstatic __inline void
96129198Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
97129198Scognet{
98144761Scognet	__with_interrupts_disabled(*address &= ~clearmask);
99129198Scognet}
100129198Scognet
101144761Scognetstatic __inline u_int32_t
102144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
103129198Scognet{
104144761Scognet	int ret;
105144761Scognet
106144761Scognet	__with_interrupts_disabled(
107144761Scognet	 {
108144761Scognet	    	if (*p == cmpval) {
109144761Scognet			*p = newval;
110144761Scognet			ret = 1;
111144761Scognet		} else {
112144761Scognet			ret = 0;
113144761Scognet		}
114144761Scognet	});
115144761Scognet	return (ret);
116129198Scognet}
117129198Scognet
118129198Scognetstatic __inline void
119144761Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val)
120129198Scognet{
121144761Scognet	__with_interrupts_disabled(*p += val);
122129198Scognet}
123129198Scognet
124144761Scognetstatic __inline void
125144761Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
126129198Scognet{
127144761Scognet	__with_interrupts_disabled(*p -= val);
128129198Scognet}
129129198Scognet
130150627Sjhbstatic __inline uint32_t
131150627Sjhbatomic_fetchadd_32(volatile uint32_t *p, uint32_t v)
132150627Sjhb{
133150627Sjhb	uint32_t value;
134150627Sjhb
135150627Sjhb	__with_interrupts_disabled(
136150627Sjhb	{
137150627Sjhb	    	value = *p;
138150627Sjhb		*p += v;
139150627Sjhb	});
140150627Sjhb	return (value);
141150627Sjhb}
142150627Sjhb
143144761Scognet#else /* !_KERNEL */
144144761Scognet
145129198Scognetstatic __inline u_int32_t
146144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
147129198Scognet{
148144761Scognet	register int done, ras_start;
149144761Scognet
150144761Scognet	__asm __volatile("1:\n"
151144761Scognet	    "mov	%0, #0xe0000008\n"
152144761Scognet	    "adr	%1, 2f\n"
153144761Scognet	    "str	%1, [%0]\n"
154144761Scognet	    "adr	%1, 1b\n"
155144761Scognet	    "mov	%0, #0xe0000004\n"
156144761Scognet	    "str	%1, [%0]\n"
157155355Scognet	    "ldr	%1, [%2]\n"
158144761Scognet	    "cmp	%1, %3\n"
159155355Scognet	    "streq	%4, [%2]\n"
160144761Scognet	    "2:\n"
161146591Scognet	    "mov	%1, #0\n"
162146591Scognet	    "str	%1, [%0]\n"
163144761Scognet	    "moveq	%1, #1\n"
164144761Scognet	    "movne	%1, #0\n"
165144761Scognet	    : "=r" (ras_start), "=r" (done)
166155391Scognet	    ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory");
167137282Scognet	return (done);
168129198Scognet}
169129198Scognet
170129198Scognetstatic __inline void
171129198Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val)
172129198Scognet{
173144761Scognet	int ras_start, start;
174144761Scognet
175144761Scognet	__asm __volatile("1:\n"
176144761Scognet	    "mov	%0, #0xe0000008\n"
177144761Scognet	    "adr	%1, 2f\n"
178144761Scognet	    "str	%1, [%0]\n"
179144761Scognet	    "adr	%1, 1b\n"
180144761Scognet	    "mov	%0, #0xe0000004\n"
181144761Scognet	    "str	%1, [%0]\n"
182155355Scognet	    "ldr	%1, [%2]\n"
183144761Scognet	    "add	%1, %1, %3\n"
184155355Scognet	    "str	%1, [%2]\n"
185144761Scognet	    "2:\n"
186146591Scognet	    "mov	%1, #0\n"
187146591Scognet	    "str	%1, [%0]\n"
188155391Scognet	    : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val)
189155391Scognet	    : : "memory");
190129198Scognet}
191129198Scognet
192129198Scognetstatic __inline void
193129198Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
194129198Scognet{
195144761Scognet	int ras_start, start;
196144761Scognet
197144761Scognet	__asm __volatile("1:\n"
198144761Scognet	    "mov	%0, #0xe0000008\n"
199144761Scognet	    "adr	%1, 2f\n"
200144761Scognet	    "str	%1, [%0]\n"
201144761Scognet	    "adr	%1, 1b\n"
202144761Scognet	    "mov	%0, #0xe0000004\n"
203144761Scognet	    "str	%1, [%0]\n"
204155355Scognet	    "ldr	%1, [%2]\n"
205144761Scognet	    "sub	%1, %1, %3\n"
206155355Scognet	    "str	%1, [%2]\n"
207144761Scognet	    "2:\n"
208146591Scognet	    "mov	%1, #0\n"
209146591Scognet	    "str	%1, [%0]\n"
210146591Scognet
211155391Scognet	    : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val)
212155391Scognet	    : : "memory");
213129198Scognet}
214129198Scognet
215144761Scognetstatic __inline void
216144761Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask)
217144761Scognet{
218144761Scognet	int ras_start, start;
219144761Scognet
220144761Scognet	__asm __volatile("1:\n"
221144761Scognet	    "mov	%0, #0xe0000008\n"
222144761Scognet	    "adr	%1, 2f\n"
223144761Scognet	    "str	%1, [%0]\n"
224144761Scognet	    "adr	%1, 1b\n"
225144761Scognet	    "mov	%0, #0xe0000004\n"
226144761Scognet	    "str	%1, [%0]\n"
227155355Scognet	    "ldr	%1, [%2]\n"
228144761Scognet	    "orr	%1, %1, %3\n"
229155355Scognet	    "str	%1, [%2]\n"
230144761Scognet	    "2:\n"
231146591Scognet	    "mov	%1, #0\n"
232146591Scognet	    "str	%1, [%0]\n"
233146591Scognet
234155391Scognet	    : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask)
235155391Scognet	    : : "memory");
236144761Scognet}
237144761Scognet
238144761Scognetstatic __inline void
239144761Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
240144761Scognet{
241144761Scognet	int ras_start, start;
242144761Scognet
243144761Scognet	__asm __volatile("1:\n"
244144761Scognet	    "mov	%0, #0xe0000008\n"
245144761Scognet	    "adr	%1, 2f\n"
246144761Scognet	    "str	%1, [%0]\n"
247144761Scognet	    "adr	%1, 1b\n"
248144761Scognet	    "mov	%0, #0xe0000004\n"
249144761Scognet	    "str	%1, [%0]\n"
250155355Scognet	    "ldr	%1, [%2]\n"
251144761Scognet	    "bic	%1, %1, %3\n"
252155355Scognet	    "str	%1, [%2]\n"
253144761Scognet	    "2:\n"
254146591Scognet	    "mov	%1, #0\n"
255146591Scognet	    "str	%1, [%0]\n"
256155391Scognet	    : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask)
257155391Scognet	    : : "memory");
258144761Scognet
259144761Scognet}
260150627Sjhb
261150627Sjhbstatic __inline uint32_t
262150627Sjhbatomic_fetchadd_32(volatile uint32_t *p, uint32_t v)
263150627Sjhb{
264150627Sjhb	uint32_t ras_start, start;
265150627Sjhb
266150627Sjhb	__asm __volatile("1:\n"
267150627Sjhb	    "mov	%0, #0xe0000008\n"
268150627Sjhb	    "adr	%1, 2f\n"
269150627Sjhb	    "str	%1, [%0]\n"
270150627Sjhb	    "adr	%1, 1b\n"
271150627Sjhb	    "mov	%0, #0xe0000004\n"
272150627Sjhb	    "str	%1, [%0]\n"
273155355Scognet	    "ldr	%1, [%2]\n"
274150627Sjhb	    "add	%3, %1, %3\n"
275155355Scognet	    "str	%3, [%2]\n"
276150627Sjhb	    "2:\n"
277150627Sjhb	    "mov	%3, #0\n"
278150627Sjhb	    "str	%3, [%0]\n"
279155391Scognet	    : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (v)
280155391Scognet	    : : "memory");
281150627Sjhb	return (start);
282150627Sjhb}
283150627Sjhb
284150627Sjhb
285144761Scognet#endif /* _KERNEL */
286144761Scognet
287144761Scognetstatic __inline int
288144761Scognetatomic_load_32(volatile uint32_t *v)
289144761Scognet{
290144761Scognet
291144761Scognet	return (*v);
292144761Scognet}
293144761Scognet
294144761Scognetstatic __inline void
295144761Scognetatomic_store_32(volatile uint32_t *dst, uint32_t src)
296144761Scognet{
297144761Scognet	*dst = src;
298144761Scognet}
299144761Scognet
300144761Scognetstatic __inline uint32_t
301144761Scognetatomic_readandclear_32(volatile u_int32_t *p)
302144761Scognet{
303144761Scognet
304144761Scognet	return (__swp(0, p));
305144761Scognet}
306144761Scognet
307137222Scognet#undef __with_interrupts_disabled
308129198Scognet
309137222Scognet#endif /* _LOCORE */
310129198Scognet
311165786Sticso#define	atomic_add_long(p, v) \
312165786Sticso	atomic_add_32((volatile u_int *)(p), (u_int)(v))
313165786Sticso#define atomic_add_acq_long		atomic_add_long
314165786Sticso#define atomic_add_rel_long		atomic_add_long
315165786Sticso#define	atomic_subtract_long(p, v) \
316165786Sticso	atomic_subtract_32((volatile u_int *)(p), (u_int)(v))
317165786Sticso#define atomic_subtract_acq_long	atomic_subtract_long
318165786Sticso#define atomic_subtract_rel_long	atomic_subtract_long
319165786Sticso#define	atomic_clear_long(p, v) \
320165786Sticso	atomic_clear_32((volatile u_int *)(p), (u_int)(v))
321165786Sticso#define atomic_clear_acq_long		atomic_clear_long
322165786Sticso#define atomic_clear_rel_long		atomic_clear_long
323165786Sticso#define	atomic_set_long(p, v) \
324165786Sticso	atomic_set_32((volatile u_int *)(p), (u_int)(v))
325165786Sticso#define atomic_set_acq_long		atomic_set_long
326165786Sticso#define atomic_set_rel_long		atomic_set_long
327165786Sticso#define	atomic_cmpset_long(dst, old, new) \
328165786Sticso	atomic_cmpset_32((volatile u_int *)(dst), (u_int)(old), (u_int)(new))
329165786Sticso#define atomic_cmpset_acq_long		atomic_cmpset_long
330165786Sticso#define atomic_cmpset_rel_long		atomic_cmpset_long
331165786Sticso#define	atomic_fetchadd_long(p, v) \
332165786Sticso	atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v))
333165786Sticso#define	atomic_readandclear_long(p) \
334165786Sticso	atomic_readandclear_long((volatile u_int *)(p))
335165786Sticso#define	atomic_load_long(p) \
336165786Sticso	atomic_load_32((volatile u_int *)(p))
337165786Sticso#define atomic_load_acq_long		atomic_load_long
338165786Sticso#define	atomic_store_rel_long(p, v) \
339165786Sticso	atomic_store_rel_32((volatile u_int *)(p), (u_int)(v))
340129198Scognet
341153276Scognet
342165786Sticso#define atomic_clear_ptr		atomic_clear_32
343165786Sticso#define atomic_set_ptr			atomic_set_32
344165786Sticso#define atomic_cmpset_ptr		atomic_cmpset_32
345165786Sticso#define atomic_cmpset_rel_ptr		atomic_cmpset_ptr
346165786Sticso#define atomic_cmpset_acq_ptr		atomic_cmpset_ptr
347165786Sticso#define atomic_store_ptr		atomic_store_32
348165786Sticso#define atomic_store_rel_ptr		atomic_store_ptr
349165786Sticso
350165786Sticso#define atomic_add_int			atomic_add_32
351165786Sticso#define atomic_add_acq_int		atomic_add_int
352165786Sticso#define atomic_add_rel_int		atomic_add_int
353165786Sticso#define atomic_subtract_int		atomic_subtract_32
354165786Sticso#define atomic_subtract_acq_int		atomic_subtract_int
355165786Sticso#define atomic_subtract_rel_int		atomic_subtract_int
356165786Sticso#define atomic_clear_int		atomic_clear_32
357165786Sticso#define atomic_clear_acq_int		atomic_clear_int
358165786Sticso#define atomic_clear_rel_int		atomic_clear_int
359137222Scognet#define atomic_set_int			atomic_set_32
360165786Sticso#define atomic_set_acq_int		atomic_set_int
361165786Sticso#define atomic_set_rel_int		atomic_set_int
362165786Sticso#define atomic_cmpset_int		atomic_cmpset_32
363165786Sticso#define atomic_cmpset_acq_int		atomic_cmpset_int
364165786Sticso#define atomic_cmpset_rel_int		atomic_cmpset_int
365165786Sticso#define atomic_fetchadd_int		atomic_fetchadd_32
366137222Scognet#define atomic_readandclear_int		atomic_readandclear_32
367165786Sticso#define atomic_load_acq_int		atomic_load_32
368165786Sticso#define atomic_store_rel_int		atomic_store_32
369165786Sticso
370165786Sticso#define atomic_add_acq_32		atomic_add_32
371165786Sticso#define atomic_add_rel_32		atomic_add_32
372165786Sticso#define atomic_subtract_acq_32		atomic_subtract_32
373158593Scognet#define atomic_subtract_rel_32		atomic_subtract_32
374165786Sticso#define atomic_clear_acq_32		atomic_clear_32
375165786Sticso#define atomic_clear_rel_32		atomic_clear_32
376165786Sticso#define atomic_set_acq_32		atomic_set_32
377165786Sticso#define atomic_set_rel_32		atomic_set_32
378164059Scognet#define atomic_cmpset_acq_32		atomic_cmpset_32
379137222Scognet#define atomic_cmpset_rel_32		atomic_cmpset_32
380158593Scognet#define atomic_load_acq_32		atomic_load_32
381165786Sticso#define atomic_store_rel_32		atomic_store_32
382129198Scognet
383129198Scognet#endif /* _MACHINE_ATOMIC_H_ */
384