]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - include/asm-x86/local.h
x86: unify local_{32|64}.h
[linux-2.6-omap-h63xx.git] / include / asm-x86 / local.h
1 #ifndef _ARCH_LOCAL_H
2 #define _ARCH_LOCAL_H
3
4 #include <linux/percpu.h>
5
6 #include <asm/system.h>
7 #include <asm/atomic.h>
8 #include <asm/asm.h>
9
10 typedef struct
11 {
12         atomic_long_t a;
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 static inline void local_inc(local_t *l)
21 {
22         __asm__ __volatile__(
23                 _ASM_INC "%0"
24                 :"+m" (l->a.counter));
25 }
26
27 static inline void local_dec(local_t *l)
28 {
29         __asm__ __volatile__(
30                 _ASM_DEC "%0"
31                 :"+m" (l->a.counter));
32 }
33
34 static inline void local_add(long i, local_t *l)
35 {
36         __asm__ __volatile__(
37                 _ASM_ADD "%1,%0"
38                 :"+m" (l->a.counter)
39                 :"ir" (i));
40 }
41
42 static inline void local_sub(long i, local_t *l)
43 {
44         __asm__ __volatile__(
45                 _ASM_SUB "%1,%0"
46                 :"+m" (l->a.counter)
47                 :"ir" (i));
48 }
49
50 /**
51  * local_sub_and_test - subtract value from variable and test result
52  * @i: integer value to subtract
53  * @l: pointer to type local_t
54  *
55  * Atomically subtracts @i from @l and returns
56  * true if the result is zero, or false for all
57  * other cases.
58  */
59 static inline int local_sub_and_test(long i, local_t *l)
60 {
61         unsigned char c;
62
63         __asm__ __volatile__(
64                 _ASM_SUB "%2,%0; sete %1"
65                 :"+m" (l->a.counter), "=qm" (c)
66                 :"ir" (i) : "memory");
67         return c;
68 }
69
70 /**
71  * local_dec_and_test - decrement and test
72  * @l: pointer to type local_t
73  *
74  * Atomically decrements @l by 1 and
75  * returns true if the result is 0, or false for all other
76  * cases.
77  */
78 static inline int local_dec_and_test(local_t *l)
79 {
80         unsigned char c;
81
82         __asm__ __volatile__(
83                 _ASM_DEC "%0; sete %1"
84                 :"+m" (l->a.counter), "=qm" (c)
85                 : : "memory");
86         return c != 0;
87 }
88
89 /**
90  * local_inc_and_test - increment and test
91  * @l: pointer to type local_t
92  *
93  * Atomically increments @l by 1
94  * and returns true if the result is zero, or false for all
95  * other cases.
96  */
97 static inline int local_inc_and_test(local_t *l)
98 {
99         unsigned char c;
100
101         __asm__ __volatile__(
102                 _ASM_INC "%0; sete %1"
103                 :"+m" (l->a.counter), "=qm" (c)
104                 : : "memory");
105         return c != 0;
106 }
107
108 /**
109  * local_add_negative - add and test if negative
110  * @i: integer value to add
111  * @l: pointer to type local_t
112  *
113  * Atomically adds @i to @l and returns true
114  * if the result is negative, or false when
115  * result is greater than or equal to zero.
116  */
117 static inline int local_add_negative(long i, local_t *l)
118 {
119         unsigned char c;
120
121         __asm__ __volatile__(
122                 _ASM_ADD "%2,%0; sets %1"
123                 :"+m" (l->a.counter), "=qm" (c)
124                 :"ir" (i) : "memory");
125         return c;
126 }
127
128 /**
129  * local_add_return - add and return
130  * @i: integer value to add
131  * @l: pointer to type local_t
132  *
133  * Atomically adds @i to @l and returns @i + @l
134  */
135 static inline long local_add_return(long i, local_t *l)
136 {
137         long __i;
138 #ifdef CONFIG_M386
139         unsigned long flags;
140         if(unlikely(boot_cpu_data.x86 <= 3))
141                 goto no_xadd;
142 #endif
143         /* Modern 486+ processor */
144         __i = i;
145         __asm__ __volatile__(
146                 _ASM_XADD "%0, %1;"
147                 :"+r" (i), "+m" (l->a.counter)
148                 : : "memory");
149         return i + __i;
150
151 #ifdef CONFIG_M386
152 no_xadd: /* Legacy 386 processor */
153         local_irq_save(flags);
154         __i = local_read(l);
155         local_set(l, i + __i);
156         local_irq_restore(flags);
157         return i + __i;
158 #endif
159 }
160
161 static inline long local_sub_return(long i, local_t *l)
162 {
163         return local_add_return(-i,l);
164 }
165
166 #define local_inc_return(l)  (local_add_return(1,l))
167 #define local_dec_return(l)  (local_sub_return(1,l))
168
169 #define local_cmpxchg(l, o, n) \
170         (cmpxchg_local(&((l)->a.counter), (o), (n)))
171 /* Always has a lock prefix */
172 #define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
173
174 /**
175  * local_add_unless - add unless the number is a given value
176  * @l: pointer of type local_t
177  * @a: the amount to add to l...
178  * @u: ...unless l is equal to u.
179  *
180  * Atomically adds @a to @l, so long as it was not @u.
181  * Returns non-zero if @l was not @u, and zero otherwise.
182  */
183 #define local_add_unless(l, a, u)                               \
184 ({                                                              \
185         long c, old;                                            \
186         c = local_read(l);                                      \
187         for (;;) {                                              \
188                 if (unlikely(c == (u)))                         \
189                         break;                                  \
190                 old = local_cmpxchg((l), c, c + (a));   \
191                 if (likely(old == c))                           \
192                         break;                                  \
193                 c = old;                                        \
194         }                                                       \
195         c != (u);                                               \
196 })
197 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
198
199 /* On x86_32, these are no better than the atomic variants.
200  * On x86-64 these are better than the atomic variants on SMP kernels
201  * because they dont use a lock prefix.
202  */
203 #define __local_inc(l)          local_inc(l)
204 #define __local_dec(l)          local_dec(l)
205 #define __local_add(i,l)        local_add((i),(l))
206 #define __local_sub(i,l)        local_sub((i),(l))
207
208 /* Use these for per-cpu local_t variables: on some archs they are
209  * much more efficient than these naive implementations.  Note they take
210  * a variable, not an address.
211  *
212  * X86_64: This could be done better if we moved the per cpu data directly
213  * after GS.
214  */
215
216 /* Need to disable preemption for the cpu local counters otherwise we could
217    still access a variable of a previous CPU in a non atomic way. */
218 #define cpu_local_wrap_v(l)             \
219         ({ local_t res__;               \
220            preempt_disable();           \
221            res__ = (l);                 \
222            preempt_enable();            \
223            res__; })
224 #define cpu_local_wrap(l)               \
225         ({ preempt_disable();           \
226            l;                           \
227            preempt_enable(); })         \
228
229 #define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
230 #define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
231 #define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
232 #define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
233 #define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
234 #define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
235
236 #define __cpu_local_inc(l)      cpu_local_inc(l)
237 #define __cpu_local_dec(l)      cpu_local_dec(l)
238 #define __cpu_local_add(i, l)   cpu_local_add((i), (l))
239 #define __cpu_local_sub(i, l)   cpu_local_sub((i), (l))
240
241 #endif /* _ARCH_LOCAL_H */