1 /* MN10300 Atomic counter operations
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #ifndef _ASM_ATOMIC_H
12 #define _ASM_ATOMIC_H
13 
14 #include <asm/irqflags.h>
15 
16 #ifndef __ASSEMBLY__
17 
18 #ifdef CONFIG_SMP
19 #ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
20 static inline
__xchg(volatile unsigned long * m,unsigned long val)21 unsigned long __xchg(volatile unsigned long *m, unsigned long val)
22 {
23 	unsigned long status;
24 	unsigned long oldval;
25 
26 	asm volatile(
27 		"1:	mov	%4,(_AAR,%3)	\n"
28 		"	mov	(_ADR,%3),%1	\n"
29 		"	mov	%5,(_ADR,%3)	\n"
30 		"	mov	(_ADR,%3),%0	\n"	/* flush */
31 		"	mov	(_ASR,%3),%0	\n"
32 		"	or	%0,%0		\n"
33 		"	bne	1b		\n"
34 		: "=&r"(status), "=&r"(oldval), "=m"(*m)
35 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
36 		: "memory", "cc");
37 
38 	return oldval;
39 }
40 
__cmpxchg(volatile unsigned long * m,unsigned long old,unsigned long new)41 static inline unsigned long __cmpxchg(volatile unsigned long *m,
42 				      unsigned long old, unsigned long new)
43 {
44 	unsigned long status;
45 	unsigned long oldval;
46 
47 	asm volatile(
48 		"1:	mov	%4,(_AAR,%3)	\n"
49 		"	mov	(_ADR,%3),%1	\n"
50 		"	cmp	%5,%1		\n"
51 		"	bne	2f		\n"
52 		"	mov	%6,(_ADR,%3)	\n"
53 		"2:	mov	(_ADR,%3),%0	\n"	/* flush */
54 		"	mov	(_ASR,%3),%0	\n"
55 		"	or	%0,%0		\n"
56 		"	bne	1b		\n"
57 		: "=&r"(status), "=&r"(oldval), "=m"(*m)
58 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
59 		  "r"(old), "r"(new)
60 		: "memory", "cc");
61 
62 	return oldval;
63 }
64 #else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
65 #error "No SMP atomic operation support!"
66 #endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
67 
68 #else  /* CONFIG_SMP */
69 
70 /*
71  * Emulate xchg for non-SMP MN10300
72  */
73 struct __xchg_dummy { unsigned long a[100]; };
74 #define __xg(x) ((struct __xchg_dummy *)(x))
75 
76 static inline
__xchg(volatile unsigned long * m,unsigned long val)77 unsigned long __xchg(volatile unsigned long *m, unsigned long val)
78 {
79 	unsigned long oldval;
80 	unsigned long flags;
81 
82 	flags = arch_local_cli_save();
83 	oldval = *m;
84 	*m = val;
85 	arch_local_irq_restore(flags);
86 	return oldval;
87 }
88 
89 /*
90  * Emulate cmpxchg for non-SMP MN10300
91  */
__cmpxchg(volatile unsigned long * m,unsigned long old,unsigned long new)92 static inline unsigned long __cmpxchg(volatile unsigned long *m,
93 				      unsigned long old, unsigned long new)
94 {
95 	unsigned long oldval;
96 	unsigned long flags;
97 
98 	flags = arch_local_cli_save();
99 	oldval = *m;
100 	if (oldval == old)
101 		*m = new;
102 	arch_local_irq_restore(flags);
103 	return oldval;
104 }
105 
106 #endif /* CONFIG_SMP */
107 
108 #define xchg(ptr, v)						\
109 	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
110 				     (unsigned long)(v)))
111 
112 #define cmpxchg(ptr, o, n)					\
113 	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
114 					(unsigned long)(o),	\
115 					(unsigned long)(n)))
116 
117 #define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
118 #define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
119 
120 #endif /* !__ASSEMBLY__ */
121 
122 #ifndef CONFIG_SMP
123 #include <asm-generic/atomic.h>
124 #else
125 
126 /*
127  * Atomic operations that C can't guarantee us.  Useful for
128  * resource counting etc..
129  */
130 
131 #define ATOMIC_INIT(i)	{ (i) }
132 
133 #ifdef __KERNEL__
134 
135 /**
136  * atomic_read - read atomic variable
137  * @v: pointer of type atomic_t
138  *
139  * Atomically reads the value of @v.  Note that the guaranteed
140  * useful range of an atomic_t is only 24 bits.
141  */
142 #define atomic_read(v)	(ACCESS_ONCE((v)->counter))
143 
144 /**
145  * atomic_set - set atomic variable
146  * @v: pointer of type atomic_t
147  * @i: required value
148  *
149  * Atomically sets the value of @v to @i.  Note that the guaranteed
150  * useful range of an atomic_t is only 24 bits.
151  */
152 #define atomic_set(v, i) (((v)->counter) = (i))
153 
154 /**
155  * atomic_add_return - add integer to atomic variable
156  * @i: integer value to add
157  * @v: pointer of type atomic_t
158  *
159  * Atomically adds @i to @v and returns the result
160  * Note that the guaranteed useful range of an atomic_t is only 24 bits.
161  */
atomic_add_return(int i,atomic_t * v)162 static inline int atomic_add_return(int i, atomic_t *v)
163 {
164 	int retval;
165 #ifdef CONFIG_SMP
166 	int status;
167 
168 	asm volatile(
169 		"1:	mov	%4,(_AAR,%3)	\n"
170 		"	mov	(_ADR,%3),%1	\n"
171 		"	add	%5,%1		\n"
172 		"	mov	%1,(_ADR,%3)	\n"
173 		"	mov	(_ADR,%3),%0	\n"	/* flush */
174 		"	mov	(_ASR,%3),%0	\n"
175 		"	or	%0,%0		\n"
176 		"	bne	1b		\n"
177 		: "=&r"(status), "=&r"(retval), "=m"(v->counter)
178 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
179 		: "memory", "cc");
180 
181 #else
182 	unsigned long flags;
183 
184 	flags = arch_local_cli_save();
185 	retval = v->counter;
186 	retval += i;
187 	v->counter = retval;
188 	arch_local_irq_restore(flags);
189 #endif
190 	return retval;
191 }
192 
193 /**
194  * atomic_sub_return - subtract integer from atomic variable
195  * @i: integer value to subtract
196  * @v: pointer of type atomic_t
197  *
198  * Atomically subtracts @i from @v and returns the result
199  * Note that the guaranteed useful range of an atomic_t is only 24 bits.
200  */
atomic_sub_return(int i,atomic_t * v)201 static inline int atomic_sub_return(int i, atomic_t *v)
202 {
203 	int retval;
204 #ifdef CONFIG_SMP
205 	int status;
206 
207 	asm volatile(
208 		"1:	mov	%4,(_AAR,%3)	\n"
209 		"	mov	(_ADR,%3),%1	\n"
210 		"	sub	%5,%1		\n"
211 		"	mov	%1,(_ADR,%3)	\n"
212 		"	mov	(_ADR,%3),%0	\n"	/* flush */
213 		"	mov	(_ASR,%3),%0	\n"
214 		"	or	%0,%0		\n"
215 		"	bne	1b		\n"
216 		: "=&r"(status), "=&r"(retval), "=m"(v->counter)
217 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
218 		: "memory", "cc");
219 
220 #else
221 	unsigned long flags;
222 	flags = arch_local_cli_save();
223 	retval = v->counter;
224 	retval -= i;
225 	v->counter = retval;
226 	arch_local_irq_restore(flags);
227 #endif
228 	return retval;
229 }
230 
atomic_add_negative(int i,atomic_t * v)231 static inline int atomic_add_negative(int i, atomic_t *v)
232 {
233 	return atomic_add_return(i, v) < 0;
234 }
235 
atomic_add(int i,atomic_t * v)236 static inline void atomic_add(int i, atomic_t *v)
237 {
238 	atomic_add_return(i, v);
239 }
240 
atomic_sub(int i,atomic_t * v)241 static inline void atomic_sub(int i, atomic_t *v)
242 {
243 	atomic_sub_return(i, v);
244 }
245 
atomic_inc(atomic_t * v)246 static inline void atomic_inc(atomic_t *v)
247 {
248 	atomic_add_return(1, v);
249 }
250 
atomic_dec(atomic_t * v)251 static inline void atomic_dec(atomic_t *v)
252 {
253 	atomic_sub_return(1, v);
254 }
255 
256 #define atomic_dec_return(v)		atomic_sub_return(1, (v))
257 #define atomic_inc_return(v)		atomic_add_return(1, (v))
258 
259 #define atomic_sub_and_test(i, v)	(atomic_sub_return((i), (v)) == 0)
260 #define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
261 #define atomic_inc_and_test(v)		(atomic_add_return(1, (v)) == 0)
262 
263 #define __atomic_add_unless(v, a, u)				\
264 ({								\
265 	int c, old;						\
266 	c = atomic_read(v);					\
267 	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
268 		c = old;					\
269 	c;							\
270 })
271 
272 
273 /**
274  * atomic_clear_mask - Atomically clear bits in memory
275  * @mask: Mask of the bits to be cleared
276  * @v: pointer to word in memory
277  *
278  * Atomically clears the bits set in mask from the memory word specified.
279  */
atomic_clear_mask(unsigned long mask,unsigned long * addr)280 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
281 {
282 #ifdef CONFIG_SMP
283 	int status;
284 
285 	asm volatile(
286 		"1:	mov	%3,(_AAR,%2)	\n"
287 		"	mov	(_ADR,%2),%0	\n"
288 		"	and	%4,%0		\n"
289 		"	mov	%0,(_ADR,%2)	\n"
290 		"	mov	(_ADR,%2),%0	\n"	/* flush */
291 		"	mov	(_ASR,%2),%0	\n"
292 		"	or	%0,%0		\n"
293 		"	bne	1b		\n"
294 		: "=&r"(status), "=m"(*addr)
295 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
296 		: "memory", "cc");
297 #else
298 	unsigned long flags;
299 
300 	mask = ~mask;
301 	flags = arch_local_cli_save();
302 	*addr &= mask;
303 	arch_local_irq_restore(flags);
304 #endif
305 }
306 
307 /**
308  * atomic_set_mask - Atomically set bits in memory
309  * @mask: Mask of the bits to be set
310  * @v: pointer to word in memory
311  *
312  * Atomically sets the bits set in mask from the memory word specified.
313  */
atomic_set_mask(unsigned long mask,unsigned long * addr)314 static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
315 {
316 #ifdef CONFIG_SMP
317 	int status;
318 
319 	asm volatile(
320 		"1:	mov	%3,(_AAR,%2)	\n"
321 		"	mov	(_ADR,%2),%0	\n"
322 		"	or	%4,%0		\n"
323 		"	mov	%0,(_ADR,%2)	\n"
324 		"	mov	(_ADR,%2),%0	\n"	/* flush */
325 		"	mov	(_ASR,%2),%0	\n"
326 		"	or	%0,%0		\n"
327 		"	bne	1b		\n"
328 		: "=&r"(status), "=m"(*addr)
329 		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
330 		: "memory", "cc");
331 #else
332 	unsigned long flags;
333 
334 	flags = arch_local_cli_save();
335 	*addr |= mask;
336 	arch_local_irq_restore(flags);
337 #endif
338 }
339 
340 /* Atomic operations are already serializing on MN10300??? */
341 #define smp_mb__before_atomic_dec()	barrier()
342 #define smp_mb__after_atomic_dec()	barrier()
343 #define smp_mb__before_atomic_inc()	barrier()
344 #define smp_mb__after_atomic_inc()	barrier()
345 
346 #endif /* __KERNEL__ */
347 #endif /* CONFIG_SMP */
348 #endif /* _ASM_ATOMIC_H */
349