Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/davem/tg3-2.6
[linux-2.6] / 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 static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
246 {
247         unsigned long flags;
248         unsigned long tmp;
249
250         local_irq_save(flags);
251         __asm__ __volatile__ (
252                 "# atomic_clear_mask            \n\t"
253                 DCACHE_CLEAR("%0", "r5", "%1")
254                 M32R_LOCK" %0, @%1;             \n\t"
255                 "and    %0, %2;                 \n\t"
256                 M32R_UNLOCK" %0, @%1;           \n\t"
257                 : "=&r" (tmp)
258                 : "r" (addr), "r" (~mask)
259                 : "memory"
260 #ifdef CONFIG_CHIP_M32700_TS1
261                 , "r5"
262 #endif  /* CONFIG_CHIP_M32700_TS1 */
263         );
264         local_irq_restore(flags);
265 }
266
267 static __inline__ void atomic_set_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_set_mask              \n\t"
275                 DCACHE_CLEAR("%0", "r5", "%1")
276                 M32R_LOCK" %0, @%1;             \n\t"
277                 "or     %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 /* Atomic operations are already serializing on m32r */
290 #define smp_mb__before_atomic_dec()     barrier()
291 #define smp_mb__after_atomic_dec()      barrier()
292 #define smp_mb__before_atomic_inc()     barrier()
293 #define smp_mb__after_atomic_inc()      barrier()
294
295 #endif  /* _ASM_M32R_ATOMIC_H */