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 _ARCH_MIPS_LOCAL_H
2 #define _ARCH_MIPS_LOCAL_H
3 
4 #include <linux/percpu.h>
5 #include <linux/bitops.h>
6 #include <linux/atomic.h>
7 #include <asm/cmpxchg.h>
8 #include <asm/war.h>
9 
10 typedef struct
11 {
13 } local_t;
14 
15 #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
16 
17 #define local_read(l) atomic_long_read(&(l)->a)
18 #define local_set(l, i) atomic_long_set(&(l)->a, (i))
19 
20 #define local_add(i, l) atomic_long_add((i), (&(l)->a))
21 #define local_sub(i, l) atomic_long_sub((i), (&(l)->a))
22 #define local_inc(l) atomic_long_inc(&(l)->a)
23 #define local_dec(l) atomic_long_dec(&(l)->a)
24 
25 /*
26  * Same as above, but return the result value
27  */
28 static __inline__ long local_add_return(long i, local_t * l)
29 {
30  unsigned long result;
31 
33  unsigned long temp;
34 
35  __asm__ __volatile__(
36  " .set mips3 \n"
37  "1:" __LL "%1, %2 # local_add_return \n"
38  " addu %0, %1, %3 \n"
39  __SC "%0, %2 \n"
40  " beqzl %0, 1b \n"
41  " addu %0, %1, %3 \n"
42  " .set mips0 \n"
43  : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
44  : "Ir" (i), "m" (l->a.counter)
45  : "memory");
46  } else if (kernel_uses_llsc) {
47  unsigned long temp;
48 
49  __asm__ __volatile__(
50  " .set mips3 \n"
51  "1:" __LL "%1, %2 # local_add_return \n"
52  " addu %0, %1, %3 \n"
53  __SC "%0, %2 \n"
54  " beqz %0, 1b \n"
55  " addu %0, %1, %3 \n"
56  " .set mips0 \n"
57  : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
58  : "Ir" (i), "m" (l->a.counter)
59  : "memory");
60  } else {
61  unsigned long flags;
62 
63  local_irq_save(flags);
64  result = l->a.counter;
65  result += i;
66  l->a.counter = result;
67  local_irq_restore(flags);
68  }
69 
70  return result;
71 }
72 
73 static __inline__ long local_sub_return(long i, local_t * l)
74 {
75  unsigned long result;
76 
78  unsigned long temp;
79 
80  __asm__ __volatile__(
81  " .set mips3 \n"
82  "1:" __LL "%1, %2 # local_sub_return \n"
83  " subu %0, %1, %3 \n"
84  __SC "%0, %2 \n"
85  " beqzl %0, 1b \n"
86  " subu %0, %1, %3 \n"
87  " .set mips0 \n"
88  : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
89  : "Ir" (i), "m" (l->a.counter)
90  : "memory");
91  } else if (kernel_uses_llsc) {
92  unsigned long temp;
93 
94  __asm__ __volatile__(
95  " .set mips3 \n"
96  "1:" __LL "%1, %2 # local_sub_return \n"
97  " subu %0, %1, %3 \n"
98  __SC "%0, %2 \n"
99  " beqz %0, 1b \n"
100  " subu %0, %1, %3 \n"
101  " .set mips0 \n"
102  : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
103  : "Ir" (i), "m" (l->a.counter)
104  : "memory");
105  } else {
106  unsigned long flags;
107 
108  local_irq_save(flags);
109  result = l->a.counter;
110  result -= i;
111  l->a.counter = result;
112  local_irq_restore(flags);
113  }
114 
115  return result;
116 }
117 
118 #define local_cmpxchg(l, o, n) \
119  ((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
120 #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n)))
121 
131 #define local_add_unless(l, a, u) \
132 ({ \
133  long c, old; \
134  c = local_read(l); \
135  while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
136  c = old; \
137  c != (u); \
138 })
139 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
140 
141 #define local_dec_return(l) local_sub_return(1, (l))
142 #define local_inc_return(l) local_add_return(1, (l))
143 
144 /*
145  * local_sub_and_test - subtract value from variable and test result
146  * @i: integer value to subtract
147  * @l: pointer of type local_t
148  *
149  * Atomically subtracts @i from @l and returns
150  * true if the result is zero, or false for all
151  * other cases.
152  */
153 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
154 
155 /*
156  * local_inc_and_test - increment and test
157  * @l: pointer of type local_t
158  *
159  * Atomically increments @l by 1
160  * and returns true if the result is zero, or false for all
161  * other cases.
162  */
163 #define local_inc_and_test(l) (local_inc_return(l) == 0)
164 
165 /*
166  * local_dec_and_test - decrement by 1 and test
167  * @l: pointer of type local_t
168  *
169  * Atomically decrements @l by 1 and
170  * returns true if the result is 0, or false for all other
171  * cases.
172  */
173 #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
174 
175 /*
176  * local_add_negative - add and test if negative
177  * @l: pointer of type local_t
178  * @i: integer value to add
179  *
180  * Atomically adds @i to @l and returns true
181  * if the result is negative, or false when
182  * result is greater than or equal to zero.
183  */
184 #define local_add_negative(i, l) (local_add_return(i, (l)) < 0)
185 
186 /* Use these for per-cpu local_t variables: on some archs they are
187  * much more efficient than these naive implementations. Note they take
188  * a variable, not an address.
189  */
190 
191 #define __local_inc(l) ((l)->a.counter++)
192 #define __local_dec(l) ((l)->a.counter++)
193 #define __local_add(i, l) ((l)->a.counter+=(i))
194 #define __local_sub(i, l) ((l)->a.counter-=(i))
195 
196 #endif /* _ARCH_MIPS_LOCAL_H */