blob: d21e725d3d8458c4d7a31e895185059af5a008cb [file] [log] [blame]
Ingo Molnarb7882b72009-07-03 13:26:39 +02001#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
7static 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
25u64 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
39u64 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 */
57void 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 */
68u64 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 */
86u64 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
99u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
100{
101 return atomic64_add_return(-delta, ptr);
102}
103
104u64 atomic64_inc_return(atomic64_t *ptr)
105{
106 return atomic64_add_return(1, ptr);
107}
108
109u64 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 */
121void 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 */
133void 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 */
147int 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 */
160void 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 */
171void 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 */
184int 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 */
197int 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 */
211int 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}