Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
local.h
Go to the documentation of this file.
1 #ifndef __M32R_LOCAL_H
2 #define __M32R_LOCAL_H
3 
4 /*
5  * linux/include/asm-m32r/local.h
6  *
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 <[email protected]>
11  */
12 
13 #include <linux/percpu.h>
14 #include <asm/assembler.h>
15 #include <asm/local.h>
16 
17 /*
18  * Atomic operations that C can't guarantee us. Useful for
19  * resource counting etc..
20  */
21 
22 /*
23  * Make sure gcc doesn't try to be clever and move things around
24  * on us. We need to use _exactly_ the address the user gave us,
25  * not some alias that contains the same information.
26  */
27 typedef struct { volatile int counter; } local_t;
28 
29 #define LOCAL_INIT(i) { (i) }
30 
37 #define local_read(l) ((l)->counter)
38 
46 #define local_set(l, i) (((l)->counter) = (i))
47 
55 static inline long local_add_return(long i, local_t *l)
56 {
57  unsigned long flags;
58  long result;
59 
60  local_irq_save(flags);
61  __asm__ __volatile__ (
62  "# local_add_return \n\t"
63  DCACHE_CLEAR("%0", "r4", "%1")
64  "ld %0, @%1; \n\t"
65  "add %0, %2; \n\t"
66  "st %0, @%1; \n\t"
67  : "=&r" (result)
68  : "r" (&l->counter), "r" (i)
69  : "memory"
70 #ifdef CONFIG_CHIP_M32700_TS1
71  , "r4"
72 #endif /* CONFIG_CHIP_M32700_TS1 */
73  );
74  local_irq_restore(flags);
75 
76  return result;
77 }
78 
86 static inline long local_sub_return(long i, local_t *l)
87 {
88  unsigned long flags;
89  long result;
90 
91  local_irq_save(flags);
92  __asm__ __volatile__ (
93  "# local_sub_return \n\t"
94  DCACHE_CLEAR("%0", "r4", "%1")
95  "ld %0, @%1; \n\t"
96  "sub %0, %2; \n\t"
97  "st %0, @%1; \n\t"
98  : "=&r" (result)
99  : "r" (&l->counter), "r" (i)
100  : "memory"
101 #ifdef CONFIG_CHIP_M32700_TS1
102  , "r4"
103 #endif /* CONFIG_CHIP_M32700_TS1 */
104  );
105  local_irq_restore(flags);
106 
107  return result;
108 }
109 
117 #define local_add(i, l) ((void) local_add_return((i), (l)))
118 
126 #define local_sub(i, l) ((void) local_sub_return((i), (l)))
127 
137 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
138 
145 static inline long local_inc_return(local_t *l)
146 {
147  unsigned long flags;
148  long result;
149 
150  local_irq_save(flags);
151  __asm__ __volatile__ (
152  "# local_inc_return \n\t"
153  DCACHE_CLEAR("%0", "r4", "%1")
154  "ld %0, @%1; \n\t"
155  "addi %0, #1; \n\t"
156  "st %0, @%1; \n\t"
157  : "=&r" (result)
158  : "r" (&l->counter)
159  : "memory"
160 #ifdef CONFIG_CHIP_M32700_TS1
161  , "r4"
162 #endif /* CONFIG_CHIP_M32700_TS1 */
163  );
164  local_irq_restore(flags);
165 
166  return result;
167 }
168 
175 static inline long local_dec_return(local_t *l)
176 {
177  unsigned long flags;
178  long result;
179 
180  local_irq_save(flags);
181  __asm__ __volatile__ (
182  "# local_dec_return \n\t"
183  DCACHE_CLEAR("%0", "r4", "%1")
184  "ld %0, @%1; \n\t"
185  "addi %0, #-1; \n\t"
186  "st %0, @%1; \n\t"
187  : "=&r" (result)
188  : "r" (&l->counter)
189  : "memory"
190 #ifdef CONFIG_CHIP_M32700_TS1
191  , "r4"
192 #endif /* CONFIG_CHIP_M32700_TS1 */
193  );
194  local_irq_restore(flags);
195 
196  return result;
197 }
198 
205 #define local_inc(l) ((void)local_inc_return(l))
206 
213 #define local_dec(l) ((void)local_dec_return(l))
214 
223 #define local_inc_and_test(l) (local_inc_return(l) == 0)
224 
233 #define local_dec_and_test(l) (local_dec_return(l) == 0)
234 
244 #define local_add_negative(i, l) (local_add_return((i), (l)) < 0)
245 
246 #define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))
247 #define local_xchg(v, new) (xchg_local(&((l)->counter), new))
248 
258 static inline int local_add_unless(local_t *l, long a, long u)
259 {
260  long c, old;
261  c = local_read(l);
262  for (;;) {
263  if (unlikely(c == (u)))
264  break;
265  old = local_cmpxchg((l), c, c + (a));
266  if (likely(old == c))
267  break;
268  c = old;
269  }
270  return c != (u);
271 }
272 
273 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
274 
275 static inline void local_clear_mask(unsigned long mask, local_t *addr)
276 {
277  unsigned long flags;
278  unsigned long tmp;
279 
280  local_irq_save(flags);
281  __asm__ __volatile__ (
282  "# local_clear_mask \n\t"
283  DCACHE_CLEAR("%0", "r5", "%1")
284  "ld %0, @%1; \n\t"
285  "and %0, %2; \n\t"
286  "st %0, @%1; \n\t"
287  : "=&r" (tmp)
288  : "r" (addr), "r" (~mask)
289  : "memory"
290 #ifdef CONFIG_CHIP_M32700_TS1
291  , "r5"
292 #endif /* CONFIG_CHIP_M32700_TS1 */
293  );
294  local_irq_restore(flags);
295 }
296 
297 static inline void local_set_mask(unsigned long mask, local_t *addr)
298 {
299  unsigned long flags;
300  unsigned long tmp;
301 
302  local_irq_save(flags);
303  __asm__ __volatile__ (
304  "# local_set_mask \n\t"
305  DCACHE_CLEAR("%0", "r5", "%1")
306  "ld %0, @%1; \n\t"
307  "or %0, %2; \n\t"
308  "st %0, @%1; \n\t"
309  : "=&r" (tmp)
310  : "r" (addr), "r" (mask)
311  : "memory"
312 #ifdef CONFIG_CHIP_M32700_TS1
313  , "r5"
314 #endif /* CONFIG_CHIP_M32700_TS1 */
315  );
316  local_irq_restore(flags);
317 }
318 
319 /* Atomic operations are already serializing on m32r */
320 #define smp_mb__before_local_dec() barrier()
321 #define smp_mb__after_local_dec() barrier()
322 #define smp_mb__before_local_inc() barrier()
323 #define smp_mb__after_local_inc() barrier()
324 
325 /* Use these for per-cpu local_t variables: on some archs they are
326  * much more efficient than these naive implementations. Note they take
327  * a variable, not an address.
328  */
329 
330 #define __local_inc(l) ((l)->a.counter++)
331 #define __local_dec(l) ((l)->a.counter++)
332 #define __local_add(i, l) ((l)->a.counter += (i))
333 #define __local_sub(i, l) ((l)->a.counter -= (i))
334 
335 /* Use these for per-cpu local_t variables: on some archs they are
336  * much more efficient than these naive implementations. Note they take
337  * a variable, not an address.
338  */
339 
340 #endif /* __M32R_LOCAL_H */