blob: afa5d444918b4e05cac9d431e7fb01a32e8ffa9e [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{
Eric Dumazetaacf6822009-07-03 12:14:27 +020070 u64 old = 1LL << 32;
Ingo Molnarb7882b72009-07-03 13:26:39 +020071
Eric Dumazetaacf6822009-07-03 12:14:27 +020072 return cmpxchg8b(&ptr->counter, old, old);
Ingo Molnarb7882b72009-07-03 13:26:39 +020073}
74
75/**
76 * atomic64_add_return - add and return
77 * @delta: integer value to add
78 * @ptr: pointer to type atomic64_t
79 *
80 * Atomically adds @delta to @ptr and returns @delta + *@ptr
81 */
82u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
83{
84 u64 old_val, new_val;
85
86 do {
87 old_val = atomic_read(ptr);
88 new_val = old_val + delta;
89
90 } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
91
92 return new_val;
93}
94
95u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
96{
97 return atomic64_add_return(-delta, ptr);
98}
99
100u64 atomic64_inc_return(atomic64_t *ptr)
101{
102 return atomic64_add_return(1, ptr);
103}
104
105u64 atomic64_dec_return(atomic64_t *ptr)
106{
107 return atomic64_sub_return(1, ptr);
108}
109
110/**
111 * atomic64_add - add integer to atomic64 variable
112 * @delta: integer value to add
113 * @ptr: pointer to type atomic64_t
114 *
115 * Atomically adds @delta to @ptr.
116 */
117void atomic64_add(u64 delta, atomic64_t *ptr)
118{
119 atomic64_add_return(delta, ptr);
120}
121
122/**
123 * atomic64_sub - subtract the atomic64 variable
124 * @delta: integer value to subtract
125 * @ptr: pointer to type atomic64_t
126 *
127 * Atomically subtracts @delta from @ptr.
128 */
129void atomic64_sub(u64 delta, atomic64_t *ptr)
130{
131 atomic64_add(-delta, ptr);
132}
133
134/**
135 * atomic64_sub_and_test - subtract value from variable and test result
136 * @delta: integer value to subtract
137 * @ptr: pointer to type atomic64_t
138 *
139 * Atomically subtracts @delta from @ptr and returns
140 * true if the result is zero, or false for all
141 * other cases.
142 */
143int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
144{
145 u64 old_val = atomic64_sub_return(delta, ptr);
146
147 return old_val == 0;
148}
149
150/**
151 * atomic64_inc - increment atomic64 variable
152 * @ptr: pointer to type atomic64_t
153 *
154 * Atomically increments @ptr by 1.
155 */
156void atomic64_inc(atomic64_t *ptr)
157{
158 atomic64_add(1, ptr);
159}
160
161/**
162 * atomic64_dec - decrement atomic64 variable
163 * @ptr: pointer to type atomic64_t
164 *
165 * Atomically decrements @ptr by 1.
166 */
167void atomic64_dec(atomic64_t *ptr)
168{
169 atomic64_sub(1, ptr);
170}
171
172/**
173 * atomic64_dec_and_test - decrement and test
174 * @ptr: pointer to type atomic64_t
175 *
176 * Atomically decrements @ptr by 1 and
177 * returns true if the result is 0, or false for all other
178 * cases.
179 */
180int atomic64_dec_and_test(atomic64_t *ptr)
181{
182 return atomic64_sub_and_test(1, ptr);
183}
184
185/**
186 * atomic64_inc_and_test - increment and test
187 * @ptr: pointer to type atomic64_t
188 *
189 * Atomically increments @ptr by 1
190 * and returns true if the result is zero, or false for all
191 * other cases.
192 */
193int atomic64_inc_and_test(atomic64_t *ptr)
194{
195 return atomic64_sub_and_test(-1, ptr);
196}
197
198/**
199 * atomic64_add_negative - add and test if negative
200 * @delta: integer value to add
201 * @ptr: pointer to type atomic64_t
202 *
203 * Atomically adds @delta to @ptr and returns true
204 * if the result is negative, or false when
205 * result is greater than or equal to zero.
206 */
207int atomic64_add_negative(u64 delta, atomic64_t *ptr)
208{
209 long long old_val = atomic64_add_return(delta, ptr);
210
211 return old_val < 0;
212}