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