Merge branch 'nvme-5.2-rc-next' of git://git.infradead.org/nvme into for-linus
[sfrench/cifs-2.6.git] / include / asm-generic / atomic.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Generic C implementation of atomic counter operations. Usable on
4  * UP systems only. Do not include in machine independent code.
5  *
6  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
7  * Written by David Howells (dhowells@redhat.com)
8  */
9 #ifndef __ASM_GENERIC_ATOMIC_H
10 #define __ASM_GENERIC_ATOMIC_H
11
12 #include <asm/cmpxchg.h>
13 #include <asm/barrier.h>
14
15 /*
16  * atomic_$op() - $op integer to atomic variable
17  * @i: integer value to $op
18  * @v: pointer to the atomic variable
19  *
20  * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use
21  * smp_mb__{before,after}_atomic().
22  */
23
24 /*
25  * atomic_$op_return() - $op interer to atomic variable and returns the result
26  * @i: integer value to $op
27  * @v: pointer to the atomic variable
28  *
29  * Atomically $ops @i to @v. Does imply a full memory barrier.
30  */
31
32 #ifdef CONFIG_SMP
33
34 /* we can build all atomic primitives from cmpxchg */
35
36 #define ATOMIC_OP(op, c_op)                                             \
37 static inline void atomic_##op(int i, atomic_t *v)                      \
38 {                                                                       \
39         int c, old;                                                     \
40                                                                         \
41         c = v->counter;                                                 \
42         while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
43                 c = old;                                                \
44 }
45
46 #define ATOMIC_OP_RETURN(op, c_op)                                      \
47 static inline int atomic_##op##_return(int i, atomic_t *v)              \
48 {                                                                       \
49         int c, old;                                                     \
50                                                                         \
51         c = v->counter;                                                 \
52         while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
53                 c = old;                                                \
54                                                                         \
55         return c c_op i;                                                \
56 }
57
58 #define ATOMIC_FETCH_OP(op, c_op)                                       \
59 static inline int atomic_fetch_##op(int i, atomic_t *v)                 \
60 {                                                                       \
61         int c, old;                                                     \
62                                                                         \
63         c = v->counter;                                                 \
64         while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
65                 c = old;                                                \
66                                                                         \
67         return c;                                                       \
68 }
69
70 #else
71
72 #include <linux/irqflags.h>
73
74 #define ATOMIC_OP(op, c_op)                                             \
75 static inline void atomic_##op(int i, atomic_t *v)                      \
76 {                                                                       \
77         unsigned long flags;                                            \
78                                                                         \
79         raw_local_irq_save(flags);                                      \
80         v->counter = v->counter c_op i;                                 \
81         raw_local_irq_restore(flags);                                   \
82 }
83
84 #define ATOMIC_OP_RETURN(op, c_op)                                      \
85 static inline int atomic_##op##_return(int i, atomic_t *v)              \
86 {                                                                       \
87         unsigned long flags;                                            \
88         int ret;                                                        \
89                                                                         \
90         raw_local_irq_save(flags);                                      \
91         ret = (v->counter = v->counter c_op i);                         \
92         raw_local_irq_restore(flags);                                   \
93                                                                         \
94         return ret;                                                     \
95 }
96
97 #define ATOMIC_FETCH_OP(op, c_op)                                       \
98 static inline int atomic_fetch_##op(int i, atomic_t *v)                 \
99 {                                                                       \
100         unsigned long flags;                                            \
101         int ret;                                                        \
102                                                                         \
103         raw_local_irq_save(flags);                                      \
104         ret = v->counter;                                               \
105         v->counter = v->counter c_op i;                                 \
106         raw_local_irq_restore(flags);                                   \
107                                                                         \
108         return ret;                                                     \
109 }
110
111 #endif /* CONFIG_SMP */
112
113 #ifndef atomic_add_return
114 ATOMIC_OP_RETURN(add, +)
115 #endif
116
117 #ifndef atomic_sub_return
118 ATOMIC_OP_RETURN(sub, -)
119 #endif
120
121 #ifndef atomic_fetch_add
122 ATOMIC_FETCH_OP(add, +)
123 #endif
124
125 #ifndef atomic_fetch_sub
126 ATOMIC_FETCH_OP(sub, -)
127 #endif
128
129 #ifndef atomic_fetch_and
130 ATOMIC_FETCH_OP(and, &)
131 #endif
132
133 #ifndef atomic_fetch_or
134 ATOMIC_FETCH_OP(or, |)
135 #endif
136
137 #ifndef atomic_fetch_xor
138 ATOMIC_FETCH_OP(xor, ^)
139 #endif
140
141 #ifndef atomic_and
142 ATOMIC_OP(and, &)
143 #endif
144
145 #ifndef atomic_or
146 ATOMIC_OP(or, |)
147 #endif
148
149 #ifndef atomic_xor
150 ATOMIC_OP(xor, ^)
151 #endif
152
153 #undef ATOMIC_FETCH_OP
154 #undef ATOMIC_OP_RETURN
155 #undef ATOMIC_OP
156
157 /*
158  * Atomic operations that C can't guarantee us.  Useful for
159  * resource counting etc..
160  */
161
162 #define ATOMIC_INIT(i)  { (i) }
163
164 /**
165  * atomic_read - read atomic variable
166  * @v: pointer of type atomic_t
167  *
168  * Atomically reads the value of @v.
169  */
170 #ifndef atomic_read
171 #define atomic_read(v)  READ_ONCE((v)->counter)
172 #endif
173
174 /**
175  * atomic_set - set atomic variable
176  * @v: pointer of type atomic_t
177  * @i: required value
178  *
179  * Atomically sets the value of @v to @i.
180  */
181 #define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
182
183 #include <linux/irqflags.h>
184
185 static inline void atomic_add(int i, atomic_t *v)
186 {
187         atomic_add_return(i, v);
188 }
189
190 static inline void atomic_sub(int i, atomic_t *v)
191 {
192         atomic_sub_return(i, v);
193 }
194
195 #define atomic_xchg(ptr, v)             (xchg(&(ptr)->counter, (v)))
196 #define atomic_cmpxchg(v, old, new)     (cmpxchg(&((v)->counter), (old), (new)))
197
198 #endif /* __ASM_GENERIC_ATOMIC_H */