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