diff options
Diffstat (limited to 'include/asm-mips/atomic.h')
-rw-r--r-- | include/asm-mips/atomic.h | 801 |
1 files changed, 0 insertions, 801 deletions
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h deleted file mode 100644 index 1232be3885b0..000000000000 --- a/include/asm-mips/atomic.h +++ /dev/null | |||
@@ -1,801 +0,0 @@ | |||
1 | /* | ||
2 | * Atomic operations that C can't guarantee us. Useful for | ||
3 | * resource counting etc.. | ||
4 | * | ||
5 | * But use these as seldom as possible since they are much more slower | ||
6 | * than regular operations. | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | * | ||
12 | * Copyright (C) 1996, 97, 99, 2000, 03, 04, 06 by Ralf Baechle | ||
13 | */ | ||
14 | #ifndef _ASM_ATOMIC_H | ||
15 | #define _ASM_ATOMIC_H | ||
16 | |||
17 | #include <linux/irqflags.h> | ||
18 | #include <asm/barrier.h> | ||
19 | #include <asm/cpu-features.h> | ||
20 | #include <asm/war.h> | ||
21 | #include <asm/system.h> | ||
22 | |||
23 | typedef struct { volatile int counter; } atomic_t; | ||
24 | |||
25 | #define ATOMIC_INIT(i) { (i) } | ||
26 | |||
27 | /* | ||
28 | * atomic_read - read atomic variable | ||
29 | * @v: pointer of type atomic_t | ||
30 | * | ||
31 | * Atomically reads the value of @v. | ||
32 | */ | ||
33 | #define atomic_read(v) ((v)->counter) | ||
34 | |||
35 | /* | ||
36 | * atomic_set - set atomic variable | ||
37 | * @v: pointer of type atomic_t | ||
38 | * @i: required value | ||
39 | * | ||
40 | * Atomically sets the value of @v to @i. | ||
41 | */ | ||
42 | #define atomic_set(v, i) ((v)->counter = (i)) | ||
43 | |||
44 | /* | ||
45 | * atomic_add - add integer to atomic variable | ||
46 | * @i: integer value to add | ||
47 | * @v: pointer of type atomic_t | ||
48 | * | ||
49 | * Atomically adds @i to @v. | ||
50 | */ | ||
51 | static __inline__ void atomic_add(int i, atomic_t * v) | ||
52 | { | ||
53 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
54 | unsigned long temp; | ||
55 | |||
56 | __asm__ __volatile__( | ||
57 | " .set mips3 \n" | ||
58 | "1: ll %0, %1 # atomic_add \n" | ||
59 | " addu %0, %2 \n" | ||
60 | " sc %0, %1 \n" | ||
61 | " beqzl %0, 1b \n" | ||
62 | " .set mips0 \n" | ||
63 | : "=&r" (temp), "=m" (v->counter) | ||
64 | : "Ir" (i), "m" (v->counter)); | ||
65 | } else if (cpu_has_llsc) { | ||
66 | unsigned long temp; | ||
67 | |||
68 | __asm__ __volatile__( | ||
69 | " .set mips3 \n" | ||
70 | "1: ll %0, %1 # atomic_add \n" | ||
71 | " addu %0, %2 \n" | ||
72 | " sc %0, %1 \n" | ||
73 | " beqz %0, 2f \n" | ||
74 | " .subsection 2 \n" | ||
75 | "2: b 1b \n" | ||
76 | " .previous \n" | ||
77 | " .set mips0 \n" | ||
78 | : "=&r" (temp), "=m" (v->counter) | ||
79 | : "Ir" (i), "m" (v->counter)); | ||
80 | } else { | ||
81 | unsigned long flags; | ||
82 | |||
83 | raw_local_irq_save(flags); | ||
84 | v->counter += i; | ||
85 | raw_local_irq_restore(flags); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * atomic_sub - subtract the atomic variable | ||
91 | * @i: integer value to subtract | ||
92 | * @v: pointer of type atomic_t | ||
93 | * | ||
94 | * Atomically subtracts @i from @v. | ||
95 | */ | ||
96 | static __inline__ void atomic_sub(int i, atomic_t * v) | ||
97 | { | ||
98 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
99 | unsigned long temp; | ||
100 | |||
101 | __asm__ __volatile__( | ||
102 | " .set mips3 \n" | ||
103 | "1: ll %0, %1 # atomic_sub \n" | ||
104 | " subu %0, %2 \n" | ||
105 | " sc %0, %1 \n" | ||
106 | " beqzl %0, 1b \n" | ||
107 | " .set mips0 \n" | ||
108 | : "=&r" (temp), "=m" (v->counter) | ||
109 | : "Ir" (i), "m" (v->counter)); | ||
110 | } else if (cpu_has_llsc) { | ||
111 | unsigned long temp; | ||
112 | |||
113 | __asm__ __volatile__( | ||
114 | " .set mips3 \n" | ||
115 | "1: ll %0, %1 # atomic_sub \n" | ||
116 | " subu %0, %2 \n" | ||
117 | " sc %0, %1 \n" | ||
118 | " beqz %0, 2f \n" | ||
119 | " .subsection 2 \n" | ||
120 | "2: b 1b \n" | ||
121 | " .previous \n" | ||
122 | " .set mips0 \n" | ||
123 | : "=&r" (temp), "=m" (v->counter) | ||
124 | : "Ir" (i), "m" (v->counter)); | ||
125 | } else { | ||
126 | unsigned long flags; | ||
127 | |||
128 | raw_local_irq_save(flags); | ||
129 | v->counter -= i; | ||
130 | raw_local_irq_restore(flags); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Same as above, but return the result value | ||
136 | */ | ||
137 | static __inline__ int atomic_add_return(int i, atomic_t * v) | ||
138 | { | ||
139 | unsigned long result; | ||
140 | |||
141 | smp_llsc_mb(); | ||
142 | |||
143 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
144 | unsigned long temp; | ||
145 | |||
146 | __asm__ __volatile__( | ||
147 | " .set mips3 \n" | ||
148 | "1: ll %1, %2 # atomic_add_return \n" | ||
149 | " addu %0, %1, %3 \n" | ||
150 | " sc %0, %2 \n" | ||
151 | " beqzl %0, 1b \n" | ||
152 | " addu %0, %1, %3 \n" | ||
153 | " .set mips0 \n" | ||
154 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
155 | : "Ir" (i), "m" (v->counter) | ||
156 | : "memory"); | ||
157 | } else if (cpu_has_llsc) { | ||
158 | unsigned long temp; | ||
159 | |||
160 | __asm__ __volatile__( | ||
161 | " .set mips3 \n" | ||
162 | "1: ll %1, %2 # atomic_add_return \n" | ||
163 | " addu %0, %1, %3 \n" | ||
164 | " sc %0, %2 \n" | ||
165 | " beqz %0, 2f \n" | ||
166 | " addu %0, %1, %3 \n" | ||
167 | " .subsection 2 \n" | ||
168 | "2: b 1b \n" | ||
169 | " .previous \n" | ||
170 | " .set mips0 \n" | ||
171 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
172 | : "Ir" (i), "m" (v->counter) | ||
173 | : "memory"); | ||
174 | } else { | ||
175 | unsigned long flags; | ||
176 | |||
177 | raw_local_irq_save(flags); | ||
178 | result = v->counter; | ||
179 | result += i; | ||
180 | v->counter = result; | ||
181 | raw_local_irq_restore(flags); | ||
182 | } | ||
183 | |||
184 | smp_llsc_mb(); | ||
185 | |||
186 | return result; | ||
187 | } | ||
188 | |||
189 | static __inline__ int atomic_sub_return(int i, atomic_t * v) | ||
190 | { | ||
191 | unsigned long result; | ||
192 | |||
193 | smp_llsc_mb(); | ||
194 | |||
195 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
196 | unsigned long temp; | ||
197 | |||
198 | __asm__ __volatile__( | ||
199 | " .set mips3 \n" | ||
200 | "1: ll %1, %2 # atomic_sub_return \n" | ||
201 | " subu %0, %1, %3 \n" | ||
202 | " sc %0, %2 \n" | ||
203 | " beqzl %0, 1b \n" | ||
204 | " subu %0, %1, %3 \n" | ||
205 | " .set mips0 \n" | ||
206 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
207 | : "Ir" (i), "m" (v->counter) | ||
208 | : "memory"); | ||
209 | } else if (cpu_has_llsc) { | ||
210 | unsigned long temp; | ||
211 | |||
212 | __asm__ __volatile__( | ||
213 | " .set mips3 \n" | ||
214 | "1: ll %1, %2 # atomic_sub_return \n" | ||
215 | " subu %0, %1, %3 \n" | ||
216 | " sc %0, %2 \n" | ||
217 | " beqz %0, 2f \n" | ||
218 | " subu %0, %1, %3 \n" | ||
219 | " .subsection 2 \n" | ||
220 | "2: b 1b \n" | ||
221 | " .previous \n" | ||
222 | " .set mips0 \n" | ||
223 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
224 | : "Ir" (i), "m" (v->counter) | ||
225 | : "memory"); | ||
226 | } else { | ||
227 | unsigned long flags; | ||
228 | |||
229 | raw_local_irq_save(flags); | ||
230 | result = v->counter; | ||
231 | result -= i; | ||
232 | v->counter = result; | ||
233 | raw_local_irq_restore(flags); | ||
234 | } | ||
235 | |||
236 | smp_llsc_mb(); | ||
237 | |||
238 | return result; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * atomic_sub_if_positive - conditionally subtract integer from atomic variable | ||
243 | * @i: integer value to subtract | ||
244 | * @v: pointer of type atomic_t | ||
245 | * | ||
246 | * Atomically test @v and subtract @i if @v is greater or equal than @i. | ||
247 | * The function returns the old value of @v minus @i. | ||
248 | */ | ||
249 | static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) | ||
250 | { | ||
251 | unsigned long result; | ||
252 | |||
253 | smp_llsc_mb(); | ||
254 | |||
255 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
256 | unsigned long temp; | ||
257 | |||
258 | __asm__ __volatile__( | ||
259 | " .set mips3 \n" | ||
260 | "1: ll %1, %2 # atomic_sub_if_positive\n" | ||
261 | " subu %0, %1, %3 \n" | ||
262 | " bltz %0, 1f \n" | ||
263 | " sc %0, %2 \n" | ||
264 | " .set noreorder \n" | ||
265 | " beqzl %0, 1b \n" | ||
266 | " subu %0, %1, %3 \n" | ||
267 | " .set reorder \n" | ||
268 | "1: \n" | ||
269 | " .set mips0 \n" | ||
270 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
271 | : "Ir" (i), "m" (v->counter) | ||
272 | : "memory"); | ||
273 | } else if (cpu_has_llsc) { | ||
274 | unsigned long temp; | ||
275 | |||
276 | __asm__ __volatile__( | ||
277 | " .set mips3 \n" | ||
278 | "1: ll %1, %2 # atomic_sub_if_positive\n" | ||
279 | " subu %0, %1, %3 \n" | ||
280 | " bltz %0, 1f \n" | ||
281 | " sc %0, %2 \n" | ||
282 | " .set noreorder \n" | ||
283 | " beqz %0, 2f \n" | ||
284 | " subu %0, %1, %3 \n" | ||
285 | " .set reorder \n" | ||
286 | " .subsection 2 \n" | ||
287 | "2: b 1b \n" | ||
288 | " .previous \n" | ||
289 | "1: \n" | ||
290 | " .set mips0 \n" | ||
291 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
292 | : "Ir" (i), "m" (v->counter) | ||
293 | : "memory"); | ||
294 | } else { | ||
295 | unsigned long flags; | ||
296 | |||
297 | raw_local_irq_save(flags); | ||
298 | result = v->counter; | ||
299 | result -= i; | ||
300 | if (result >= 0) | ||
301 | v->counter = result; | ||
302 | raw_local_irq_restore(flags); | ||
303 | } | ||
304 | |||
305 | smp_llsc_mb(); | ||
306 | |||
307 | return result; | ||
308 | } | ||
309 | |||
310 | #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) | ||
311 | #define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) | ||
312 | |||
313 | /** | ||
314 | * atomic_add_unless - add unless the number is a given value | ||
315 | * @v: pointer of type atomic_t | ||
316 | * @a: the amount to add to v... | ||
317 | * @u: ...unless v is equal to u. | ||
318 | * | ||
319 | * Atomically adds @a to @v, so long as it was not @u. | ||
320 | * Returns non-zero if @v was not @u, and zero otherwise. | ||
321 | */ | ||
322 | static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) | ||
323 | { | ||
324 | int c, old; | ||
325 | c = atomic_read(v); | ||
326 | for (;;) { | ||
327 | if (unlikely(c == (u))) | ||
328 | break; | ||
329 | old = atomic_cmpxchg((v), c, c + (a)); | ||
330 | if (likely(old == c)) | ||
331 | break; | ||
332 | c = old; | ||
333 | } | ||
334 | return c != (u); | ||
335 | } | ||
336 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | ||
337 | |||
338 | #define atomic_dec_return(v) atomic_sub_return(1, (v)) | ||
339 | #define atomic_inc_return(v) atomic_add_return(1, (v)) | ||
340 | |||
341 | /* | ||
342 | * atomic_sub_and_test - subtract value from variable and test result | ||
343 | * @i: integer value to subtract | ||
344 | * @v: pointer of type atomic_t | ||
345 | * | ||
346 | * Atomically subtracts @i from @v and returns | ||
347 | * true if the result is zero, or false for all | ||
348 | * other cases. | ||
349 | */ | ||
350 | #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) | ||
351 | |||
352 | /* | ||
353 | * atomic_inc_and_test - increment and test | ||
354 | * @v: pointer of type atomic_t | ||
355 | * | ||
356 | * Atomically increments @v by 1 | ||
357 | * and returns true if the result is zero, or false for all | ||
358 | * other cases. | ||
359 | */ | ||
360 | #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) | ||
361 | |||
362 | /* | ||
363 | * atomic_dec_and_test - decrement by 1 and test | ||
364 | * @v: pointer of type atomic_t | ||
365 | * | ||
366 | * Atomically decrements @v by 1 and | ||
367 | * returns true if the result is 0, or false for all other | ||
368 | * cases. | ||
369 | */ | ||
370 | #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) | ||
371 | |||
372 | /* | ||
373 | * atomic_dec_if_positive - decrement by 1 if old value positive | ||
374 | * @v: pointer of type atomic_t | ||
375 | */ | ||
376 | #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) | ||
377 | |||
378 | /* | ||
379 | * atomic_inc - increment atomic variable | ||
380 | * @v: pointer of type atomic_t | ||
381 | * | ||
382 | * Atomically increments @v by 1. | ||
383 | */ | ||
384 | #define atomic_inc(v) atomic_add(1, (v)) | ||
385 | |||
386 | /* | ||
387 | * atomic_dec - decrement and test | ||
388 | * @v: pointer of type atomic_t | ||
389 | * | ||
390 | * Atomically decrements @v by 1. | ||
391 | */ | ||
392 | #define atomic_dec(v) atomic_sub(1, (v)) | ||
393 | |||
394 | /* | ||
395 | * atomic_add_negative - add and test if negative | ||
396 | * @v: pointer of type atomic_t | ||
397 | * @i: integer value to add | ||
398 | * | ||
399 | * Atomically adds @i to @v and returns true | ||
400 | * if the result is negative, or false when | ||
401 | * result is greater than or equal to zero. | ||
402 | */ | ||
403 | #define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0) | ||
404 | |||
405 | #ifdef CONFIG_64BIT | ||
406 | |||
407 | typedef struct { volatile long counter; } atomic64_t; | ||
408 | |||
409 | #define ATOMIC64_INIT(i) { (i) } | ||
410 | |||
411 | /* | ||
412 | * atomic64_read - read atomic variable | ||
413 | * @v: pointer of type atomic64_t | ||
414 | * | ||
415 | */ | ||
416 | #define atomic64_read(v) ((v)->counter) | ||
417 | |||
418 | /* | ||
419 | * atomic64_set - set atomic variable | ||
420 | * @v: pointer of type atomic64_t | ||
421 | * @i: required value | ||
422 | */ | ||
423 | #define atomic64_set(v, i) ((v)->counter = (i)) | ||
424 | |||
425 | /* | ||
426 | * atomic64_add - add integer to atomic variable | ||
427 | * @i: integer value to add | ||
428 | * @v: pointer of type atomic64_t | ||
429 | * | ||
430 | * Atomically adds @i to @v. | ||
431 | */ | ||
432 | static __inline__ void atomic64_add(long i, atomic64_t * v) | ||
433 | { | ||
434 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
435 | unsigned long temp; | ||
436 | |||
437 | __asm__ __volatile__( | ||
438 | " .set mips3 \n" | ||
439 | "1: lld %0, %1 # atomic64_add \n" | ||
440 | " addu %0, %2 \n" | ||
441 | " scd %0, %1 \n" | ||
442 | " beqzl %0, 1b \n" | ||
443 | " .set mips0 \n" | ||
444 | : "=&r" (temp), "=m" (v->counter) | ||
445 | : "Ir" (i), "m" (v->counter)); | ||
446 | } else if (cpu_has_llsc) { | ||
447 | unsigned long temp; | ||
448 | |||
449 | __asm__ __volatile__( | ||
450 | " .set mips3 \n" | ||
451 | "1: lld %0, %1 # atomic64_add \n" | ||
452 | " addu %0, %2 \n" | ||
453 | " scd %0, %1 \n" | ||
454 | " beqz %0, 2f \n" | ||
455 | " .subsection 2 \n" | ||
456 | "2: b 1b \n" | ||
457 | " .previous \n" | ||
458 | " .set mips0 \n" | ||
459 | : "=&r" (temp), "=m" (v->counter) | ||
460 | : "Ir" (i), "m" (v->counter)); | ||
461 | } else { | ||
462 | unsigned long flags; | ||
463 | |||
464 | raw_local_irq_save(flags); | ||
465 | v->counter += i; | ||
466 | raw_local_irq_restore(flags); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * atomic64_sub - subtract the atomic variable | ||
472 | * @i: integer value to subtract | ||
473 | * @v: pointer of type atomic64_t | ||
474 | * | ||
475 | * Atomically subtracts @i from @v. | ||
476 | */ | ||
477 | static __inline__ void atomic64_sub(long i, atomic64_t * v) | ||
478 | { | ||
479 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
480 | unsigned long temp; | ||
481 | |||
482 | __asm__ __volatile__( | ||
483 | " .set mips3 \n" | ||
484 | "1: lld %0, %1 # atomic64_sub \n" | ||
485 | " subu %0, %2 \n" | ||
486 | " scd %0, %1 \n" | ||
487 | " beqzl %0, 1b \n" | ||
488 | " .set mips0 \n" | ||
489 | : "=&r" (temp), "=m" (v->counter) | ||
490 | : "Ir" (i), "m" (v->counter)); | ||
491 | } else if (cpu_has_llsc) { | ||
492 | unsigned long temp; | ||
493 | |||
494 | __asm__ __volatile__( | ||
495 | " .set mips3 \n" | ||
496 | "1: lld %0, %1 # atomic64_sub \n" | ||
497 | " subu %0, %2 \n" | ||
498 | " scd %0, %1 \n" | ||
499 | " beqz %0, 2f \n" | ||
500 | " .subsection 2 \n" | ||
501 | "2: b 1b \n" | ||
502 | " .previous \n" | ||
503 | " .set mips0 \n" | ||
504 | : "=&r" (temp), "=m" (v->counter) | ||
505 | : "Ir" (i), "m" (v->counter)); | ||
506 | } else { | ||
507 | unsigned long flags; | ||
508 | |||
509 | raw_local_irq_save(flags); | ||
510 | v->counter -= i; | ||
511 | raw_local_irq_restore(flags); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Same as above, but return the result value | ||
517 | */ | ||
518 | static __inline__ long atomic64_add_return(long i, atomic64_t * v) | ||
519 | { | ||
520 | unsigned long result; | ||
521 | |||
522 | smp_llsc_mb(); | ||
523 | |||
524 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
525 | unsigned long temp; | ||
526 | |||
527 | __asm__ __volatile__( | ||
528 | " .set mips3 \n" | ||
529 | "1: lld %1, %2 # atomic64_add_return \n" | ||
530 | " addu %0, %1, %3 \n" | ||
531 | " scd %0, %2 \n" | ||
532 | " beqzl %0, 1b \n" | ||
533 | " addu %0, %1, %3 \n" | ||
534 | " .set mips0 \n" | ||
535 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
536 | : "Ir" (i), "m" (v->counter) | ||
537 | : "memory"); | ||
538 | } else if (cpu_has_llsc) { | ||
539 | unsigned long temp; | ||
540 | |||
541 | __asm__ __volatile__( | ||
542 | " .set mips3 \n" | ||
543 | "1: lld %1, %2 # atomic64_add_return \n" | ||
544 | " addu %0, %1, %3 \n" | ||
545 | " scd %0, %2 \n" | ||
546 | " beqz %0, 2f \n" | ||
547 | " addu %0, %1, %3 \n" | ||
548 | " .subsection 2 \n" | ||
549 | "2: b 1b \n" | ||
550 | " .previous \n" | ||
551 | " .set mips0 \n" | ||
552 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
553 | : "Ir" (i), "m" (v->counter) | ||
554 | : "memory"); | ||
555 | } else { | ||
556 | unsigned long flags; | ||
557 | |||
558 | raw_local_irq_save(flags); | ||
559 | result = v->counter; | ||
560 | result += i; | ||
561 | v->counter = result; | ||
562 | raw_local_irq_restore(flags); | ||
563 | } | ||
564 | |||
565 | smp_llsc_mb(); | ||
566 | |||
567 | return result; | ||
568 | } | ||
569 | |||
570 | static __inline__ long atomic64_sub_return(long i, atomic64_t * v) | ||
571 | { | ||
572 | unsigned long result; | ||
573 | |||
574 | smp_llsc_mb(); | ||
575 | |||
576 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
577 | unsigned long temp; | ||
578 | |||
579 | __asm__ __volatile__( | ||
580 | " .set mips3 \n" | ||
581 | "1: lld %1, %2 # atomic64_sub_return \n" | ||
582 | " subu %0, %1, %3 \n" | ||
583 | " scd %0, %2 \n" | ||
584 | " beqzl %0, 1b \n" | ||
585 | " subu %0, %1, %3 \n" | ||
586 | " .set mips0 \n" | ||
587 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
588 | : "Ir" (i), "m" (v->counter) | ||
589 | : "memory"); | ||
590 | } else if (cpu_has_llsc) { | ||
591 | unsigned long temp; | ||
592 | |||
593 | __asm__ __volatile__( | ||
594 | " .set mips3 \n" | ||
595 | "1: lld %1, %2 # atomic64_sub_return \n" | ||
596 | " subu %0, %1, %3 \n" | ||
597 | " scd %0, %2 \n" | ||
598 | " beqz %0, 2f \n" | ||
599 | " subu %0, %1, %3 \n" | ||
600 | " .subsection 2 \n" | ||
601 | "2: b 1b \n" | ||
602 | " .previous \n" | ||
603 | " .set mips0 \n" | ||
604 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
605 | : "Ir" (i), "m" (v->counter) | ||
606 | : "memory"); | ||
607 | } else { | ||
608 | unsigned long flags; | ||
609 | |||
610 | raw_local_irq_save(flags); | ||
611 | result = v->counter; | ||
612 | result -= i; | ||
613 | v->counter = result; | ||
614 | raw_local_irq_restore(flags); | ||
615 | } | ||
616 | |||
617 | smp_llsc_mb(); | ||
618 | |||
619 | return result; | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * atomic64_sub_if_positive - conditionally subtract integer from atomic variable | ||
624 | * @i: integer value to subtract | ||
625 | * @v: pointer of type atomic64_t | ||
626 | * | ||
627 | * Atomically test @v and subtract @i if @v is greater or equal than @i. | ||
628 | * The function returns the old value of @v minus @i. | ||
629 | */ | ||
630 | static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) | ||
631 | { | ||
632 | unsigned long result; | ||
633 | |||
634 | smp_llsc_mb(); | ||
635 | |||
636 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
637 | unsigned long temp; | ||
638 | |||
639 | __asm__ __volatile__( | ||
640 | " .set mips3 \n" | ||
641 | "1: lld %1, %2 # atomic64_sub_if_positive\n" | ||
642 | " dsubu %0, %1, %3 \n" | ||
643 | " bltz %0, 1f \n" | ||
644 | " scd %0, %2 \n" | ||
645 | " .set noreorder \n" | ||
646 | " beqzl %0, 1b \n" | ||
647 | " dsubu %0, %1, %3 \n" | ||
648 | " .set reorder \n" | ||
649 | "1: \n" | ||
650 | " .set mips0 \n" | ||
651 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
652 | : "Ir" (i), "m" (v->counter) | ||
653 | : "memory"); | ||
654 | } else if (cpu_has_llsc) { | ||
655 | unsigned long temp; | ||
656 | |||
657 | __asm__ __volatile__( | ||
658 | " .set mips3 \n" | ||
659 | "1: lld %1, %2 # atomic64_sub_if_positive\n" | ||
660 | " dsubu %0, %1, %3 \n" | ||
661 | " bltz %0, 1f \n" | ||
662 | " scd %0, %2 \n" | ||
663 | " .set noreorder \n" | ||
664 | " beqz %0, 2f \n" | ||
665 | " dsubu %0, %1, %3 \n" | ||
666 | " .set reorder \n" | ||
667 | " .subsection 2 \n" | ||
668 | "2: b 1b \n" | ||
669 | " .previous \n" | ||
670 | "1: \n" | ||
671 | " .set mips0 \n" | ||
672 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
673 | : "Ir" (i), "m" (v->counter) | ||
674 | : "memory"); | ||
675 | } else { | ||
676 | unsigned long flags; | ||
677 | |||
678 | raw_local_irq_save(flags); | ||
679 | result = v->counter; | ||
680 | result -= i; | ||
681 | if (result >= 0) | ||
682 | v->counter = result; | ||
683 | raw_local_irq_restore(flags); | ||
684 | } | ||
685 | |||
686 | smp_llsc_mb(); | ||
687 | |||
688 | return result; | ||
689 | } | ||
690 | |||
691 | #define atomic64_cmpxchg(v, o, n) \ | ||
692 | ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) | ||
693 | #define atomic64_xchg(v, new) (xchg(&((v)->counter), (new))) | ||
694 | |||
695 | /** | ||
696 | * atomic64_add_unless - add unless the number is a given value | ||
697 | * @v: pointer of type atomic64_t | ||
698 | * @a: the amount to add to v... | ||
699 | * @u: ...unless v is equal to u. | ||
700 | * | ||
701 | * Atomically adds @a to @v, so long as it was not @u. | ||
702 | * Returns non-zero if @v was not @u, and zero otherwise. | ||
703 | */ | ||
704 | static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) | ||
705 | { | ||
706 | long c, old; | ||
707 | c = atomic64_read(v); | ||
708 | for (;;) { | ||
709 | if (unlikely(c == (u))) | ||
710 | break; | ||
711 | old = atomic64_cmpxchg((v), c, c + (a)); | ||
712 | if (likely(old == c)) | ||
713 | break; | ||
714 | c = old; | ||
715 | } | ||
716 | return c != (u); | ||
717 | } | ||
718 | |||
719 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) | ||
720 | |||
721 | #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) | ||
722 | #define atomic64_inc_return(v) atomic64_add_return(1, (v)) | ||
723 | |||
724 | /* | ||
725 | * atomic64_sub_and_test - subtract value from variable and test result | ||
726 | * @i: integer value to subtract | ||
727 | * @v: pointer of type atomic64_t | ||
728 | * | ||
729 | * Atomically subtracts @i from @v and returns | ||
730 | * true if the result is zero, or false for all | ||
731 | * other cases. | ||
732 | */ | ||
733 | #define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0) | ||
734 | |||
735 | /* | ||
736 | * atomic64_inc_and_test - increment and test | ||
737 | * @v: pointer of type atomic64_t | ||
738 | * | ||
739 | * Atomically increments @v by 1 | ||
740 | * and returns true if the result is zero, or false for all | ||
741 | * other cases. | ||
742 | */ | ||
743 | #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) | ||
744 | |||
745 | /* | ||
746 | * atomic64_dec_and_test - decrement by 1 and test | ||
747 | * @v: pointer of type atomic64_t | ||
748 | * | ||
749 | * Atomically decrements @v by 1 and | ||
750 | * returns true if the result is 0, or false for all other | ||
751 | * cases. | ||
752 | */ | ||
753 | #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) | ||
754 | |||
755 | /* | ||
756 | * atomic64_dec_if_positive - decrement by 1 if old value positive | ||
757 | * @v: pointer of type atomic64_t | ||
758 | */ | ||
759 | #define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v) | ||
760 | |||
761 | /* | ||
762 | * atomic64_inc - increment atomic variable | ||
763 | * @v: pointer of type atomic64_t | ||
764 | * | ||
765 | * Atomically increments @v by 1. | ||
766 | */ | ||
767 | #define atomic64_inc(v) atomic64_add(1, (v)) | ||
768 | |||
769 | /* | ||
770 | * atomic64_dec - decrement and test | ||
771 | * @v: pointer of type atomic64_t | ||
772 | * | ||
773 | * Atomically decrements @v by 1. | ||
774 | */ | ||
775 | #define atomic64_dec(v) atomic64_sub(1, (v)) | ||
776 | |||
777 | /* | ||
778 | * atomic64_add_negative - add and test if negative | ||
779 | * @v: pointer of type atomic64_t | ||
780 | * @i: integer value to add | ||
781 | * | ||
782 | * Atomically adds @i to @v and returns true | ||
783 | * if the result is negative, or false when | ||
784 | * result is greater than or equal to zero. | ||
785 | */ | ||
786 | #define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0) | ||
787 | |||
788 | #endif /* CONFIG_64BIT */ | ||
789 | |||
790 | /* | ||
791 | * atomic*_return operations are serializing but not the non-*_return | ||
792 | * versions. | ||
793 | */ | ||
794 | #define smp_mb__before_atomic_dec() smp_llsc_mb() | ||
795 | #define smp_mb__after_atomic_dec() smp_llsc_mb() | ||
796 | #define smp_mb__before_atomic_inc() smp_llsc_mb() | ||
797 | #define smp_mb__after_atomic_inc() smp_llsc_mb() | ||
798 | |||
799 | #include <asm-generic/atomic.h> | ||
800 | |||
801 | #endif /* _ASM_ATOMIC_H */ | ||