Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / include / asm-m32r / 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/config.h>
13 #include <asm/assembler.h>
14 #include <asm/system.h>
15
16 /*
17  * Atomic operations that C can't guarantee us.  Useful for
18  * resource counting etc..
19  */
20
21 /*
22  * Make sure gcc doesn't try to be clever and move things around
23  * on us. We need to use _exactly_ the address the user gave us,
24  * not some alias that contains the same information.
25  */
26 typedef struct { volatile int counter; } atomic_t;
27
28 #define ATOMIC_INIT(i)  { (i) }
29
30 /**
31  * atomic_read - read atomic variable
32  * @v: pointer of type atomic_t
33  *
34  * Atomically reads the value of @v.
35  */
36 #define atomic_read(v)  ((v)->counter)
37
38 /**
39  * atomic_set - set atomic variable
40  * @v: pointer of type atomic_t
41  * @i: required value
42  *
43  * Atomically sets the value of @v to @i.
44  */
45 #define atomic_set(v,i) (((v)->counter) = (i))
46
47 /**
48  * atomic_add_return - add integer to atomic variable and return it
49  * @i: integer value to add
50  * @v: pointer of type atomic_t
51  *
52  * Atomically adds @i to @v and return (@i + @v).
53  */
54 static __inline__ int atomic_add_return(int i, atomic_t *v)
55 {
56         unsigned long flags;
57         int result;
58
59         local_irq_save(flags);
60         __asm__ __volatile__ (
61                 "# atomic_add_return            \n\t"
62                 DCACHE_CLEAR("%0", "r4", "%1")
63                 M32R_LOCK" %0, @%1;             \n\t"
64                 "add    %0, %2;                 \n\t"
65                 M32R_UNLOCK" %0, @%1;           \n\t"
66                 : "=&r" (result)
67                 : "r" (&v->counter), "r" (i)
68                 : "memory"
69 #ifdef CONFIG_CHIP_M32700_TS1
70                 , "r4"
71 #endif  /* CONFIG_CHIP_M32700_TS1 */
72         );
73         local_irq_restore(flags);
74
75         return result;
76 }
77
78 /**
79  * atomic_sub_return - subtract integer from atomic variable and return it
80  * @i: integer value to subtract
81  * @v: pointer of type atomic_t
82  *
83  * Atomically subtracts @i from @v and return (@v - @i).
84  */
85 static __inline__ int atomic_sub_return(int i, atomic_t *v)
86 {
87         unsigned long flags;
88         int result;
89
90         local_irq_save(flags);
91         __asm__ __volatile__ (
92                 "# atomic_sub_return            \n\t"
93                 DCACHE_CLEAR("%0", "r4", "%1")
94                 M32R_LOCK" %0, @%1;             \n\t"
95                 "sub    %0, %2;                 \n\t"
96                 M32R_UNLOCK" %0, @%1;           \n\t"
97                 : "=&r" (result)
98                 : "r" (&v->counter), "r" (i)
99                 : "memory"
100 #ifdef CONFIG_CHIP_M32700_TS1
101                 , "r4"
102 #endif  /* CONFIG_CHIP_M32700_TS1 */
103         );
104         local_irq_restore(flags);
105
106         return result;
107 }
108
109 /**
110  * atomic_add - add integer to atomic variable
111  * @i: integer value to add
112  * @v: pointer of type atomic_t
113  *
114  * Atomically adds @i to @v.
115  */
116 #define atomic_add(i,v) ((void) atomic_add_return((i), (v)))
117
118 /**
119  * atomic_sub - subtract the atomic variable
120  * @i: integer value to subtract
121  * @v: pointer of type atomic_t
122  *
123  * Atomically subtracts @i from @v.
124  */
125 #define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))
126
127 /**
128  * atomic_sub_and_test - subtract value from variable and test result
129  * @i: integer value to subtract
130  * @v: pointer of type atomic_t
131  *
132  * Atomically subtracts @i from @v and returns
133  * true if the result is zero, or false for all
134  * other cases.
135  */
136 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
137
138 /**
139  * atomic_inc_return - increment atomic variable and return it
140  * @v: pointer of type atomic_t
141  *
142  * Atomically increments @v by 1 and returns the result.
143  */
144 static __inline__ int atomic_inc_return(atomic_t *v)
145 {
146         unsigned long flags;
147         int result;
148
149         local_irq_save(flags);
150         __asm__ __volatile__ (
151                 "# atomic_inc_return            \n\t"
152                 DCACHE_CLEAR("%0", "r4", "%1")
153                 M32R_LOCK" %0, @%1;             \n\t"
154                 "addi   %0, #1;                 \n\t"
155                 M32R_UNLOCK" %0, @%1;           \n\t"
156                 : "=&r" (result)
157                 : "r" (&v->counter)
158                 : "memory"
159 #ifdef CONFIG_CHIP_M32700_TS1
160                 , "r4"
161 #endif  /* CONFIG_CHIP_M32700_TS1 */
162         );
163         local_irq_restore(flags);
164
165         return result;
166 }
167
168 /**
169  * atomic_dec_return - decrement atomic variable and return it
170  * @v: pointer of type atomic_t
171  *
172  * Atomically decrements @v by 1 and returns the result.
173  */
174 static __inline__ int atomic_dec_return(atomic_t *v)
175 {
176         unsigned long flags;
177         int result;
178
179         local_irq_save(flags);
180         __asm__ __volatile__ (
181                 "# atomic_dec_return            \n\t"
182                 DCACHE_CLEAR("%0", "r4", "%1")
183                 M32R_LOCK" %0, @%1;             \n\t"
184                 "addi   %0, #-1;                \n\t"
185                 M32R_UNLOCK" %0, @%1;           \n\t"
186                 : "=&r" (result)
187                 : "r" (&v->counter)
188                 : "memory"
189 #ifdef CONFIG_CHIP_M32700_TS1
190                 , "r4"
191 #endif  /* CONFIG_CHIP_M32700_TS1 */
192         );
193         local_irq_restore(flags);
194
195         return result;
196 }
197
198 /**
199  * atomic_inc - increment atomic variable
200  * @v: pointer of type atomic_t
201  *
202  * Atomically increments @v by 1.
203  */
204 #define atomic_inc(v) ((void)atomic_inc_return(v))
205
206 /**
207  * atomic_dec - decrement atomic variable
208  * @v: pointer of type atomic_t
209  *
210  * Atomically decrements @v by 1.
211  */
212 #define atomic_dec(v) ((void)atomic_dec_return(v))
213
214 /**
215  * atomic_inc_and_test - increment and test
216  * @v: pointer of type atomic_t
217  *
218  * Atomically increments @v by 1
219  * and returns true if the result is zero, or false for all
220  * other cases.
221  */
222 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
223
224 /**
225  * atomic_dec_and_test - decrement and test
226  * @v: pointer of type atomic_t
227  *
228  * Atomically decrements @v by 1 and
229  * returns true if the result is 0, or false for all
230  * other cases.
231  */
232 #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
233
234 /**
235  * atomic_add_negative - add and test if negative
236  * @v: pointer of type atomic_t
237  * @i: integer value to add
238  *
239  * Atomically adds @i to @v and returns true
240  * if the result is negative, or false when
241  * result is greater than or equal to zero.
242  */
243 #define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)
244
245 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
246 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
247
248 /**
249  * atomic_add_unless - add unless the number is a given value
250  * @v: pointer of type atomic_t
251  * @a: the amount to add to v...
252  * @u: ...unless v is equal to u.
253  *
254  * Atomically adds @a to @v, so long as it was not @u.
255  * Returns non-zero if @v was not @u, and zero otherwise.
256  */
257 #define atomic_add_unless(v, a, u)                              \
258 ({                                                              \
259         int c, old;                                             \
260         c = atomic_read(v);                                     \
261         while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
262                 c = old;                                        \
263         c != (u);                                               \
264 })
265 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
266
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
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 #include <asm-generic/atomic.h>
318 #endif  /* _ASM_M32R_ATOMIC_H */