Linux 6.10-rc6
[linux-2.6-block.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 static __always_inline int arch_atomic_read(const atomic_t *v)
18 {
19         /*
20          * Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here,
21          * it's non-inlined function that increases binary size and stack usage.
22          */
23         return __READ_ONCE((v)->counter);
24 }
25
26 static __always_inline void arch_atomic_set(atomic_t *v, int i)
27 {
28         __WRITE_ONCE(v->counter, i);
29 }
30
31 static __always_inline void arch_atomic_add(int i, atomic_t *v)
32 {
33         asm volatile(LOCK_PREFIX "addl %1,%0"
34                      : "+m" (v->counter)
35                      : "ir" (i) : "memory");
36 }
37
38 static __always_inline void arch_atomic_sub(int i, atomic_t *v)
39 {
40         asm volatile(LOCK_PREFIX "subl %1,%0"
41                      : "+m" (v->counter)
42                      : "ir" (i) : "memory");
43 }
44
45 static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
46 {
47         return GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, e, "er", i);
48 }
49 #define arch_atomic_sub_and_test arch_atomic_sub_and_test
50
51 static __always_inline void arch_atomic_inc(atomic_t *v)
52 {
53         asm volatile(LOCK_PREFIX "incl %0"
54                      : "+m" (v->counter) :: "memory");
55 }
56 #define arch_atomic_inc arch_atomic_inc
57
58 static __always_inline void arch_atomic_dec(atomic_t *v)
59 {
60         asm volatile(LOCK_PREFIX "decl %0"
61                      : "+m" (v->counter) :: "memory");
62 }
63 #define arch_atomic_dec arch_atomic_dec
64
65 static __always_inline bool arch_atomic_dec_and_test(atomic_t *v)
66 {
67         return GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, e);
68 }
69 #define arch_atomic_dec_and_test arch_atomic_dec_and_test
70
71 static __always_inline bool arch_atomic_inc_and_test(atomic_t *v)
72 {
73         return GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, e);
74 }
75 #define arch_atomic_inc_and_test arch_atomic_inc_and_test
76
77 static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
78 {
79         return GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, s, "er", i);
80 }
81 #define arch_atomic_add_negative arch_atomic_add_negative
82
83 static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
84 {
85         return i + xadd(&v->counter, i);
86 }
87 #define arch_atomic_add_return arch_atomic_add_return
88
89 #define arch_atomic_sub_return(i, v) arch_atomic_add_return(-(i), v)
90
91 static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v)
92 {
93         return xadd(&v->counter, i);
94 }
95 #define arch_atomic_fetch_add arch_atomic_fetch_add
96
97 #define arch_atomic_fetch_sub(i, v) arch_atomic_fetch_add(-(i), v)
98
99 static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
100 {
101         return arch_cmpxchg(&v->counter, old, new);
102 }
103 #define arch_atomic_cmpxchg arch_atomic_cmpxchg
104
105 static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new)
106 {
107         return arch_try_cmpxchg(&v->counter, old, new);
108 }
109 #define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg
110
111 static __always_inline int arch_atomic_xchg(atomic_t *v, int new)
112 {
113         return arch_xchg(&v->counter, new);
114 }
115 #define arch_atomic_xchg arch_atomic_xchg
116
117 static __always_inline void arch_atomic_and(int i, atomic_t *v)
118 {
119         asm volatile(LOCK_PREFIX "andl %1,%0"
120                         : "+m" (v->counter)
121                         : "ir" (i)
122                         : "memory");
123 }
124
125 static __always_inline int arch_atomic_fetch_and(int i, atomic_t *v)
126 {
127         int val = arch_atomic_read(v);
128
129         do { } while (!arch_atomic_try_cmpxchg(v, &val, val & i));
130
131         return val;
132 }
133 #define arch_atomic_fetch_and arch_atomic_fetch_and
134
135 static __always_inline void arch_atomic_or(int i, atomic_t *v)
136 {
137         asm volatile(LOCK_PREFIX "orl %1,%0"
138                         : "+m" (v->counter)
139                         : "ir" (i)
140                         : "memory");
141 }
142
143 static __always_inline int arch_atomic_fetch_or(int i, atomic_t *v)
144 {
145         int val = arch_atomic_read(v);
146
147         do { } while (!arch_atomic_try_cmpxchg(v, &val, val | i));
148
149         return val;
150 }
151 #define arch_atomic_fetch_or arch_atomic_fetch_or
152
153 static __always_inline void arch_atomic_xor(int i, atomic_t *v)
154 {
155         asm volatile(LOCK_PREFIX "xorl %1,%0"
156                         : "+m" (v->counter)
157                         : "ir" (i)
158                         : "memory");
159 }
160
161 static __always_inline int arch_atomic_fetch_xor(int i, atomic_t *v)
162 {
163         int val = arch_atomic_read(v);
164
165         do { } while (!arch_atomic_try_cmpxchg(v, &val, val ^ i));
166
167         return val;
168 }
169 #define arch_atomic_fetch_xor arch_atomic_fetch_xor
170
171 #ifdef CONFIG_X86_32
172 # include <asm/atomic64_32.h>
173 #else
174 # include <asm/atomic64_64.h>
175 #endif
176
177 #endif /* _ASM_X86_ATOMIC_H */