1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/spinlock.h>
21
22#ifndef _ASM_ATOMIC_H
23#define _ASM_ATOMIC_H
24
25#include <linux/irqflags.h>
26#include <asm/cpu-features.h>
27#include <asm/war.h>
28
29typedef struct { volatile int counter; } atomic_t;
30
31#define ATOMIC_INIT(i) { (i) }
32
33
34
35
36
37
38
39#define atomic_read(v) ((v)->counter)
40
41
42
43
44
45
46
47
48#define atomic_set(v,i) ((v)->counter = (i))
49
50
51
52
53
54
55
56
57static __inline__ void atomic_add(int i, atomic_t * v)
58{
59 if (cpu_has_llsc && R10000_LLSC_WAR) {
60 unsigned long temp;
61
62 __asm__ __volatile__(
63 " .set mips3 \n"
64 "1: ll %0, %1 # atomic_add \n"
65 " addu %0, %2 \n"
66 " sc %0, %1 \n"
67 " beqzl %0, 1b \n"
68 " .set mips0 \n"
69 : "=&r" (temp), "=m" (v->counter)
70 : "Ir" (i), "m" (v->counter));
71 } else if (cpu_has_llsc) {
72 unsigned long temp;
73
74 __asm__ __volatile__(
75 " .set mips3 \n"
76 "1: ll %0, %1 # atomic_add \n"
77 " addu %0, %2 \n"
78 " sc %0, %1 \n"
79 " beqz %0, 1b \n"
80 " .set mips0 \n"
81 : "=&r" (temp), "=m" (v->counter)
82 : "Ir" (i), "m" (v->counter));
83 } else {
84 unsigned long flags;
85
86 local_irq_save(flags);
87 v->counter += i;
88 local_irq_restore(flags);
89 }
90}
91
92
93
94
95
96
97
98
99static __inline__ void atomic_sub(int i, atomic_t * v)
100{
101 if (cpu_has_llsc && R10000_LLSC_WAR) {
102 unsigned long temp;
103
104 __asm__ __volatile__(
105 " .set mips3 \n"
106 "1: ll %0, %1 # atomic_sub \n"
107 " subu %0, %2 \n"
108 " sc %0, %1 \n"
109 " beqzl %0, 1b \n"
110 " .set mips0 \n"
111 : "=&r" (temp), "=m" (v->counter)
112 : "Ir" (i), "m" (v->counter));
113 } else if (cpu_has_llsc) {
114 unsigned long temp;
115
116 __asm__ __volatile__(
117 " .set mips3 \n"
118 "1: ll %0, %1 # atomic_sub \n"
119 " subu %0, %2 \n"
120 " sc %0, %1 \n"
121 " beqz %0, 1b \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 local_irq_save(flags);
129 v->counter -= i;
130 local_irq_restore(flags);
131 }
132}
133
134
135
136
137static __inline__ int atomic_add_return(int i, atomic_t * v)
138{
139 unsigned long result;
140
141 if (cpu_has_llsc && R10000_LLSC_WAR) {
142 unsigned long temp;
143
144 __asm__ __volatile__(
145 " .set mips3 \n"
146 "1: ll %1, %2 # atomic_add_return \n"
147 " addu %0, %1, %3 \n"
148 " sc %0, %2 \n"
149 " beqzl %0, 1b \n"
150 " addu %0, %1, %3 \n"
151 " sync \n"
152 " .set mips0 \n"
153 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
154 : "Ir" (i), "m" (v->counter)
155 : "memory");
156 } else if (cpu_has_llsc) {
157 unsigned long temp;
158
159 __asm__ __volatile__(
160 " .set mips3 \n"
161 "1: ll %1, %2 # atomic_add_return \n"
162 " addu %0, %1, %3 \n"
163 " sc %0, %2 \n"
164 " beqz %0, 1b \n"
165 " addu %0, %1, %3 \n"
166 " sync \n"
167 " .set mips0 \n"
168 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
169 : "Ir" (i), "m" (v->counter)
170 : "memory");
171 } else {
172 unsigned long flags;
173
174 local_irq_save(flags);
175 result = v->counter;
176 result += i;
177 v->counter = result;
178 local_irq_restore(flags);
179 }
180
181 return result;
182}
183
184static __inline__ int atomic_sub_return(int i, atomic_t * v)
185{
186 unsigned long result;
187
188 if (cpu_has_llsc && R10000_LLSC_WAR) {
189 unsigned long temp;
190
191 __asm__ __volatile__(
192 " .set mips3 \n"
193 "1: ll %1, %2 # atomic_sub_return \n"
194 " subu %0, %1, %3 \n"
195 " sc %0, %2 \n"
196 " beqzl %0, 1b \n"
197 " subu %0, %1, %3 \n"
198 " sync \n"
199 " .set mips0 \n"
200 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
201 : "Ir" (i), "m" (v->counter)
202 : "memory");
203 } else if (cpu_has_llsc) {
204 unsigned long temp;
205
206 __asm__ __volatile__(
207 " .set mips3 \n"
208 "1: ll %1, %2 # atomic_sub_return \n"
209 " subu %0, %1, %3 \n"
210 " sc %0, %2 \n"
211 " beqz %0, 1b \n"
212 " subu %0, %1, %3 \n"
213 " sync \n"
214 " .set mips0 \n"
215 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
216 : "Ir" (i), "m" (v->counter)
217 : "memory");
218 } else {
219 unsigned long flags;
220
221 local_irq_save(flags);
222 result = v->counter;
223 result -= i;
224 v->counter = result;
225 local_irq_restore(flags);
226 }
227
228 return result;
229}
230
231
232
233
234
235
236
237
238
239static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
240{
241 unsigned long result;
242
243 if (cpu_has_llsc && R10000_LLSC_WAR) {
244 unsigned long temp;
245
246 __asm__ __volatile__(
247 " .set mips3 \n"
248 "1: ll %1, %2 # atomic_sub_if_positive\n"
249 " subu %0, %1, %3 \n"
250 " bltz %0, 1f \n"
251 " sc %0, %2 \n"
252 " .set noreorder \n"
253 " beqzl %0, 1b \n"
254 " subu %0, %1, %3 \n"
255 " .set reorder \n"
256 " sync \n"
257 "1: \n"
258 " .set mips0 \n"
259 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
260 : "Ir" (i), "m" (v->counter)
261 : "memory");
262 } else if (cpu_has_llsc) {
263 unsigned long temp;
264
265 __asm__ __volatile__(
266 " .set mips3 \n"
267 "1: ll %1, %2 # atomic_sub_if_positive\n"
268 " subu %0, %1, %3 \n"
269 " bltz %0, 1f \n"
270 " sc %0, %2 \n"
271 " .set noreorder \n"
272 " beqz %0, 1b \n"
273 " subu %0, %1, %3 \n"
274 " .set reorder \n"
275 " sync \n"
276 "1: \n"
277 " .set mips0 \n"
278 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
279 : "Ir" (i), "m" (v->counter)
280 : "memory");
281 } else {
282 unsigned long flags;
283
284 local_irq_save(flags);
285 result = v->counter;
286 result -= i;
287 if (result >= 0)
288 v->counter = result;
289 local_irq_restore(flags);
290 }
291
292 return result;
293}
294
295#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
296#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
297
298
299
300
301
302
303
304
305
306
307#define atomic_add_unless(v, a, u) \
308({ \
309 int c, old; \
310 c = atomic_read(v); \
311 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
312 c = old; \
313 c != (u); \
314})
315#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
316
317#define atomic_dec_return(v) atomic_sub_return(1,(v))
318#define atomic_inc_return(v) atomic_add_return(1,(v))
319
320
321
322
323
324
325
326
327
328
329#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
330
331
332
333
334
335
336
337
338
339#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
340
341
342
343
344
345
346
347
348
349#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
350
351
352
353
354
355#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
356
357
358
359
360
361
362
363#define atomic_inc(v) atomic_add(1,(v))
364
365
366
367
368
369
370
371#define atomic_dec(v) atomic_sub(1,(v))
372
373
374
375
376
377
378
379
380
381
382#define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
383
384#ifdef CONFIG_64BIT
385
386typedef struct { volatile __s64 counter; } atomic64_t;
387
388#define ATOMIC64_INIT(i) { (i) }
389
390
391
392
393
394
395#define atomic64_read(v) ((v)->counter)
396
397
398
399
400
401
402#define atomic64_set(v,i) ((v)->counter = (i))
403
404
405
406
407
408
409
410
411static __inline__ void atomic64_add(long i, atomic64_t * v)
412{
413 if (cpu_has_llsc && R10000_LLSC_WAR) {
414 unsigned long temp;
415
416 __asm__ __volatile__(
417 " .set mips3 \n"
418 "1: lld %0, %1 # atomic64_add \n"
419 " addu %0, %2 \n"
420 " scd %0, %1 \n"
421 " beqzl %0, 1b \n"
422 " .set mips0 \n"
423 : "=&r" (temp), "=m" (v->counter)
424 : "Ir" (i), "m" (v->counter));
425 } else if (cpu_has_llsc) {
426 unsigned long temp;
427
428 __asm__ __volatile__(
429 " .set mips3 \n"
430 "1: lld %0, %1 # atomic64_add \n"
431 " addu %0, %2 \n"
432 " scd %0, %1 \n"
433 " beqz %0, 1b \n"
434 " .set mips0 \n"
435 : "=&r" (temp), "=m" (v->counter)
436 : "Ir" (i), "m" (v->counter));
437 } else {
438 unsigned long flags;
439
440 local_irq_save(flags);
441 v->counter += i;
442 local_irq_restore(flags);
443 }
444}
445
446
447
448
449
450
451
452
453static __inline__ void atomic64_sub(long i, atomic64_t * v)
454{
455 if (cpu_has_llsc && R10000_LLSC_WAR) {
456 unsigned long temp;
457
458 __asm__ __volatile__(
459 " .set mips3 \n"
460 "1: lld %0, %1 # atomic64_sub \n"
461 " subu %0, %2 \n"
462 " scd %0, %1 \n"
463 " beqzl %0, 1b \n"
464 " .set mips0 \n"
465 : "=&r" (temp), "=m" (v->counter)
466 : "Ir" (i), "m" (v->counter));
467 } else if (cpu_has_llsc) {
468 unsigned long temp;
469
470 __asm__ __volatile__(
471 " .set mips3 \n"
472 "1: lld %0, %1 # atomic64_sub \n"
473 " subu %0, %2 \n"
474 " scd %0, %1 \n"
475 " beqz %0, 1b \n"
476 " .set mips0 \n"
477 : "=&r" (temp), "=m" (v->counter)
478 : "Ir" (i), "m" (v->counter));
479 } else {
480 unsigned long flags;
481
482 local_irq_save(flags);
483 v->counter -= i;
484 local_irq_restore(flags);
485 }
486}
487
488
489
490
491static __inline__ long atomic64_add_return(long i, atomic64_t * v)
492{
493 unsigned long result;
494
495 if (cpu_has_llsc && R10000_LLSC_WAR) {
496 unsigned long temp;
497
498 __asm__ __volatile__(
499 " .set mips3 \n"
500 "1: lld %1, %2 # atomic64_add_return \n"
501 " addu %0, %1, %3 \n"
502 " scd %0, %2 \n"
503 " beqzl %0, 1b \n"
504 " addu %0, %1, %3 \n"
505 " sync \n"
506 " .set mips0 \n"
507 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
508 : "Ir" (i), "m" (v->counter)
509 : "memory");
510 } else if (cpu_has_llsc) {
511 unsigned long temp;
512
513 __asm__ __volatile__(
514 " .set mips3 \n"
515 "1: lld %1, %2 # atomic64_add_return \n"
516 " addu %0, %1, %3 \n"
517 " scd %0, %2 \n"
518 " beqz %0, 1b \n"
519 " addu %0, %1, %3 \n"
520 " sync \n"
521 " .set mips0 \n"
522 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
523 : "Ir" (i), "m" (v->counter)
524 : "memory");
525 } else {
526 unsigned long flags;
527
528 local_irq_save(flags);
529 result = v->counter;
530 result += i;
531 v->counter = result;
532 local_irq_restore(flags);
533 }
534
535 return result;
536}
537
538static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
539{
540 unsigned long result;
541
542 if (cpu_has_llsc && R10000_LLSC_WAR) {
543 unsigned long temp;
544
545 __asm__ __volatile__(
546 " .set mips3 \n"
547 "1: lld %1, %2 # atomic64_sub_return \n"
548 " subu %0, %1, %3 \n"
549 " scd %0, %2 \n"
550 " beqzl %0, 1b \n"
551 " subu %0, %1, %3 \n"
552 " sync \n"
553 " .set mips0 \n"
554 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
555 : "Ir" (i), "m" (v->counter)
556 : "memory");
557 } else if (cpu_has_llsc) {
558 unsigned long temp;
559
560 __asm__ __volatile__(
561 " .set mips3 \n"
562 "1: lld %1, %2 # atomic64_sub_return \n"
563 " subu %0, %1, %3 \n"
564 " scd %0, %2 \n"
565 " beqz %0, 1b \n"
566 " subu %0, %1, %3 \n"
567 " sync \n"
568 " .set mips0 \n"
569 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
570 : "Ir" (i), "m" (v->counter)
571 : "memory");
572 } else {
573 unsigned long flags;
574
575 local_irq_save(flags);
576 result = v->counter;
577 result -= i;
578 v->counter = result;
579 local_irq_restore(flags);
580 }
581
582 return result;
583}
584
585
586
587
588
589
590
591
592
593static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
594{
595 unsigned long result;
596
597 if (cpu_has_llsc && R10000_LLSC_WAR) {
598 unsigned long temp;
599
600 __asm__ __volatile__(
601 " .set mips3 \n"
602 "1: lld %1, %2 # atomic64_sub_if_positive\n"
603 " dsubu %0, %1, %3 \n"
604 " bltz %0, 1f \n"
605 " scd %0, %2 \n"
606 " .set noreorder \n"
607 " beqzl %0, 1b \n"
608 " dsubu %0, %1, %3 \n"
609 " .set reorder \n"
610 " sync \n"
611 "1: \n"
612 " .set mips0 \n"
613 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
614 : "Ir" (i), "m" (v->counter)
615 : "memory");
616 } else if (cpu_has_llsc) {
617 unsigned long temp;
618
619 __asm__ __volatile__(
620 " .set mips3 \n"
621 "1: lld %1, %2 # atomic64_sub_if_positive\n"
622 " dsubu %0, %1, %3 \n"
623 " bltz %0, 1f \n"
624 " scd %0, %2 \n"
625 " .set noreorder \n"
626 " beqz %0, 1b \n"
627 " dsubu %0, %1, %3 \n"
628 " .set reorder \n"
629 " sync \n"
630 "1: \n"
631 " .set mips0 \n"
632 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
633 : "Ir" (i), "m" (v->counter)
634 : "memory");
635 } else {
636 unsigned long flags;
637
638 local_irq_save(flags);
639 result = v->counter;
640 result -= i;
641 if (result >= 0)
642 v->counter = result;
643 local_irq_restore(flags);
644 }
645
646 return result;
647}
648
649#define atomic64_dec_return(v) atomic64_sub_return(1,(v))
650#define atomic64_inc_return(v) atomic64_add_return(1,(v))
651
652
653
654
655
656
657
658
659
660
661#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
662
663
664
665
666
667
668
669
670
671#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
672
673
674
675
676
677
678
679
680
681#define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
682
683
684
685
686
687#define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v)
688
689
690
691
692
693
694
695#define atomic64_inc(v) atomic64_add(1,(v))
696
697
698
699
700
701
702
703#define atomic64_dec(v) atomic64_sub(1,(v))
704
705
706
707
708
709
710
711
712
713
714#define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
715
716#endif
717
718
719
720
721
722#define smp_mb__before_atomic_dec() smp_mb()
723#define smp_mb__after_atomic_dec() smp_mb()
724#define smp_mb__before_atomic_inc() smp_mb()
725#define smp_mb__after_atomic_inc() smp_mb()
726
727#include <asm-generic/atomic.h>
728#endif
729