diff options
Diffstat (limited to 'arch/x86/lib/atomic64_32.c')
-rw-r--r-- | arch/x86/lib/atomic64_32.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c new file mode 100644 index 000000000000..d21e725d3d84 --- /dev/null +++ b/arch/x86/lib/atomic64_32.c | |||
@@ -0,0 +1,216 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <linux/types.h> | ||
3 | #include <asm/processor.h> | ||
4 | #include <asm/cmpxchg.h> | ||
5 | #include <asm/atomic.h> | ||
6 | |||
7 | static inline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new) | ||
8 | { | ||
9 | asm volatile( | ||
10 | |||
11 | LOCK_PREFIX "cmpxchg8b (%[ptr])\n" | ||
12 | |||
13 | : "=A" (old) | ||
14 | |||
15 | : [ptr] "D" (ptr), | ||
16 | "A" (old), | ||
17 | "b" (ll_low(new)), | ||
18 | "c" (ll_high(new)) | ||
19 | |||
20 | : "memory"); | ||
21 | |||
22 | return old; | ||
23 | } | ||
24 | |||
25 | u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val) | ||
26 | { | ||
27 | return cmpxchg8b(&ptr->counter, old_val, new_val); | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * atomic64_xchg - xchg atomic64 variable | ||
32 | * @ptr: pointer to type atomic64_t | ||
33 | * @new_val: value to assign | ||
34 | * | ||
35 | * Atomically xchgs the value of @ptr to @new_val and returns | ||
36 | * the old value. | ||
37 | */ | ||
38 | |||
39 | u64 atomic64_xchg(atomic64_t *ptr, u64 new_val) | ||
40 | { | ||
41 | u64 old_val; | ||
42 | |||
43 | do { | ||
44 | old_val = atomic_read(ptr); | ||
45 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
46 | |||
47 | return old_val; | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * atomic64_set - set atomic64 variable | ||
52 | * @ptr: pointer to type atomic64_t | ||
53 | * @new_val: value to assign | ||
54 | * | ||
55 | * Atomically sets the value of @ptr to @new_val. | ||
56 | */ | ||
57 | void atomic64_set(atomic64_t *ptr, u64 new_val) | ||
58 | { | ||
59 | atomic64_xchg(ptr, new_val); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * atomic64_read - read atomic64 variable | ||
64 | * @ptr: pointer to type atomic64_t | ||
65 | * | ||
66 | * Atomically reads the value of @ptr and returns it. | ||
67 | */ | ||
68 | u64 atomic64_read(atomic64_t *ptr) | ||
69 | { | ||
70 | u64 curr_val; | ||
71 | |||
72 | do { | ||
73 | curr_val = __atomic64_read(ptr); | ||
74 | } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val); | ||
75 | |||
76 | return curr_val; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * atomic64_add_return - add and return | ||
81 | * @delta: integer value to add | ||
82 | * @ptr: pointer to type atomic64_t | ||
83 | * | ||
84 | * Atomically adds @delta to @ptr and returns @delta + *@ptr | ||
85 | */ | ||
86 | u64 atomic64_add_return(u64 delta, atomic64_t *ptr) | ||
87 | { | ||
88 | u64 old_val, new_val; | ||
89 | |||
90 | do { | ||
91 | old_val = atomic_read(ptr); | ||
92 | new_val = old_val + delta; | ||
93 | |||
94 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
95 | |||
96 | return new_val; | ||
97 | } | ||
98 | |||
99 | u64 atomic64_sub_return(u64 delta, atomic64_t *ptr) | ||
100 | { | ||
101 | return atomic64_add_return(-delta, ptr); | ||
102 | } | ||
103 | |||
104 | u64 atomic64_inc_return(atomic64_t *ptr) | ||
105 | { | ||
106 | return atomic64_add_return(1, ptr); | ||
107 | } | ||
108 | |||
109 | u64 atomic64_dec_return(atomic64_t *ptr) | ||
110 | { | ||
111 | return atomic64_sub_return(1, ptr); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * atomic64_add - add integer to atomic64 variable | ||
116 | * @delta: integer value to add | ||
117 | * @ptr: pointer to type atomic64_t | ||
118 | * | ||
119 | * Atomically adds @delta to @ptr. | ||
120 | */ | ||
121 | void atomic64_add(u64 delta, atomic64_t *ptr) | ||
122 | { | ||
123 | atomic64_add_return(delta, ptr); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * atomic64_sub - subtract the atomic64 variable | ||
128 | * @delta: integer value to subtract | ||
129 | * @ptr: pointer to type atomic64_t | ||
130 | * | ||
131 | * Atomically subtracts @delta from @ptr. | ||
132 | */ | ||
133 | void atomic64_sub(u64 delta, atomic64_t *ptr) | ||
134 | { | ||
135 | atomic64_add(-delta, ptr); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * atomic64_sub_and_test - subtract value from variable and test result | ||
140 | * @delta: integer value to subtract | ||
141 | * @ptr: pointer to type atomic64_t | ||
142 | * | ||
143 | * Atomically subtracts @delta from @ptr and returns | ||
144 | * true if the result is zero, or false for all | ||
145 | * other cases. | ||
146 | */ | ||
147 | int atomic64_sub_and_test(u64 delta, atomic64_t *ptr) | ||
148 | { | ||
149 | u64 old_val = atomic64_sub_return(delta, ptr); | ||
150 | |||
151 | return old_val == 0; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * atomic64_inc - increment atomic64 variable | ||
156 | * @ptr: pointer to type atomic64_t | ||
157 | * | ||
158 | * Atomically increments @ptr by 1. | ||
159 | */ | ||
160 | void atomic64_inc(atomic64_t *ptr) | ||
161 | { | ||
162 | atomic64_add(1, ptr); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * atomic64_dec - decrement atomic64 variable | ||
167 | * @ptr: pointer to type atomic64_t | ||
168 | * | ||
169 | * Atomically decrements @ptr by 1. | ||
170 | */ | ||
171 | void atomic64_dec(atomic64_t *ptr) | ||
172 | { | ||
173 | atomic64_sub(1, ptr); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * atomic64_dec_and_test - decrement and test | ||
178 | * @ptr: pointer to type atomic64_t | ||
179 | * | ||
180 | * Atomically decrements @ptr by 1 and | ||
181 | * returns true if the result is 0, or false for all other | ||
182 | * cases. | ||
183 | */ | ||
184 | int atomic64_dec_and_test(atomic64_t *ptr) | ||
185 | { | ||
186 | return atomic64_sub_and_test(1, ptr); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * atomic64_inc_and_test - increment and test | ||
191 | * @ptr: pointer to type atomic64_t | ||
192 | * | ||
193 | * Atomically increments @ptr by 1 | ||
194 | * and returns true if the result is zero, or false for all | ||
195 | * other cases. | ||
196 | */ | ||
197 | int atomic64_inc_and_test(atomic64_t *ptr) | ||
198 | { | ||
199 | return atomic64_sub_and_test(-1, ptr); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * atomic64_add_negative - add and test if negative | ||
204 | * @delta: integer value to add | ||
205 | * @ptr: pointer to type atomic64_t | ||
206 | * | ||
207 | * Atomically adds @delta to @ptr and returns true | ||
208 | * if the result is negative, or false when | ||
209 | * result is greater than or equal to zero. | ||
210 | */ | ||
211 | int atomic64_add_negative(u64 delta, atomic64_t *ptr) | ||
212 | { | ||
213 | long long old_val = atomic64_add_return(delta, ptr); | ||
214 | |||
215 | return old_val < 0; | ||
216 | } | ||