xref: /kvm-unit-tests/lib/x86/atomic.h (revision a322d4c597bb7a4de7985e7b51b80504f7e4fdda)
1 #ifndef __ATOMIC_H
2 #define __ATOMIC_H
3 
4 typedef struct {
5 	volatile int counter;
6 } atomic_t;
7 
8 #ifdef __i386__
9 
10 /**
11  * atomic_read - read atomic variable
12  * @v: pointer of type atomic_t
13  *
14  * Atomically reads the value of @v.
15  */
16 static inline int atomic_read(const atomic_t *v)
17 {
18 	return v->counter;
19 }
20 
21 /**
22  * atomic_set - set atomic variable
23  * @v: pointer of type atomic_t
24  * @i: required value
25  *
26  * Atomically sets the value of @v to @i.
27  */
28 static inline void atomic_set(atomic_t *v, int i)
29 {
30 	v->counter = i;
31 }
32 
33 /**
34  * atomic_inc - increment atomic variable
35  * @v: pointer of type atomic_t
36  *
37  * Atomically increments @v by 1.
38  */
39 static inline void atomic_inc(atomic_t *v)
40 {
41 	asm volatile("lock incl %0"
42 		     : "+m" (v->counter));
43 }
44 
45 /**
46  * atomic_dec - decrement atomic variable
47  * @v: pointer of type atomic_t
48  *
49  * Atomically decrements @v by 1.
50  */
51 static inline void atomic_dec(atomic_t *v)
52 {
53 	asm volatile("lock decl %0"
54 		     : "+m" (v->counter));
55 }
56 
57 typedef struct {
58 	u64 __attribute__((aligned(8))) counter;
59 } atomic64_t;
60 
61 #define ATOMIC64_INIT(val)	{ (val) }
62 
63 /**
64  * atomic64_read - read atomic64 variable
65  * @ptr:      pointer to type atomic64_t
66  *
67  * Atomically reads the value of @ptr and returns it.
68  */
69 static inline u64 atomic64_read(atomic64_t *ptr)
70 {
71 	u64 res;
72 
73 	/*
74 	 * Note, we inline this atomic64_t primitive because
75 	 * it only clobbers EAX/EDX and leaves the others
76 	 * untouched. We also (somewhat subtly) rely on the
77 	 * fact that cmpxchg8b returns the current 64-bit value
78 	 * of the memory location we are touching:
79 	 */
80 	asm volatile("mov %%ebx, %%eax\n\t"
81                      "mov %%ecx, %%edx\n\t"
82                      "lock cmpxchg8b %1\n"
83                      : "=&A" (res)
84                      : "m" (*ptr)
85                      );
86 	return res;
87 }
88 
89 u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new);
90 
91 #elif defined(__x86_64__)
92 
93 /**
94  * atomic_read - read atomic variable
95  * @v: pointer of type atomic_t
96  *
97  * Atomically reads the value of @v.
98  */
99 static inline int atomic_read(const atomic_t *v)
100 {
101 	return v->counter;
102 }
103 
104 /**
105  * atomic_set - set atomic variable
106  * @v: pointer of type atomic_t
107  * @i: required value
108  *
109  * Atomically sets the value of @v to @i.
110  */
111 static inline void atomic_set(atomic_t *v, int i)
112 {
113 	v->counter = i;
114 }
115 
116 /**
117  * atomic_inc - increment atomic variable
118  * @v: pointer of type atomic_t
119  *
120  * Atomically increments @v by 1.
121  */
122 static inline void atomic_inc(atomic_t *v)
123 {
124 	asm volatile("lock incl %0"
125 		     : "=m" (v->counter)
126 		     : "m" (v->counter));
127 }
128 
129 /**
130  * atomic_dec - decrement atomic variable
131  * @v: pointer of type atomic_t
132  *
133  * Atomically decrements @v by 1.
134  */
135 static inline void atomic_dec(atomic_t *v)
136 {
137 	asm volatile("lock decl %0"
138 		     : "=m" (v->counter)
139 		     : "m" (v->counter));
140 }
141 
142 typedef struct {
143 	long long counter;
144 } atomic64_t;
145 
146 #define ATOMIC64_INIT(i)	{ (i) }
147 
148 /**
149  * atomic64_read - read atomic64 variable
150  * @v: pointer of type atomic64_t
151  *
152  * Atomically reads the value of @v.
153  * Doesn't imply a read memory barrier.
154  */
155 static inline long atomic64_read(const atomic64_t *v)
156 {
157 	return v->counter;
158 }
159 
160 u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new);
161 
162 #endif
163 
164 #endif
165