Full support for Ginger Console
[linux-ginger.git] / arch / m32r / include / asm / local.h
blob22256d138630508405caf42e7b2986bd7cdec241
1 #ifndef __M32R_LOCAL_H
2 #define __M32R_LOCAL_H
4 /*
5 * linux/include/asm-m32r/local.h
7 * M32R version:
8 * Copyright (C) 2001, 2002 Hitoshi Yamamoto
9 * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
10 * Copyright (C) 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
13 #include <linux/percpu.h>
14 #include <asm/assembler.h>
15 #include <asm/system.h>
16 #include <asm/local.h>
19 * Atomic operations that C can't guarantee us. Useful for
20 * resource counting etc..
24 * Make sure gcc doesn't try to be clever and move things around
25 * on us. We need to use _exactly_ the address the user gave us,
26 * not some alias that contains the same information.
28 typedef struct { volatile int counter; } local_t;
30 #define LOCAL_INIT(i) { (i) }
32 /**
33 * local_read - read local variable
34 * @l: pointer of type local_t
36 * Atomically reads the value of @l.
38 #define local_read(l) ((l)->counter)
40 /**
41 * local_set - set local variable
42 * @l: pointer of type local_t
43 * @i: required value
45 * Atomically sets the value of @l to @i.
47 #define local_set(l, i) (((l)->counter) = (i))
49 /**
50 * local_add_return - add long to local variable and return it
51 * @i: long value to add
52 * @l: pointer of type local_t
54 * Atomically adds @i to @l and return (@i + @l).
56 static inline long local_add_return(long i, local_t *l)
58 unsigned long flags;
59 long result;
61 local_irq_save(flags);
62 __asm__ __volatile__ (
63 "# local_add_return \n\t"
64 DCACHE_CLEAR("%0", "r4", "%1")
65 "ld %0, @%1; \n\t"
66 "add %0, %2; \n\t"
67 "st %0, @%1; \n\t"
68 : "=&r" (result)
69 : "r" (&l->counter), "r" (i)
70 : "memory"
71 #ifdef CONFIG_CHIP_M32700_TS1
72 , "r4"
73 #endif /* CONFIG_CHIP_M32700_TS1 */
75 local_irq_restore(flags);
77 return result;
80 /**
81 * local_sub_return - subtract long from local variable and return it
82 * @i: long value to subtract
83 * @l: pointer of type local_t
85 * Atomically subtracts @i from @l and return (@l - @i).
87 static inline long local_sub_return(long i, local_t *l)
89 unsigned long flags;
90 long result;
92 local_irq_save(flags);
93 __asm__ __volatile__ (
94 "# local_sub_return \n\t"
95 DCACHE_CLEAR("%0", "r4", "%1")
96 "ld %0, @%1; \n\t"
97 "sub %0, %2; \n\t"
98 "st %0, @%1; \n\t"
99 : "=&r" (result)
100 : "r" (&l->counter), "r" (i)
101 : "memory"
102 #ifdef CONFIG_CHIP_M32700_TS1
103 , "r4"
104 #endif /* CONFIG_CHIP_M32700_TS1 */
106 local_irq_restore(flags);
108 return result;
112 * local_add - add long to local variable
113 * @i: long value to add
114 * @l: pointer of type local_t
116 * Atomically adds @i to @l.
118 #define local_add(i, l) ((void) local_add_return((i), (l)))
121 * local_sub - subtract the local variable
122 * @i: long value to subtract
123 * @l: pointer of type local_t
125 * Atomically subtracts @i from @l.
127 #define local_sub(i, l) ((void) local_sub_return((i), (l)))
130 * local_sub_and_test - subtract value from variable and test result
131 * @i: integer value to subtract
132 * @l: pointer of type local_t
134 * Atomically subtracts @i from @l and returns
135 * true if the result is zero, or false for all
136 * other cases.
138 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
141 * local_inc_return - increment local variable and return it
142 * @l: pointer of type local_t
144 * Atomically increments @l by 1 and returns the result.
146 static inline long local_inc_return(local_t *l)
148 unsigned long flags;
149 long result;
151 local_irq_save(flags);
152 __asm__ __volatile__ (
153 "# local_inc_return \n\t"
154 DCACHE_CLEAR("%0", "r4", "%1")
155 "ld %0, @%1; \n\t"
156 "addi %0, #1; \n\t"
157 "st %0, @%1; \n\t"
158 : "=&r" (result)
159 : "r" (&l->counter)
160 : "memory"
161 #ifdef CONFIG_CHIP_M32700_TS1
162 , "r4"
163 #endif /* CONFIG_CHIP_M32700_TS1 */
165 local_irq_restore(flags);
167 return result;
171 * local_dec_return - decrement local variable and return it
172 * @l: pointer of type local_t
174 * Atomically decrements @l by 1 and returns the result.
176 static inline long local_dec_return(local_t *l)
178 unsigned long flags;
179 long result;
181 local_irq_save(flags);
182 __asm__ __volatile__ (
183 "# local_dec_return \n\t"
184 DCACHE_CLEAR("%0", "r4", "%1")
185 "ld %0, @%1; \n\t"
186 "addi %0, #-1; \n\t"
187 "st %0, @%1; \n\t"
188 : "=&r" (result)
189 : "r" (&l->counter)
190 : "memory"
191 #ifdef CONFIG_CHIP_M32700_TS1
192 , "r4"
193 #endif /* CONFIG_CHIP_M32700_TS1 */
195 local_irq_restore(flags);
197 return result;
201 * local_inc - increment local variable
202 * @l: pointer of type local_t
204 * Atomically increments @l by 1.
206 #define local_inc(l) ((void)local_inc_return(l))
209 * local_dec - decrement local variable
210 * @l: pointer of type local_t
212 * Atomically decrements @l by 1.
214 #define local_dec(l) ((void)local_dec_return(l))
217 * local_inc_and_test - increment and test
218 * @l: pointer of type local_t
220 * Atomically increments @l by 1
221 * and returns true if the result is zero, or false for all
222 * other cases.
224 #define local_inc_and_test(l) (local_inc_return(l) == 0)
227 * local_dec_and_test - decrement and test
228 * @l: pointer of type local_t
230 * Atomically decrements @l by 1 and
231 * returns true if the result is 0, or false for all
232 * other cases.
234 #define local_dec_and_test(l) (local_dec_return(l) == 0)
237 * local_add_negative - add and test if negative
238 * @l: pointer of type local_t
239 * @i: integer value to add
241 * Atomically adds @i to @l and returns true
242 * if the result is negative, or false when
243 * result is greater than or equal to zero.
245 #define local_add_negative(i, l) (local_add_return((i), (l)) < 0)
247 #define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))
248 #define local_xchg(v, new) (xchg_local(&((l)->counter), new))
251 * local_add_unless - add unless the number is a given value
252 * @l: pointer of type local_t
253 * @a: the amount to add to l...
254 * @u: ...unless l is equal to u.
256 * Atomically adds @a to @l, so long as it was not @u.
257 * Returns non-zero if @l was not @u, and zero otherwise.
259 static inline int local_add_unless(local_t *l, long a, long u)
261 long c, old;
262 c = local_read(l);
263 for (;;) {
264 if (unlikely(c == (u)))
265 break;
266 old = local_cmpxchg((l), c, c + (a));
267 if (likely(old == c))
268 break;
269 c = old;
271 return c != (u);
274 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
276 static inline void local_clear_mask(unsigned long mask, local_t *addr)
278 unsigned long flags;
279 unsigned long tmp;
281 local_irq_save(flags);
282 __asm__ __volatile__ (
283 "# local_clear_mask \n\t"
284 DCACHE_CLEAR("%0", "r5", "%1")
285 "ld %0, @%1; \n\t"
286 "and %0, %2; \n\t"
287 "st %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 */
295 local_irq_restore(flags);
298 static inline void local_set_mask(unsigned long mask, local_t *addr)
300 unsigned long flags;
301 unsigned long tmp;
303 local_irq_save(flags);
304 __asm__ __volatile__ (
305 "# local_set_mask \n\t"
306 DCACHE_CLEAR("%0", "r5", "%1")
307 "ld %0, @%1; \n\t"
308 "or %0, %2; \n\t"
309 "st %0, @%1; \n\t"
310 : "=&r" (tmp)
311 : "r" (addr), "r" (mask)
312 : "memory"
313 #ifdef CONFIG_CHIP_M32700_TS1
314 , "r5"
315 #endif /* CONFIG_CHIP_M32700_TS1 */
317 local_irq_restore(flags);
320 /* Atomic operations are already serializing on m32r */
321 #define smp_mb__before_local_dec() barrier()
322 #define smp_mb__after_local_dec() barrier()
323 #define smp_mb__before_local_inc() barrier()
324 #define smp_mb__after_local_inc() barrier()
326 /* Use these for per-cpu local_t variables: on some archs they are
327 * much more efficient than these naive implementations. Note they take
328 * a variable, not an address.
331 #define __local_inc(l) ((l)->a.counter++)
332 #define __local_dec(l) ((l)->a.counter++)
333 #define __local_add(i, l) ((l)->a.counter += (i))
334 #define __local_sub(i, l) ((l)->a.counter -= (i))
336 /* Use these for per-cpu local_t variables: on some archs they are
337 * much more efficient than these naive implementations. Note they take
338 * a variable, not an address.
341 /* Need to disable preemption for the cpu local counters otherwise we could
342 still access a variable of a previous CPU in a non local way. */
343 #define cpu_local_wrap_v(l) \
344 ({ local_t res__; \
345 preempt_disable(); \
346 res__ = (l); \
347 preempt_enable(); \
348 res__; })
349 #define cpu_local_wrap(l) \
350 ({ preempt_disable(); \
351 l; \
352 preempt_enable(); }) \
354 #define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
355 #define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
356 #define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
357 #define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
358 #define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
359 #define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
361 #define __cpu_local_inc(l) cpu_local_inc(l)
362 #define __cpu_local_dec(l) cpu_local_dec(l)
363 #define __cpu_local_add(i, l) cpu_local_add((i), (l))
364 #define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
366 #endif /* __M32R_LOCAL_H */