Rev 5270 | Rev 6934 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5270 | serge | 1 | #ifndef _ASM_X86_ATOMIC_H |
2 | #define _ASM_X86_ATOMIC_H |
||
3 | |||
4 | #include |
||
5 | #include |
||
6 | #include |
||
7 | #include |
||
8 | #include |
||
9 | #include |
||
10 | #include |
||
11 | |||
12 | /* |
||
13 | * Atomic operations that C can't guarantee us. Useful for |
||
14 | * resource counting etc.. |
||
15 | */ |
||
16 | |||
17 | #define ATOMIC_INIT(i) { (i) } |
||
18 | |||
19 | /** |
||
20 | * atomic_read - read atomic variable |
||
21 | * @v: pointer of type atomic_t |
||
22 | * |
||
23 | * Atomically reads the value of @v. |
||
24 | */ |
||
6082 | serge | 25 | static __always_inline int atomic_read(const atomic_t *v) |
5270 | serge | 26 | { |
6082 | serge | 27 | return READ_ONCE((v)->counter); |
5270 | serge | 28 | } |
29 | |||
30 | /** |
||
31 | * atomic_set - set atomic variable |
||
32 | * @v: pointer of type atomic_t |
||
33 | * @i: required value |
||
34 | * |
||
35 | * Atomically sets the value of @v to @i. |
||
36 | */ |
||
6082 | serge | 37 | static __always_inline void atomic_set(atomic_t *v, int i) |
5270 | serge | 38 | { |
6082 | serge | 39 | WRITE_ONCE(v->counter, i); |
5270 | serge | 40 | } |
41 | |||
42 | /** |
||
43 | * atomic_add - add integer to atomic variable |
||
44 | * @i: integer value to add |
||
45 | * @v: pointer of type atomic_t |
||
46 | * |
||
47 | * Atomically adds @i to @v. |
||
48 | */ |
||
6082 | serge | 49 | static __always_inline void atomic_add(int i, atomic_t *v) |
5270 | serge | 50 | { |
51 | asm volatile(LOCK_PREFIX "addl %1,%0" |
||
52 | : "+m" (v->counter) |
||
53 | : "ir" (i)); |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * atomic_sub - subtract integer from atomic variable |
||
58 | * @i: integer value to subtract |
||
59 | * @v: pointer of type atomic_t |
||
60 | * |
||
61 | * Atomically subtracts @i from @v. |
||
62 | */ |
||
6082 | serge | 63 | static __always_inline void atomic_sub(int i, atomic_t *v) |
5270 | serge | 64 | { |
65 | asm volatile(LOCK_PREFIX "subl %1,%0" |
||
66 | : "+m" (v->counter) |
||
67 | : "ir" (i)); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * atomic_sub_and_test - subtract value from variable and test result |
||
72 | * @i: integer value to subtract |
||
73 | * @v: pointer of type atomic_t |
||
74 | * |
||
75 | * Atomically subtracts @i from @v and returns |
||
76 | * true if the result is zero, or false for all |
||
77 | * other cases. |
||
78 | */ |
||
6082 | serge | 79 | static __always_inline int atomic_sub_and_test(int i, atomic_t *v) |
5270 | serge | 80 | { |
81 | GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * atomic_inc - increment atomic variable |
||
86 | * @v: pointer of type atomic_t |
||
87 | * |
||
88 | * Atomically increments @v by 1. |
||
89 | */ |
||
6082 | serge | 90 | static __always_inline void atomic_inc(atomic_t *v) |
5270 | serge | 91 | { |
92 | asm volatile(LOCK_PREFIX "incl %0" |
||
93 | : "+m" (v->counter)); |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * atomic_dec - decrement atomic variable |
||
98 | * @v: pointer of type atomic_t |
||
99 | * |
||
100 | * Atomically decrements @v by 1. |
||
101 | */ |
||
6082 | serge | 102 | static __always_inline void atomic_dec(atomic_t *v) |
5270 | serge | 103 | { |
104 | asm volatile(LOCK_PREFIX "decl %0" |
||
105 | : "+m" (v->counter)); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * atomic_dec_and_test - decrement and test |
||
110 | * @v: pointer of type atomic_t |
||
111 | * |
||
112 | * Atomically decrements @v by 1 and |
||
113 | * returns true if the result is 0, or false for all other |
||
114 | * cases. |
||
115 | */ |
||
6082 | serge | 116 | static __always_inline int atomic_dec_and_test(atomic_t *v) |
5270 | serge | 117 | { |
118 | GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * atomic_inc_and_test - increment and test |
||
123 | * @v: pointer of type atomic_t |
||
124 | * |
||
125 | * Atomically increments @v by 1 |
||
126 | * and returns true if the result is zero, or false for all |
||
127 | * other cases. |
||
128 | */ |
||
6082 | serge | 129 | static __always_inline int atomic_inc_and_test(atomic_t *v) |
5270 | serge | 130 | { |
131 | GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e"); |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * atomic_add_negative - add and test if negative |
||
136 | * @i: integer value to add |
||
137 | * @v: pointer of type atomic_t |
||
138 | * |
||
139 | * Atomically adds @i to @v and returns true |
||
140 | * if the result is negative, or false when |
||
141 | * result is greater than or equal to zero. |
||
142 | */ |
||
6082 | serge | 143 | static __always_inline int atomic_add_negative(int i, atomic_t *v) |
5270 | serge | 144 | { |
145 | GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * atomic_add_return - add integer and return |
||
150 | * @i: integer value to add |
||
151 | * @v: pointer of type atomic_t |
||
152 | * |
||
153 | * Atomically adds @i to @v and returns @i + @v |
||
154 | */ |
||
6082 | serge | 155 | static __always_inline int atomic_add_return(int i, atomic_t *v) |
5270 | serge | 156 | { |
157 | return i + xadd(&v->counter, i); |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * atomic_sub_return - subtract integer and return |
||
162 | * @v: pointer of type atomic_t |
||
163 | * @i: integer value to subtract |
||
164 | * |
||
165 | * Atomically subtracts @i from @v and returns @v - @i |
||
166 | */ |
||
6082 | serge | 167 | static __always_inline int atomic_sub_return(int i, atomic_t *v) |
5270 | serge | 168 | { |
169 | return atomic_add_return(-i, v); |
||
170 | } |
||
171 | |||
172 | #define atomic_inc_return(v) (atomic_add_return(1, v)) |
||
173 | #define atomic_dec_return(v) (atomic_sub_return(1, v)) |
||
174 | |||
6082 | serge | 175 | static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) |
5270 | serge | 176 | { |
177 | return cmpxchg(&v->counter, old, new); |
||
178 | } |
||
179 | |||
180 | static inline int atomic_xchg(atomic_t *v, int new) |
||
181 | { |
||
182 | return xchg(&v->counter, new); |
||
183 | } |
||
184 | |||
6082 | serge | 185 | #define ATOMIC_OP(op) \ |
186 | static inline void atomic_##op(int i, atomic_t *v) \ |
||
187 | { \ |
||
188 | asm volatile(LOCK_PREFIX #op"l %1,%0" \ |
||
189 | : "+m" (v->counter) \ |
||
190 | : "ir" (i) \ |
||
191 | : "memory"); \ |
||
192 | } |
||
193 | |||
194 | ATOMIC_OP(and) |
||
195 | ATOMIC_OP(or) |
||
196 | ATOMIC_OP(xor) |
||
197 | |||
198 | #undef ATOMIC_OP |
||
199 | |||
5270 | serge | 200 | /** |
201 | * __atomic_add_unless - add unless the number is already a given value |
||
202 | * @v: pointer of type atomic_t |
||
203 | * @a: the amount to add to v... |
||
204 | * @u: ...unless v is equal to u. |
||
205 | * |
||
206 | * Atomically adds @a to @v, so long as @v was not already @u. |
||
207 | * Returns the old value of @v. |
||
208 | */ |
||
6082 | serge | 209 | static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) |
5270 | serge | 210 | { |
211 | int c, old; |
||
212 | c = atomic_read(v); |
||
213 | for (;;) { |
||
214 | if (unlikely(c == (u))) |
||
215 | break; |
||
216 | old = atomic_cmpxchg((v), c, c + (a)); |
||
217 | if (likely(old == c)) |
||
218 | break; |
||
219 | c = old; |
||
220 | } |
||
221 | return c; |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * atomic_inc_short - increment of a short integer |
||
226 | * @v: pointer to type int |
||
227 | * |
||
228 | * Atomically adds 1 to @v |
||
229 | * Returns the new value of @u |
||
230 | */ |
||
6082 | serge | 231 | static __always_inline short int atomic_inc_short(short int *v) |
5270 | serge | 232 | { |
233 | asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); |
||
234 | return *v; |
||
235 | } |
||
236 | |||
237 | #ifdef CONFIG_X86_32 |
||
238 | # include |
||
239 | #else |
||
240 | # include |
||
241 | #endif |
||
242 | |||
243 | #endif /* _ASM_X86_ATOMIC_H */ |