5 * linux/include/asm-m32r/local.h
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) }
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)
41 * local_set - set local variable
42 * @l: pointer of type local_t
45 * Atomically sets the value of @l to @i.
47 #define local_set(l, i) (((l)->counter) = (i))
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
)
61 local_irq_save(flags
);
62 __asm__
__volatile__ (
63 "# local_add_return \n\t"
64 DCACHE_CLEAR("%0", "r4", "%1")
69 : "r" (&l
->counter
), "r" (i
)
71 #ifdef CONFIG_CHIP_M32700_TS1
73 #endif /* CONFIG_CHIP_M32700_TS1 */
75 local_irq_restore(flags
);
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
)
92 local_irq_save(flags
);
93 __asm__
__volatile__ (
94 "# local_sub_return \n\t"
95 DCACHE_CLEAR("%0", "r4", "%1")
100 : "r" (&l
->counter
), "r" (i
)
102 #ifdef CONFIG_CHIP_M32700_TS1
104 #endif /* CONFIG_CHIP_M32700_TS1 */
106 local_irq_restore(flags
);
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
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
)
151 local_irq_save(flags
);
152 __asm__
__volatile__ (
153 "# local_inc_return \n\t"
154 DCACHE_CLEAR("%0", "r4", "%1")
161 #ifdef CONFIG_CHIP_M32700_TS1
163 #endif /* CONFIG_CHIP_M32700_TS1 */
165 local_irq_restore(flags
);
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
)
181 local_irq_save(flags
);
182 __asm__
__volatile__ (
183 "# local_dec_return \n\t"
184 DCACHE_CLEAR("%0", "r4", "%1")
191 #ifdef CONFIG_CHIP_M32700_TS1
193 #endif /* CONFIG_CHIP_M32700_TS1 */
195 local_irq_restore(flags
);
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
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
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
)
264 if (unlikely(c
== (u
)))
266 old
= local_cmpxchg((l
), c
, c
+ (a
));
267 if (likely(old
== c
))
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
)
281 local_irq_save(flags
);
282 __asm__
__volatile__ (
283 "# local_clear_mask \n\t"
284 DCACHE_CLEAR("%0", "r5", "%1")
289 : "r" (addr
), "r" (~mask
)
291 #ifdef CONFIG_CHIP_M32700_TS1
293 #endif /* CONFIG_CHIP_M32700_TS1 */
295 local_irq_restore(flags
);
298 static inline void local_set_mask(unsigned long mask
, local_t
*addr
)
303 local_irq_save(flags
);
304 __asm__
__volatile__ (
305 "# local_set_mask \n\t"
306 DCACHE_CLEAR("%0", "r5", "%1")
311 : "r" (addr
), "r" (mask
)
313 #ifdef CONFIG_CHIP_M32700_TS1
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) \
349 #define cpu_local_wrap(l) \
350 ({ preempt_disable(); \
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 */