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