blob: 5fc1e2caa5449077ab8bf8ecb68ba6c5303a9664 [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{
Eric Dumazet69237f92009-07-03 13:26:41 +02009 u32 low = new;
10 u32 high = new >> 32;
11
Ingo Molnarb7882b72009-07-03 13:26:39 +020012 asm volatile(
Eric Dumazet69237f92009-07-03 13:26:41 +020013 LOCK_PREFIX "cmpxchg8b %1\n"
14 : "+A" (old), "+m" (*ptr)
15 : "b" (low), "c" (high)
16 );
Ingo Molnarb7882b72009-07-03 13:26:39 +020017 return old;
18}
19
20u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val)
21{
22 return cmpxchg8b(&ptr->counter, old_val, new_val);
23}
24
25/**
26 * atomic64_xchg - xchg atomic64 variable
27 * @ptr: pointer to type atomic64_t
28 * @new_val: value to assign
29 *
30 * Atomically xchgs the value of @ptr to @new_val and returns
31 * the old value.
32 */
33
34u64 atomic64_xchg(atomic64_t *ptr, u64 new_val)
35{
36 u64 old_val;
37
38 do {
39 old_val = atomic_read(ptr);
40 } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
41
42 return old_val;
43}
44
45/**
46 * atomic64_set - set atomic64 variable
47 * @ptr: pointer to type atomic64_t
48 * @new_val: value to assign
49 *
50 * Atomically sets the value of @ptr to @new_val.
51 */
52void atomic64_set(atomic64_t *ptr, u64 new_val)
53{
54 atomic64_xchg(ptr, new_val);
55}
56
57/**
58 * atomic64_read - read atomic64 variable
59 * @ptr: pointer to type atomic64_t
60 *
61 * Atomically reads the value of @ptr and returns it.
62 */
63u64 atomic64_read(atomic64_t *ptr)
64{
Eric Dumazetaacf6822009-07-03 12:14:27 +020065 u64 old = 1LL << 32;
Ingo Molnarb7882b72009-07-03 13:26:39 +020066
Eric Dumazetaacf6822009-07-03 12:14:27 +020067 return cmpxchg8b(&ptr->counter, old, old);
Ingo Molnarb7882b72009-07-03 13:26:39 +020068}
69
70/**
71 * atomic64_add_return - add and return
72 * @delta: integer value to add
73 * @ptr: pointer to type atomic64_t
74 *
75 * Atomically adds @delta to @ptr and returns @delta + *@ptr
76 */
77u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
78{
79 u64 old_val, new_val;
80
81 do {
82 old_val = atomic_read(ptr);
83 new_val = old_val + delta;
84
85 } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
86
87 return new_val;
88}
89
90u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
91{
92 return atomic64_add_return(-delta, ptr);
93}
94
95u64 atomic64_inc_return(atomic64_t *ptr)
96{
97 return atomic64_add_return(1, ptr);
98}
99
100u64 atomic64_dec_return(atomic64_t *ptr)
101{
102 return atomic64_sub_return(1, ptr);
103}
104
105/**
106 * atomic64_add - add integer to atomic64 variable
107 * @delta: integer value to add
108 * @ptr: pointer to type atomic64_t
109 *
110 * Atomically adds @delta to @ptr.
111 */
112void atomic64_add(u64 delta, atomic64_t *ptr)
113{
114 atomic64_add_return(delta, ptr);
115}
116
117/**
118 * atomic64_sub - subtract the atomic64 variable
119 * @delta: integer value to subtract
120 * @ptr: pointer to type atomic64_t
121 *
122 * Atomically subtracts @delta from @ptr.
123 */
124void atomic64_sub(u64 delta, atomic64_t *ptr)
125{
126 atomic64_add(-delta, ptr);
127}
128
129/**
130 * atomic64_sub_and_test - subtract value from variable and test result
131 * @delta: integer value to subtract
132 * @ptr: pointer to type atomic64_t
133 *
134 * Atomically subtracts @delta from @ptr and returns
135 * true if the result is zero, or false for all
136 * other cases.
137 */
138int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
139{
140 u64 old_val = atomic64_sub_return(delta, ptr);
141
142 return old_val == 0;
143}
144
145/**
146 * atomic64_inc - increment atomic64 variable
147 * @ptr: pointer to type atomic64_t
148 *
149 * Atomically increments @ptr by 1.
150 */
151void atomic64_inc(atomic64_t *ptr)
152{
153 atomic64_add(1, ptr);
154}
155
156/**
157 * atomic64_dec - decrement atomic64 variable
158 * @ptr: pointer to type atomic64_t
159 *
160 * Atomically decrements @ptr by 1.
161 */
162void atomic64_dec(atomic64_t *ptr)
163{
164 atomic64_sub(1, ptr);
165}
166
167/**
168 * atomic64_dec_and_test - decrement and test
169 * @ptr: pointer to type atomic64_t
170 *
171 * Atomically decrements @ptr by 1 and
172 * returns true if the result is 0, or false for all other
173 * cases.
174 */
175int atomic64_dec_and_test(atomic64_t *ptr)
176{
177 return atomic64_sub_and_test(1, ptr);
178}
179
180/**
181 * atomic64_inc_and_test - increment and test
182 * @ptr: pointer to type atomic64_t
183 *
184 * Atomically increments @ptr by 1
185 * and returns true if the result is zero, or false for all
186 * other cases.
187 */
188int atomic64_inc_and_test(atomic64_t *ptr)
189{
190 return atomic64_sub_and_test(-1, ptr);
191}
192
193/**
194 * atomic64_add_negative - add and test if negative
195 * @delta: integer value to add
196 * @ptr: pointer to type atomic64_t
197 *
198 * Atomically adds @delta to @ptr and returns true
199 * if the result is negative, or false when
200 * result is greater than or equal to zero.
201 */
202int atomic64_add_negative(u64 delta, atomic64_t *ptr)
203{
204 long long old_val = atomic64_add_return(delta, ptr);
205
206 return old_val < 0;
207}