Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/include/asm/atomic.h
10821 views
1
#ifndef _ASM_X86_ATOMIC_H
2
#define _ASM_X86_ATOMIC_H
3
4
#include <linux/compiler.h>
5
#include <linux/types.h>
6
#include <asm/processor.h>
7
#include <asm/alternative.h>
8
#include <asm/cmpxchg.h>
9
10
/*
11
* Atomic operations that C can't guarantee us. Useful for
12
* resource counting etc..
13
*/
14
15
#define ATOMIC_INIT(i) { (i) }
16
17
/**
18
* atomic_read - read atomic variable
19
* @v: pointer of type atomic_t
20
*
21
* Atomically reads the value of @v.
22
*/
23
static inline int atomic_read(const atomic_t *v)
24
{
25
return (*(volatile int *)&(v)->counter);
26
}
27
28
/**
29
* atomic_set - set atomic variable
30
* @v: pointer of type atomic_t
31
* @i: required value
32
*
33
* Atomically sets the value of @v to @i.
34
*/
35
static inline void atomic_set(atomic_t *v, int i)
36
{
37
v->counter = i;
38
}
39
40
/**
41
* atomic_add - add integer to atomic variable
42
* @i: integer value to add
43
* @v: pointer of type atomic_t
44
*
45
* Atomically adds @i to @v.
46
*/
47
static inline void atomic_add(int i, atomic_t *v)
48
{
49
asm volatile(LOCK_PREFIX "addl %1,%0"
50
: "+m" (v->counter)
51
: "ir" (i));
52
}
53
54
/**
55
* atomic_sub - subtract integer from atomic variable
56
* @i: integer value to subtract
57
* @v: pointer of type atomic_t
58
*
59
* Atomically subtracts @i from @v.
60
*/
61
static inline void atomic_sub(int i, atomic_t *v)
62
{
63
asm volatile(LOCK_PREFIX "subl %1,%0"
64
: "+m" (v->counter)
65
: "ir" (i));
66
}
67
68
/**
69
* atomic_sub_and_test - subtract value from variable and test result
70
* @i: integer value to subtract
71
* @v: pointer of type atomic_t
72
*
73
* Atomically subtracts @i from @v and returns
74
* true if the result is zero, or false for all
75
* other cases.
76
*/
77
static inline int atomic_sub_and_test(int i, atomic_t *v)
78
{
79
unsigned char c;
80
81
asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
82
: "+m" (v->counter), "=qm" (c)
83
: "ir" (i) : "memory");
84
return c;
85
}
86
87
/**
88
* atomic_inc - increment atomic variable
89
* @v: pointer of type atomic_t
90
*
91
* Atomically increments @v by 1.
92
*/
93
static inline void atomic_inc(atomic_t *v)
94
{
95
asm volatile(LOCK_PREFIX "incl %0"
96
: "+m" (v->counter));
97
}
98
99
/**
100
* atomic_dec - decrement atomic variable
101
* @v: pointer of type atomic_t
102
*
103
* Atomically decrements @v by 1.
104
*/
105
static inline void atomic_dec(atomic_t *v)
106
{
107
asm volatile(LOCK_PREFIX "decl %0"
108
: "+m" (v->counter));
109
}
110
111
/**
112
* atomic_dec_and_test - decrement and test
113
* @v: pointer of type atomic_t
114
*
115
* Atomically decrements @v by 1 and
116
* returns true if the result is 0, or false for all other
117
* cases.
118
*/
119
static inline int atomic_dec_and_test(atomic_t *v)
120
{
121
unsigned char c;
122
123
asm volatile(LOCK_PREFIX "decl %0; sete %1"
124
: "+m" (v->counter), "=qm" (c)
125
: : "memory");
126
return c != 0;
127
}
128
129
/**
130
* 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 inline int atomic_inc_and_test(atomic_t *v)
138
{
139
unsigned char c;
140
141
asm volatile(LOCK_PREFIX "incl %0; sete %1"
142
: "+m" (v->counter), "=qm" (c)
143
: : "memory");
144
return c != 0;
145
}
146
147
/**
148
* atomic_add_negative - add and test if negative
149
* @i: integer value to add
150
* @v: pointer of type atomic_t
151
*
152
* Atomically adds @i to @v and returns true
153
* if the result is negative, or false when
154
* result is greater than or equal to zero.
155
*/
156
static inline int atomic_add_negative(int i, atomic_t *v)
157
{
158
unsigned char c;
159
160
asm volatile(LOCK_PREFIX "addl %2,%0; sets %1"
161
: "+m" (v->counter), "=qm" (c)
162
: "ir" (i) : "memory");
163
return c;
164
}
165
166
/**
167
* atomic_add_return - add integer and return
168
* @i: integer value to add
169
* @v: pointer of type atomic_t
170
*
171
* Atomically adds @i to @v and returns @i + @v
172
*/
173
static inline int atomic_add_return(int i, atomic_t *v)
174
{
175
int __i;
176
#ifdef CONFIG_M386
177
unsigned long flags;
178
if (unlikely(boot_cpu_data.x86 <= 3))
179
goto no_xadd;
180
#endif
181
/* Modern 486+ processor */
182
__i = i;
183
asm volatile(LOCK_PREFIX "xaddl %0, %1"
184
: "+r" (i), "+m" (v->counter)
185
: : "memory");
186
return i + __i;
187
188
#ifdef CONFIG_M386
189
no_xadd: /* Legacy 386 processor */
190
raw_local_irq_save(flags);
191
__i = atomic_read(v);
192
atomic_set(v, i + __i);
193
raw_local_irq_restore(flags);
194
return i + __i;
195
#endif
196
}
197
198
/**
199
* atomic_sub_return - subtract integer and return
200
* @v: pointer of type atomic_t
201
* @i: integer value to subtract
202
*
203
* Atomically subtracts @i from @v and returns @v - @i
204
*/
205
static inline int atomic_sub_return(int i, atomic_t *v)
206
{
207
return atomic_add_return(-i, v);
208
}
209
210
#define atomic_inc_return(v) (atomic_add_return(1, v))
211
#define atomic_dec_return(v) (atomic_sub_return(1, v))
212
213
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
214
{
215
return cmpxchg(&v->counter, old, new);
216
}
217
218
static inline int atomic_xchg(atomic_t *v, int new)
219
{
220
return xchg(&v->counter, new);
221
}
222
223
/**
224
* atomic_add_unless - add unless the number is already a given value
225
* @v: pointer of type atomic_t
226
* @a: the amount to add to v...
227
* @u: ...unless v is equal to u.
228
*
229
* Atomically adds @a to @v, so long as @v was not already @u.
230
* Returns non-zero if @v was not @u, and zero otherwise.
231
*/
232
static inline int atomic_add_unless(atomic_t *v, int a, int u)
233
{
234
int c, old;
235
c = atomic_read(v);
236
for (;;) {
237
if (unlikely(c == (u)))
238
break;
239
old = atomic_cmpxchg((v), c, c + (a));
240
if (likely(old == c))
241
break;
242
c = old;
243
}
244
return c != (u);
245
}
246
247
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
248
249
/*
250
* atomic_dec_if_positive - decrement by 1 if old value positive
251
* @v: pointer of type atomic_t
252
*
253
* The function returns the old value of *v minus 1, even if
254
* the atomic variable, v, was not decremented.
255
*/
256
static inline int atomic_dec_if_positive(atomic_t *v)
257
{
258
int c, old, dec;
259
c = atomic_read(v);
260
for (;;) {
261
dec = c - 1;
262
if (unlikely(dec < 0))
263
break;
264
old = atomic_cmpxchg((v), c, dec);
265
if (likely(old == c))
266
break;
267
c = old;
268
}
269
return dec;
270
}
271
272
/**
273
* atomic_inc_short - increment of a short integer
274
* @v: pointer to type int
275
*
276
* Atomically adds 1 to @v
277
* Returns the new value of @u
278
*/
279
static inline short int atomic_inc_short(short int *v)
280
{
281
asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
282
return *v;
283
}
284
285
#ifdef CONFIG_X86_64
286
/**
287
* atomic_or_long - OR of two long integers
288
* @v1: pointer to type unsigned long
289
* @v2: pointer to type unsigned long
290
*
291
* Atomically ORs @v1 and @v2
292
* Returns the result of the OR
293
*/
294
static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
295
{
296
asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2));
297
}
298
#endif
299
300
/* These are x86-specific, used by some header files */
301
#define atomic_clear_mask(mask, addr) \
302
asm volatile(LOCK_PREFIX "andl %0,%1" \
303
: : "r" (~(mask)), "m" (*(addr)) : "memory")
304
305
#define atomic_set_mask(mask, addr) \
306
asm volatile(LOCK_PREFIX "orl %0,%1" \
307
: : "r" ((unsigned)(mask)), "m" (*(addr)) \
308
: "memory")
309
310
/* Atomic operations are already serializing on x86 */
311
#define smp_mb__before_atomic_dec() barrier()
312
#define smp_mb__after_atomic_dec() barrier()
313
#define smp_mb__before_atomic_inc() barrier()
314
#define smp_mb__after_atomic_inc() barrier()
315
316
#ifdef CONFIG_X86_32
317
# include "atomic64_32.h"
318
#else
319
# include "atomic64_64.h"
320
#endif
321
322
#include <asm-generic/atomic-long.h>
323
#endif /* _ASM_X86_ATOMIC_H */
324
325