1 #ifndef _ASM_M32R_ATOMIC_H
2 #define _ASM_M32R_ATOMIC_H
3 
4 /*
5  *  linux/include/asm-m32r/atomic.h
6  *
7  *  M32R version:
8  *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
9  *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
10  */
11 
12 #include <linux/types.h>
13 #include <asm/assembler.h>
14 #include <asm/cmpxchg.h>
15 #include <asm/dcache_clear.h>
16 
17 /*
18  * Atomic operations that C can't guarantee us.  Useful for
19  * resource counting etc..
20  */
21 
22 #define ATOMIC_INIT(i)	{ (i) }
23 
24 /**
25  * atomic_read - read atomic variable
26  * @v: pointer of type atomic_t
27  *
28  * Atomically reads the value of @v.
29  */
30 #define atomic_read(v)	(*(volatile int *)&(v)->counter)
31 
32 /**
33  * atomic_set - set atomic variable
34  * @v: pointer of type atomic_t
35  * @i: required value
36  *
37  * Atomically sets the value of @v to @i.
38  */
39 #define atomic_set(v,i)	(((v)->counter) = (i))
40 
41 /**
42  * atomic_add_return - add integer to atomic variable and return it
43  * @i: integer value to add
44  * @v: pointer of type atomic_t
45  *
46  * Atomically adds @i to @v and return (@i + @v).
47  */
atomic_add_return(int i,atomic_t * v)48 static __inline__ int atomic_add_return(int i, atomic_t *v)
49 {
50 	unsigned long flags;
51 	int result;
52 
53 	local_irq_save(flags);
54 	__asm__ __volatile__ (
55 		"# atomic_add_return		\n\t"
56 		DCACHE_CLEAR("%0", "r4", "%1")
57 		M32R_LOCK" %0, @%1;		\n\t"
58 		"add	%0, %2;			\n\t"
59 		M32R_UNLOCK" %0, @%1;		\n\t"
60 		: "=&r" (result)
61 		: "r" (&v->counter), "r" (i)
62 		: "memory"
63 #ifdef CONFIG_CHIP_M32700_TS1
64 		, "r4"
65 #endif	/* CONFIG_CHIP_M32700_TS1 */
66 	);
67 	local_irq_restore(flags);
68 
69 	return result;
70 }
71 
72 /**
73  * atomic_sub_return - subtract integer from atomic variable and return it
74  * @i: integer value to subtract
75  * @v: pointer of type atomic_t
76  *
77  * Atomically subtracts @i from @v and return (@v - @i).
78  */
atomic_sub_return(int i,atomic_t * v)79 static __inline__ int atomic_sub_return(int i, atomic_t *v)
80 {
81 	unsigned long flags;
82 	int result;
83 
84 	local_irq_save(flags);
85 	__asm__ __volatile__ (
86 		"# atomic_sub_return		\n\t"
87 		DCACHE_CLEAR("%0", "r4", "%1")
88 		M32R_LOCK" %0, @%1;		\n\t"
89 		"sub	%0, %2;			\n\t"
90 		M32R_UNLOCK" %0, @%1;		\n\t"
91 		: "=&r" (result)
92 		: "r" (&v->counter), "r" (i)
93 		: "memory"
94 #ifdef CONFIG_CHIP_M32700_TS1
95 		, "r4"
96 #endif	/* CONFIG_CHIP_M32700_TS1 */
97 	);
98 	local_irq_restore(flags);
99 
100 	return result;
101 }
102 
103 /**
104  * atomic_add - add integer to atomic variable
105  * @i: integer value to add
106  * @v: pointer of type atomic_t
107  *
108  * Atomically adds @i to @v.
109  */
110 #define atomic_add(i,v) ((void) atomic_add_return((i), (v)))
111 
112 /**
113  * atomic_sub - subtract the atomic variable
114  * @i: integer value to subtract
115  * @v: pointer of type atomic_t
116  *
117  * Atomically subtracts @i from @v.
118  */
119 #define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))
120 
121 /**
122  * atomic_sub_and_test - subtract value from variable and test result
123  * @i: integer value to subtract
124  * @v: pointer of type atomic_t
125  *
126  * Atomically subtracts @i from @v and returns
127  * true if the result is zero, or false for all
128  * other cases.
129  */
130 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
131 
132 /**
133  * atomic_inc_return - increment atomic variable and return it
134  * @v: pointer of type atomic_t
135  *
136  * Atomically increments @v by 1 and returns the result.
137  */
atomic_inc_return(atomic_t * v)138 static __inline__ int atomic_inc_return(atomic_t *v)
139 {
140 	unsigned long flags;
141 	int result;
142 
143 	local_irq_save(flags);
144 	__asm__ __volatile__ (
145 		"# atomic_inc_return		\n\t"
146 		DCACHE_CLEAR("%0", "r4", "%1")
147 		M32R_LOCK" %0, @%1;		\n\t"
148 		"addi	%0, #1;			\n\t"
149 		M32R_UNLOCK" %0, @%1;		\n\t"
150 		: "=&r" (result)
151 		: "r" (&v->counter)
152 		: "memory"
153 #ifdef CONFIG_CHIP_M32700_TS1
154 		, "r4"
155 #endif	/* CONFIG_CHIP_M32700_TS1 */
156 	);
157 	local_irq_restore(flags);
158 
159 	return result;
160 }
161 
162 /**
163  * atomic_dec_return - decrement atomic variable and return it
164  * @v: pointer of type atomic_t
165  *
166  * Atomically decrements @v by 1 and returns the result.
167  */
atomic_dec_return(atomic_t * v)168 static __inline__ int atomic_dec_return(atomic_t *v)
169 {
170 	unsigned long flags;
171 	int result;
172 
173 	local_irq_save(flags);
174 	__asm__ __volatile__ (
175 		"# atomic_dec_return		\n\t"
176 		DCACHE_CLEAR("%0", "r4", "%1")
177 		M32R_LOCK" %0, @%1;		\n\t"
178 		"addi	%0, #-1;		\n\t"
179 		M32R_UNLOCK" %0, @%1;		\n\t"
180 		: "=&r" (result)
181 		: "r" (&v->counter)
182 		: "memory"
183 #ifdef CONFIG_CHIP_M32700_TS1
184 		, "r4"
185 #endif	/* CONFIG_CHIP_M32700_TS1 */
186 	);
187 	local_irq_restore(flags);
188 
189 	return result;
190 }
191 
192 /**
193  * atomic_inc - increment atomic variable
194  * @v: pointer of type atomic_t
195  *
196  * Atomically increments @v by 1.
197  */
198 #define atomic_inc(v) ((void)atomic_inc_return(v))
199 
200 /**
201  * atomic_dec - decrement atomic variable
202  * @v: pointer of type atomic_t
203  *
204  * Atomically decrements @v by 1.
205  */
206 #define atomic_dec(v) ((void)atomic_dec_return(v))
207 
208 /**
209  * atomic_inc_and_test - increment and test
210  * @v: pointer of type atomic_t
211  *
212  * Atomically increments @v by 1
213  * and returns true if the result is zero, or false for all
214  * other cases.
215  */
216 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
217 
218 /**
219  * atomic_dec_and_test - decrement and test
220  * @v: pointer of type atomic_t
221  *
222  * Atomically decrements @v by 1 and
223  * returns true if the result is 0, or false for all
224  * other cases.
225  */
226 #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
227 
228 /**
229  * atomic_add_negative - add and test if negative
230  * @v: pointer of type atomic_t
231  * @i: integer value to add
232  *
233  * Atomically adds @i to @v and returns true
234  * if the result is negative, or false when
235  * result is greater than or equal to zero.
236  */
237 #define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)
238 
239 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
240 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
241 
242 /**
243  * __atomic_add_unless - add unless the number is a given value
244  * @v: pointer of type atomic_t
245  * @a: the amount to add to v...
246  * @u: ...unless v is equal to u.
247  *
248  * Atomically adds @a to @v, so long as it was not @u.
249  * Returns the old value of @v.
250  */
__atomic_add_unless(atomic_t * v,int a,int u)251 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
252 {
253 	int c, old;
254 	c = atomic_read(v);
255 	for (;;) {
256 		if (unlikely(c == (u)))
257 			break;
258 		old = atomic_cmpxchg((v), c, c + (a));
259 		if (likely(old == c))
260 			break;
261 		c = old;
262 	}
263 	return c;
264 }
265 
266 
atomic_clear_mask(unsigned long mask,atomic_t * addr)267 static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
268 {
269 	unsigned long flags;
270 	unsigned long tmp;
271 
272 	local_irq_save(flags);
273 	__asm__ __volatile__ (
274 		"# atomic_clear_mask		\n\t"
275 		DCACHE_CLEAR("%0", "r5", "%1")
276 		M32R_LOCK" %0, @%1;		\n\t"
277 		"and	%0, %2;			\n\t"
278 		M32R_UNLOCK" %0, @%1;		\n\t"
279 		: "=&r" (tmp)
280 		: "r" (addr), "r" (~mask)
281 		: "memory"
282 #ifdef CONFIG_CHIP_M32700_TS1
283 		, "r5"
284 #endif	/* CONFIG_CHIP_M32700_TS1 */
285 	);
286 	local_irq_restore(flags);
287 }
288 
atomic_set_mask(unsigned long mask,atomic_t * addr)289 static __inline__ void atomic_set_mask(unsigned long  mask, atomic_t *addr)
290 {
291 	unsigned long flags;
292 	unsigned long tmp;
293 
294 	local_irq_save(flags);
295 	__asm__ __volatile__ (
296 		"# atomic_set_mask		\n\t"
297 		DCACHE_CLEAR("%0", "r5", "%1")
298 		M32R_LOCK" %0, @%1;		\n\t"
299 		"or	%0, %2;			\n\t"
300 		M32R_UNLOCK" %0, @%1;		\n\t"
301 		: "=&r" (tmp)
302 		: "r" (addr), "r" (mask)
303 		: "memory"
304 #ifdef CONFIG_CHIP_M32700_TS1
305 		, "r5"
306 #endif	/* CONFIG_CHIP_M32700_TS1 */
307 	);
308 	local_irq_restore(flags);
309 }
310 
311 /* Atomic operations are already serializing on m32r */
312 #define smp_mb__before_atomic_dec()	barrier()
313 #define smp_mb__after_atomic_dec()	barrier()
314 #define smp_mb__before_atomic_inc()	barrier()
315 #define smp_mb__after_atomic_inc()	barrier()
316 
317 #endif	/* _ASM_M32R_ATOMIC_H */
318