Merge branch 'dt/schema-cleanups' into dt/linus
[linux-2.6-microblaze.git] / arch / x86 / include / asm / atomic.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_X86_ATOMIC_H
3 #define _ASM_X86_ATOMIC_H
4
5 #include <linux/compiler.h>
6 #include <linux/types.h>
7 #include <asm/alternative.h>
8 #include <asm/cmpxchg.h>
9 #include <asm/rmwcc.h>
10 #include <asm/barrier.h>
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  * arch_atomic_read - read atomic variable
21  * @v: pointer of type atomic_t
22  *
23  * Atomically reads the value of @v.
24  */
25 static __always_inline int arch_atomic_read(const atomic_t *v)
26 {
27         /*
28          * Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here,
29          * it's non-inlined function that increases binary size and stack usage.
30          */
31         return READ_ONCE((v)->counter);
32 }
33
34 /**
35  * arch_atomic_set - set atomic variable
36  * @v: pointer of type atomic_t
37  * @i: required value
38  *
39  * Atomically sets the value of @v to @i.
40  */
41 static __always_inline void arch_atomic_set(atomic_t *v, int i)
42 {
43         WRITE_ONCE(v->counter, i);
44 }
45
46 /**
47  * arch_atomic_add - add integer to atomic variable
48  * @i: integer value to add
49  * @v: pointer of type atomic_t
50  *
51  * Atomically adds @i to @v.
52  */
53 static __always_inline void arch_atomic_add(int i, atomic_t *v)
54 {
55         asm volatile(LOCK_PREFIX "addl %1,%0"
56                      : "+m" (v->counter)
57                      : "ir" (i) : "memory");
58 }
59
60 /**
61  * arch_atomic_sub - subtract integer from atomic variable
62  * @i: integer value to subtract
63  * @v: pointer of type atomic_t
64  *
65  * Atomically subtracts @i from @v.
66  */
67 static __always_inline void arch_atomic_sub(int i, atomic_t *v)
68 {
69         asm volatile(LOCK_PREFIX "subl %1,%0"
70                      : "+m" (v->counter)
71                      : "ir" (i) : "memory");
72 }
73
74 /**
75  * arch_atomic_sub_and_test - subtract value from variable and test result
76  * @i: integer value to subtract
77  * @v: pointer of type atomic_t
78  *
79  * Atomically subtracts @i from @v and returns
80  * true if the result is zero, or false for all
81  * other cases.
82  */
83 static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
84 {
85         return GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, e, "er", i);
86 }
87 #define arch_atomic_sub_and_test arch_atomic_sub_and_test
88
89 /**
90  * arch_atomic_inc - increment atomic variable
91  * @v: pointer of type atomic_t
92  *
93  * Atomically increments @v by 1.
94  */
95 static __always_inline void arch_atomic_inc(atomic_t *v)
96 {
97         asm volatile(LOCK_PREFIX "incl %0"
98                      : "+m" (v->counter) :: "memory");
99 }
100 #define arch_atomic_inc arch_atomic_inc
101
102 /**
103  * arch_atomic_dec - decrement atomic variable
104  * @v: pointer of type atomic_t
105  *
106  * Atomically decrements @v by 1.
107  */
108 static __always_inline void arch_atomic_dec(atomic_t *v)
109 {
110         asm volatile(LOCK_PREFIX "decl %0"
111                      : "+m" (v->counter) :: "memory");
112 }
113 #define arch_atomic_dec arch_atomic_dec
114
115 /**
116  * arch_atomic_dec_and_test - decrement and test
117  * @v: pointer of type atomic_t
118  *
119  * Atomically decrements @v by 1 and
120  * returns true if the result is 0, or false for all other
121  * cases.
122  */
123 static __always_inline bool arch_atomic_dec_and_test(atomic_t *v)
124 {
125         return GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, e);
126 }
127 #define arch_atomic_dec_and_test arch_atomic_dec_and_test
128
129 /**
130  * arch_atomic_inc_and_test - increment and test
131  * @v: pointer of type atomic_t
132  *
133  * Atomically increments @v by 1
134  * and returns true if the result is zero, or false for all
135  * other cases.
136  */
137 static __always_inline bool arch_atomic_inc_and_test(atomic_t *v)
138 {
139         return GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, e);
140 }
141 #define arch_atomic_inc_and_test arch_atomic_inc_and_test
142
143 /**
144  * arch_atomic_add_negative - add and test if negative
145  * @i: integer value to add
146  * @v: pointer of type atomic_t
147  *
148  * Atomically adds @i to @v and returns true
149  * if the result is negative, or false when
150  * result is greater than or equal to zero.
151  */
152 static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
153 {
154         return GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, s, "er", i);
155 }
156 #define arch_atomic_add_negative arch_atomic_add_negative
157
158 /**
159  * arch_atomic_add_return - add integer and return
160  * @i: integer value to add
161  * @v: pointer of type atomic_t
162  *
163  * Atomically adds @i to @v and returns @i + @v
164  */
165 static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
166 {
167         return i + xadd(&v->counter, i);
168 }
169
170 /**
171  * arch_atomic_sub_return - subtract integer and return
172  * @v: pointer of type atomic_t
173  * @i: integer value to subtract
174  *
175  * Atomically subtracts @i from @v and returns @v - @i
176  */
177 static __always_inline int arch_atomic_sub_return(int i, atomic_t *v)
178 {
179         return arch_atomic_add_return(-i, v);
180 }
181
182 static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v)
183 {
184         return xadd(&v->counter, i);
185 }
186
187 static __always_inline int arch_atomic_fetch_sub(int i, atomic_t *v)
188 {
189         return xadd(&v->counter, -i);
190 }
191
192 static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
193 {
194         return arch_cmpxchg(&v->counter, old, new);
195 }
196
197 #define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg
198 static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new)
199 {
200         return try_cmpxchg(&v->counter, old, new);
201 }
202
203 static inline int arch_atomic_xchg(atomic_t *v, int new)
204 {
205         return arch_xchg(&v->counter, new);
206 }
207
208 static inline void arch_atomic_and(int i, atomic_t *v)
209 {
210         asm volatile(LOCK_PREFIX "andl %1,%0"
211                         : "+m" (v->counter)
212                         : "ir" (i)
213                         : "memory");
214 }
215
216 static inline int arch_atomic_fetch_and(int i, atomic_t *v)
217 {
218         int val = arch_atomic_read(v);
219
220         do { } while (!arch_atomic_try_cmpxchg(v, &val, val & i));
221
222         return val;
223 }
224
225 static inline void arch_atomic_or(int i, atomic_t *v)
226 {
227         asm volatile(LOCK_PREFIX "orl %1,%0"
228                         : "+m" (v->counter)
229                         : "ir" (i)
230                         : "memory");
231 }
232
233 static inline int arch_atomic_fetch_or(int i, atomic_t *v)
234 {
235         int val = arch_atomic_read(v);
236
237         do { } while (!arch_atomic_try_cmpxchg(v, &val, val | i));
238
239         return val;
240 }
241
242 static inline void arch_atomic_xor(int i, atomic_t *v)
243 {
244         asm volatile(LOCK_PREFIX "xorl %1,%0"
245                         : "+m" (v->counter)
246                         : "ir" (i)
247                         : "memory");
248 }
249
250 static inline int arch_atomic_fetch_xor(int i, atomic_t *v)
251 {
252         int val = arch_atomic_read(v);
253
254         do { } while (!arch_atomic_try_cmpxchg(v, &val, val ^ i));
255
256         return val;
257 }
258
259 #ifdef CONFIG_X86_32
260 # include <asm/atomic64_32.h>
261 #else
262 # include <asm/atomic64_64.h>
263 #endif
264
265 #include <asm-generic/atomic-instrumented.h>
266
267 #endif /* _ASM_X86_ATOMIC_H */