a804f96e90e2fd01504eb267c5dceaa3913eecf0
[linux-block.git] / arch / x86 / lib / atomic64_32.c
1 #include <linux/compiler.h>
2 #include <linux/module.h>
3 #include <linux/types.h>
4
5 #include <asm/processor.h>
6 #include <asm/cmpxchg.h>
7 #include <asm/atomic.h>
8
9 static noinline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new)
10 {
11         u32 low = new;
12         u32 high = new >> 32;
13
14         asm volatile(
15                 LOCK_PREFIX "cmpxchg8b %1\n"
16                      : "+A" (old), "+m" (*ptr)
17                      :  "b" (low),  "c" (high)
18                      );
19         return old;
20 }
21
22 u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val)
23 {
24         return cmpxchg8b(&ptr->counter, old_val, new_val);
25 }
26 EXPORT_SYMBOL(atomic64_cmpxchg);
27
28 /**
29  * atomic64_xchg - xchg atomic64 variable
30  * @ptr:      pointer to type atomic64_t
31  * @new_val:  value to assign
32  *
33  * Atomically xchgs the value of @ptr to @new_val and returns
34  * the old value.
35  */
36 u64 atomic64_xchg(atomic64_t *ptr, u64 new_val)
37 {
38         /*
39          * Try first with a (possibly incorrect) assumption about
40          * what we have there. We'll do two loops most likely,
41          * but we'll get an ownership MESI transaction straight away
42          * instead of a read transaction followed by a
43          * flush-for-ownership transaction:
44          */
45         u64 old_val, real_val = 0;
46
47         do {
48                 old_val = real_val;
49
50                 real_val = atomic64_cmpxchg(ptr, old_val, new_val);
51
52         } while (real_val != old_val);
53
54         return old_val;
55 }
56 EXPORT_SYMBOL(atomic64_xchg);
57
58 /**
59  * atomic64_set - set atomic64 variable
60  * @ptr:      pointer to type atomic64_t
61  * @new_val:  value to assign
62  *
63  * Atomically sets the value of @ptr to @new_val.
64  */
65 void atomic64_set(atomic64_t *ptr, u64 new_val)
66 {
67         atomic64_xchg(ptr, new_val);
68 }
69 EXPORT_SYMBOL(atomic64_read);
70
71 /**
72  * atomic64_read - read atomic64 variable
73  * @ptr:      pointer to type atomic64_t
74  *
75  * Atomically reads the value of @ptr and returns it.
76  */
77 u64 atomic64_read(atomic64_t *ptr)
78 {
79         u64 res;
80
81         asm volatile(
82                 "mov %%ebx, %%eax\n\t"
83                 "mov %%ecx, %%edx\n\t"
84                 LOCK_PREFIX "cmpxchg8b %1\n"
85                         : "+A" (res)
86                         : "m" (*ptr)
87                 );
88
89         return res;
90 }
91 EXPORT_SYMBOL(atomic64_read);
92
93 /**
94  * atomic64_add_return - add and return
95  * @delta: integer value to add
96  * @ptr:   pointer to type atomic64_t
97  *
98  * Atomically adds @delta to @ptr and returns @delta + *@ptr
99  */
100 noinline u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
101 {
102         /*
103          * Try first with a (possibly incorrect) assumption about
104          * what we have there. We'll do two loops most likely,
105          * but we'll get an ownership MESI transaction straight away
106          * instead of a read transaction followed by a
107          * flush-for-ownership transaction:
108          */
109         u64 old_val, new_val, real_val = 0;
110
111         do {
112                 old_val = real_val;
113                 new_val = old_val + delta;
114
115                 real_val = atomic64_cmpxchg(ptr, old_val, new_val);
116
117         } while (real_val != old_val);
118
119         return new_val;
120 }
121 EXPORT_SYMBOL(atomic64_add_return);
122
123 u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
124 {
125         return atomic64_add_return(-delta, ptr);
126 }
127 EXPORT_SYMBOL(atomic64_sub_return);
128
129 u64 atomic64_inc_return(atomic64_t *ptr)
130 {
131         return atomic64_add_return(1, ptr);
132 }
133 EXPORT_SYMBOL(atomic64_inc_return);
134
135 u64 atomic64_dec_return(atomic64_t *ptr)
136 {
137         return atomic64_sub_return(1, ptr);
138 }
139 EXPORT_SYMBOL(atomic64_dec_return);
140
141 /**
142  * atomic64_add - add integer to atomic64 variable
143  * @delta: integer value to add
144  * @ptr:   pointer to type atomic64_t
145  *
146  * Atomically adds @delta to @ptr.
147  */
148 void atomic64_add(u64 delta, atomic64_t *ptr)
149 {
150         atomic64_add_return(delta, ptr);
151 }
152 EXPORT_SYMBOL(atomic64_add);
153
154 /**
155  * atomic64_sub - subtract the atomic64 variable
156  * @delta: integer value to subtract
157  * @ptr:   pointer to type atomic64_t
158  *
159  * Atomically subtracts @delta from @ptr.
160  */
161 void atomic64_sub(u64 delta, atomic64_t *ptr)
162 {
163         atomic64_add(-delta, ptr);
164 }
165 EXPORT_SYMBOL(atomic64_sub);
166
167 /**
168  * atomic64_sub_and_test - subtract value from variable and test result
169  * @delta: integer value to subtract
170  * @ptr:   pointer to type atomic64_t
171  *
172  * Atomically subtracts @delta from @ptr and returns
173  * true if the result is zero, or false for all
174  * other cases.
175  */
176 int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
177 {
178         u64 old_val = atomic64_sub_return(delta, ptr);
179
180         return old_val == 0;
181 }
182 EXPORT_SYMBOL(atomic64_sub_and_test);
183
184 /**
185  * atomic64_inc - increment atomic64 variable
186  * @ptr: pointer to type atomic64_t
187  *
188  * Atomically increments @ptr by 1.
189  */
190 void atomic64_inc(atomic64_t *ptr)
191 {
192         atomic64_add(1, ptr);
193 }
194 EXPORT_SYMBOL(atomic64_inc);
195
196 /**
197  * atomic64_dec - decrement atomic64 variable
198  * @ptr: pointer to type atomic64_t
199  *
200  * Atomically decrements @ptr by 1.
201  */
202 void atomic64_dec(atomic64_t *ptr)
203 {
204         atomic64_sub(1, ptr);
205 }
206 EXPORT_SYMBOL(atomic64_dec);
207
208 /**
209  * atomic64_dec_and_test - decrement and test
210  * @ptr: pointer to type atomic64_t
211  *
212  * Atomically decrements @ptr by 1 and
213  * returns true if the result is 0, or false for all other
214  * cases.
215  */
216 int atomic64_dec_and_test(atomic64_t *ptr)
217 {
218         return atomic64_sub_and_test(1, ptr);
219 }
220 EXPORT_SYMBOL(atomic64_dec_and_test);
221
222 /**
223  * atomic64_inc_and_test - increment and test
224  * @ptr: pointer to type atomic64_t
225  *
226  * Atomically increments @ptr by 1
227  * and returns true if the result is zero, or false for all
228  * other cases.
229  */
230 int atomic64_inc_and_test(atomic64_t *ptr)
231 {
232         return atomic64_sub_and_test(-1, ptr);
233 }
234 EXPORT_SYMBOL(atomic64_inc_and_test);
235
236 /**
237  * atomic64_add_negative - add and test if negative
238  * @delta: integer value to add
239  * @ptr:   pointer to type atomic64_t
240  *
241  * Atomically adds @delta to @ptr and returns true
242  * if the result is negative, or false when
243  * result is greater than or equal to zero.
244  */
245 int atomic64_add_negative(u64 delta, atomic64_t *ptr)
246 {
247         long long old_val = atomic64_add_return(delta, ptr);
248
249         return old_val < 0;
250 }
251 EXPORT_SYMBOL(atomic64_add_negative);