Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
[linux-2.6.git] / arch / blackfin / mach-bf561 / atomic.S
1 /*
2  * Copyright 2007-2008 Analog Devices Inc.
3  *              Philippe Gerum <rpm@xenomai.org>
4  *
5  * Licensed under the GPL-2 or later.
6  */
7
8 #include <linux/linkage.h>
9 #include <asm/blackfin.h>
10 #include <asm/cache.h>
11 #include <asm/asm-offsets.h>
12 #include <asm/rwlock.h>
13 #include <asm/cplb.h>
14
15 .text
16
17 .macro coreslot_loadaddr reg:req
18         \reg\().l = _corelock;
19         \reg\().h = _corelock;
20 .endm
21
22 .macro safe_testset addr:req, scratch:req
23 #if ANOMALY_05000477
24         cli \scratch;
25         testset (\addr);
26         sti \scratch;
27 #else
28         testset (\addr);
29 #endif
30 .endm
31
32 /*
33  * r0 = address of atomic data to flush and invalidate (32bit).
34  *
35  * Clear interrupts and return the old mask.
36  * We assume that no atomic data can span cachelines.
37  *
38  * Clobbers: r2:0, p0
39  */
40 ENTRY(_get_core_lock)
41         r1 = -L1_CACHE_BYTES;
42         r1 = r0 & r1;
43         cli r0;
44         coreslot_loadaddr p0;
45 .Lretry_corelock:
46         safe_testset p0, r2;
47         if cc jump .Ldone_corelock;
48         SSYNC(r2);
49         jump .Lretry_corelock
50 .Ldone_corelock:
51         p0 = r1;
52         CSYNC(r2);
53         flushinv[p0];
54         SSYNC(r2);
55         rts;
56 ENDPROC(_get_core_lock)
57
58 /*
59  * r0 = address of atomic data in uncacheable memory region (32bit).
60  *
61  * Clear interrupts and return the old mask.
62  *
63  * Clobbers: r0, p0
64  */
65 ENTRY(_get_core_lock_noflush)
66         cli r0;
67         coreslot_loadaddr p0;
68 .Lretry_corelock_noflush:
69         safe_testset p0, r2;
70         if cc jump .Ldone_corelock_noflush;
71         SSYNC(r2);
72         jump .Lretry_corelock_noflush
73 .Ldone_corelock_noflush:
74         rts;
75 ENDPROC(_get_core_lock_noflush)
76
77 /*
78  * r0 = interrupt mask to restore.
79  * r1 = address of atomic data to flush and invalidate (32bit).
80  *
81  * Interrupts are masked on entry (see _get_core_lock).
82  * Clobbers: r2:0, p0
83  */
84 ENTRY(_put_core_lock)
85         /* Write-through cache assumed, so no flush needed here. */
86         coreslot_loadaddr p0;
87         r1 = 0;
88         [p0] = r1;
89         SSYNC(r2);
90         sti r0;
91         rts;
92 ENDPROC(_put_core_lock)
93
94 #ifdef __ARCH_SYNC_CORE_DCACHE
95
96 ENTRY(___raw_smp_mark_barrier_asm)
97         [--sp] = rets;
98         [--sp] = ( r7:5 );
99         [--sp] = r0;
100         [--sp] = p1;
101         [--sp] = p0;
102         call _get_core_lock_noflush;
103
104         /*
105          * Calculate current core mask
106          */
107         GET_CPUID(p1, r7);
108         r6 = 1;
109         r6 <<= r7;
110
111         /*
112          * Set bit of other cores in barrier mask. Don't change current core bit.
113          */
114         p1.l = _barrier_mask;
115         p1.h = _barrier_mask;
116         r7 = [p1];
117         r5 = r7 & r6;
118         r7 = ~r6;
119         cc = r5 == 0;
120         if cc jump 1f;
121         r7 = r7 | r6;
122 1:
123         [p1] = r7;
124         SSYNC(r2);
125
126         call _put_core_lock;
127         p0 = [sp++];
128         p1 = [sp++];
129         r0 = [sp++];
130         ( r7:5 ) = [sp++];
131         rets = [sp++];
132         rts;
133 ENDPROC(___raw_smp_mark_barrier_asm)
134
135 ENTRY(___raw_smp_check_barrier_asm)
136         [--sp] = rets;
137         [--sp] = ( r7:5 );
138         [--sp] = r0;
139         [--sp] = p1;
140         [--sp] = p0;
141         call _get_core_lock_noflush;
142
143         /*
144          * Calculate current core mask
145          */
146         GET_CPUID(p1, r7);
147         r6 = 1;
148         r6 <<= r7;
149
150         /*
151          * Clear current core bit in barrier mask if it is set.
152          */
153         p1.l = _barrier_mask;
154         p1.h = _barrier_mask;
155         r7 = [p1];
156         r5 = r7 & r6;
157         cc = r5 == 0;
158         if cc jump 1f;
159         r6 = ~r6;
160         r7 = r7 & r6;
161         [p1] = r7;
162         SSYNC(r2);
163
164         call _put_core_lock;
165
166         /*
167          * Invalidate the entire D-cache of current core.
168          */
169         sp += -12;
170         call _resync_core_dcache
171         sp += 12;
172         jump 2f;
173 1:
174         call _put_core_lock;
175 2:
176         p0 = [sp++];
177         p1 = [sp++];
178         r0 = [sp++];
179         ( r7:5 ) = [sp++];
180         rets = [sp++];
181         rts;
182 ENDPROC(___raw_smp_check_barrier_asm)
183
184 /*
185  * r0 = irqflags
186  * r1 = address of atomic data
187  *
188  * Clobbers: r2:0, p1:0
189  */
190 _start_lock_coherent:
191
192         [--sp] = rets;
193         [--sp] = ( r7:6 );
194         r7 = r0;
195         p1 = r1;
196
197         /*
198          * Determine whether the atomic data was previously
199          * owned by another CPU (=r6).
200          */
201         GET_CPUID(p0, r2);
202         r1 = 1;
203         r1 <<= r2;
204         r2 = ~r1;
205
206         r1 = [p1];
207         r1 >>= 28;   /* CPU fingerprints are stored in the high nibble. */
208         r6 = r1 & r2;
209         r1 = [p1];
210         r1 <<= 4;
211         r1 >>= 4;
212         [p1] = r1;
213
214         /*
215          * Release the core lock now, but keep IRQs disabled while we are
216          * performing the remaining housekeeping chores for the current CPU.
217          */
218         coreslot_loadaddr p0;
219         r1 = 0;
220         [p0] = r1;
221
222         /*
223          * If another CPU has owned the same atomic section before us,
224          * then our D-cached copy of the shared data protected by the
225          * current spin/write_lock may be obsolete.
226          */
227         cc = r6 == 0;
228         if cc jump .Lcache_synced
229
230         /*
231          * Invalidate the entire D-cache of the current core.
232          */
233         sp += -12;
234         call _resync_core_dcache
235         sp += 12;
236
237 .Lcache_synced:
238         SSYNC(r2);
239         sti r7;
240         ( r7:6 ) = [sp++];
241         rets = [sp++];
242         rts
243
244 /*
245  * r0 = irqflags
246  * r1 = address of atomic data
247  *
248  * Clobbers: r2:0, p1:0
249  */
250 _end_lock_coherent:
251
252         p1 = r1;
253         GET_CPUID(p0, r2);
254         r2 += 28;
255         r1 = 1;
256         r1 <<= r2;
257         r2 = [p1];
258         r2 = r1 | r2;
259         [p1] = r2;
260         r1 = p1;
261         jump _put_core_lock;
262
263 #endif /* __ARCH_SYNC_CORE_DCACHE */
264
265 /*
266  * r0 = &spinlock->lock
267  *
268  * Clobbers: r3:0, p1:0
269  */
270 ENTRY(___raw_spin_is_locked_asm)
271         p1 = r0;
272         [--sp] = rets;
273         call _get_core_lock;
274         r3 = [p1];
275         cc = bittst( r3, 0 );
276         r3 = cc;
277         r1 = p1;
278         call _put_core_lock;
279         rets = [sp++];
280         r0 = r3;
281         rts;
282 ENDPROC(___raw_spin_is_locked_asm)
283
284 /*
285  * r0 = &spinlock->lock
286  *
287  * Clobbers: r3:0, p1:0
288  */
289 ENTRY(___raw_spin_lock_asm)
290         p1 = r0;
291         [--sp] = rets;
292 .Lretry_spinlock:
293         call _get_core_lock;
294         r1 = p1;
295         r2 = [p1];
296         cc = bittst( r2, 0 );
297         if cc jump .Lbusy_spinlock
298 #ifdef __ARCH_SYNC_CORE_DCACHE
299         r3 = p1;
300         bitset ( r2, 0 ); /* Raise the lock bit. */
301         [p1] = r2;
302         call _start_lock_coherent
303 #else
304         r2 = 1;
305         [p1] = r2;
306         call _put_core_lock;
307 #endif
308         rets = [sp++];
309         rts;
310
311 .Lbusy_spinlock:
312         /* We don't touch the atomic area if busy, so that flush
313            will behave like nop in _put_core_lock. */
314         call _put_core_lock;
315         SSYNC(r2);
316         r0 = p1;
317         jump .Lretry_spinlock
318 ENDPROC(___raw_spin_lock_asm)
319
320 /*
321  * r0 = &spinlock->lock
322  *
323  * Clobbers: r3:0, p1:0
324  */
325 ENTRY(___raw_spin_trylock_asm)
326         p1 = r0;
327         [--sp] = rets;
328         call _get_core_lock;
329         r1 = p1;
330         r3 = [p1];
331         cc = bittst( r3, 0 );
332         if cc jump .Lfailed_trylock
333 #ifdef __ARCH_SYNC_CORE_DCACHE
334         bitset ( r3, 0 ); /* Raise the lock bit. */
335         [p1] = r3;
336         call _start_lock_coherent
337 #else
338         r2 = 1;
339         [p1] = r2;
340         call _put_core_lock;
341 #endif
342         r0 = 1;
343         rets = [sp++];
344         rts;
345 .Lfailed_trylock:
346         call _put_core_lock;
347         r0 = 0;
348         rets = [sp++];
349         rts;
350 ENDPROC(___raw_spin_trylock_asm)
351
352 /*
353  * r0 = &spinlock->lock
354  *
355  * Clobbers: r2:0, p1:0
356  */
357 ENTRY(___raw_spin_unlock_asm)
358         p1 = r0;
359         [--sp] = rets;
360         call _get_core_lock;
361         r2 = [p1];
362         bitclr ( r2, 0 );
363         [p1] = r2;
364         r1 = p1;
365 #ifdef __ARCH_SYNC_CORE_DCACHE
366         call _end_lock_coherent
367 #else
368         call _put_core_lock;
369 #endif
370         rets = [sp++];
371         rts;
372 ENDPROC(___raw_spin_unlock_asm)
373
374 /*
375  * r0 = &rwlock->lock
376  *
377  * Clobbers: r2:0, p1:0
378  */
379 ENTRY(___raw_read_lock_asm)
380         p1 = r0;
381         [--sp] = rets;
382         call _get_core_lock;
383 .Lrdlock_try:
384         r1 = [p1];
385         r1 += -1;
386         [p1] = r1;
387         cc = r1 < 0;
388         if cc jump .Lrdlock_failed
389         r1 = p1;
390 #ifdef __ARCH_SYNC_CORE_DCACHE
391         call _start_lock_coherent
392 #else
393         call _put_core_lock;
394 #endif
395         rets = [sp++];
396         rts;
397
398 .Lrdlock_failed:
399         r1 += 1;
400         [p1] = r1;
401 .Lrdlock_wait:
402         r1 = p1;
403         call _put_core_lock;
404         SSYNC(r2);
405         r0 = p1;
406         call _get_core_lock;
407         r1 = [p1];
408         cc = r1 < 2;
409         if cc jump .Lrdlock_wait;
410         jump .Lrdlock_try
411 ENDPROC(___raw_read_lock_asm)
412
413 /*
414  * r0 = &rwlock->lock
415  *
416  * Clobbers: r3:0, p1:0
417  */
418 ENTRY(___raw_read_trylock_asm)
419         p1 = r0;
420         [--sp] = rets;
421         call _get_core_lock;
422         r1 = [p1];
423         cc = r1 <= 0;
424         if cc jump .Lfailed_tryrdlock;
425         r1 += -1;
426         [p1] = r1;
427         r1 = p1;
428 #ifdef __ARCH_SYNC_CORE_DCACHE
429         call _start_lock_coherent
430 #else
431         call _put_core_lock;
432 #endif
433         rets = [sp++];
434         r0 = 1;
435         rts;
436 .Lfailed_tryrdlock:
437         r1 = p1;
438         call _put_core_lock;
439         rets = [sp++];
440         r0 = 0;
441         rts;
442 ENDPROC(___raw_read_trylock_asm)
443
444 /*
445  * r0 = &rwlock->lock
446  *
447  * Note: Processing controlled by a reader lock should not have
448  * any side-effect on cache issues with the other core, so we
449  * just release the core lock and exit (no _end_lock_coherent).
450  *
451  * Clobbers: r3:0, p1:0
452  */
453 ENTRY(___raw_read_unlock_asm)
454         p1 = r0;
455         [--sp] = rets;
456         call _get_core_lock;
457         r1 = [p1];
458         r1 += 1;
459         [p1] = r1;
460         r1 = p1;
461         call _put_core_lock;
462         rets = [sp++];
463         rts;
464 ENDPROC(___raw_read_unlock_asm)
465
466 /*
467  * r0 = &rwlock->lock
468  *
469  * Clobbers: r3:0, p1:0
470  */
471 ENTRY(___raw_write_lock_asm)
472         p1 = r0;
473         r3.l = lo(RW_LOCK_BIAS);
474         r3.h = hi(RW_LOCK_BIAS);
475         [--sp] = rets;
476         call _get_core_lock;
477 .Lwrlock_try:
478         r1 = [p1];
479         r1 = r1 - r3;
480 #ifdef __ARCH_SYNC_CORE_DCACHE
481         r2 = r1;
482         r2 <<= 4;
483         r2 >>= 4;
484         cc = r2 == 0;
485 #else
486         cc = r1 == 0;
487 #endif
488         if !cc jump .Lwrlock_wait
489         [p1] = r1;
490         r1 = p1;
491 #ifdef __ARCH_SYNC_CORE_DCACHE
492         call _start_lock_coherent
493 #else
494         call _put_core_lock;
495 #endif
496         rets = [sp++];
497         rts;
498
499 .Lwrlock_wait:
500         r1 = p1;
501         call _put_core_lock;
502         SSYNC(r2);
503         r0 = p1;
504         call _get_core_lock;
505         r1 = [p1];
506 #ifdef __ARCH_SYNC_CORE_DCACHE
507         r1 <<= 4;
508         r1 >>= 4;
509 #endif
510         cc = r1 == r3;
511         if !cc jump .Lwrlock_wait;
512         jump .Lwrlock_try
513 ENDPROC(___raw_write_lock_asm)
514
515 /*
516  * r0 = &rwlock->lock
517  *
518  * Clobbers: r3:0, p1:0
519  */
520 ENTRY(___raw_write_trylock_asm)
521         p1 = r0;
522         [--sp] = rets;
523         call _get_core_lock;
524         r1 = [p1];
525         r2.l = lo(RW_LOCK_BIAS);
526         r2.h = hi(RW_LOCK_BIAS);
527         cc = r1 == r2;
528         if !cc jump .Lfailed_trywrlock;
529 #ifdef __ARCH_SYNC_CORE_DCACHE
530         r1 >>= 28;
531         r1 <<= 28;
532 #else
533         r1 = 0;
534 #endif
535         [p1] = r1;
536         r1 = p1;
537 #ifdef __ARCH_SYNC_CORE_DCACHE
538         call _start_lock_coherent
539 #else
540         call _put_core_lock;
541 #endif
542         rets = [sp++];
543         r0 = 1;
544         rts;
545
546 .Lfailed_trywrlock:
547         r1 = p1;
548         call _put_core_lock;
549         rets = [sp++];
550         r0 = 0;
551         rts;
552 ENDPROC(___raw_write_trylock_asm)
553
554 /*
555  * r0 = &rwlock->lock
556  *
557  * Clobbers: r3:0, p1:0
558  */
559 ENTRY(___raw_write_unlock_asm)
560         p1 = r0;
561         r3.l = lo(RW_LOCK_BIAS);
562         r3.h = hi(RW_LOCK_BIAS);
563         [--sp] = rets;
564         call _get_core_lock;
565         r1 = [p1];
566         r1 = r1 + r3;
567         [p1] = r1;
568         r1 = p1;
569 #ifdef __ARCH_SYNC_CORE_DCACHE
570         call _end_lock_coherent
571 #else
572         call _put_core_lock;
573 #endif
574         rets = [sp++];
575         rts;
576 ENDPROC(___raw_write_unlock_asm)
577
578 /*
579  * r0 = ptr
580  * r1 = value
581  *
582  * Add a signed value to a 32bit word and return the new value atomically.
583  * Clobbers: r3:0, p1:0
584  */
585 ENTRY(___raw_atomic_update_asm)
586         p1 = r0;
587         r3 = r1;
588         [--sp] = rets;
589         call _get_core_lock;
590         r2 = [p1];
591         r3 = r3 + r2;
592         [p1] = r3;
593         r1 = p1;
594         call _put_core_lock;
595         r0 = r3;
596         rets = [sp++];
597         rts;
598 ENDPROC(___raw_atomic_update_asm)
599
600 /*
601  * r0 = ptr
602  * r1 = mask
603  *
604  * Clear the mask bits from a 32bit word and return the old 32bit value
605  * atomically.
606  * Clobbers: r3:0, p1:0
607  */
608 ENTRY(___raw_atomic_clear_asm)
609         p1 = r0;
610         r3 = ~r1;
611         [--sp] = rets;
612         call _get_core_lock;
613         r2 = [p1];
614         r3 = r2 & r3;
615         [p1] = r3;
616         r3 = r2;
617         r1 = p1;
618         call _put_core_lock;
619         r0 = r3;
620         rets = [sp++];
621         rts;
622 ENDPROC(___raw_atomic_clear_asm)
623
624 /*
625  * r0 = ptr
626  * r1 = mask
627  *
628  * Set the mask bits into a 32bit word and return the old 32bit value
629  * atomically.
630  * Clobbers: r3:0, p1:0
631  */
632 ENTRY(___raw_atomic_set_asm)
633         p1 = r0;
634         r3 = r1;
635         [--sp] = rets;
636         call _get_core_lock;
637         r2 = [p1];
638         r3 = r2 | r3;
639         [p1] = r3;
640         r3 = r2;
641         r1 = p1;
642         call _put_core_lock;
643         r0 = r3;
644         rets = [sp++];
645         rts;
646 ENDPROC(___raw_atomic_set_asm)
647
648 /*
649  * r0 = ptr
650  * r1 = mask
651  *
652  * XOR the mask bits with a 32bit word and return the old 32bit value
653  * atomically.
654  * Clobbers: r3:0, p1:0
655  */
656 ENTRY(___raw_atomic_xor_asm)
657         p1 = r0;
658         r3 = r1;
659         [--sp] = rets;
660         call _get_core_lock;
661         r2 = [p1];
662         r3 = r2 ^ r3;
663         [p1] = r3;
664         r3 = r2;
665         r1 = p1;
666         call _put_core_lock;
667         r0 = r3;
668         rets = [sp++];
669         rts;
670 ENDPROC(___raw_atomic_xor_asm)
671
672 /*
673  * r0 = ptr
674  * r1 = mask
675  *
676  * Perform a logical AND between the mask bits and a 32bit word, and
677  * return the masked value. We need this on this architecture in
678  * order to invalidate the local cache before testing.
679  *
680  * Clobbers: r3:0, p1:0
681  */
682 ENTRY(___raw_atomic_test_asm)
683         p1 = r0;
684         r3 = r1;
685         r1 = -L1_CACHE_BYTES;
686         r1 = r0 & r1;
687         p0 = r1;
688         flushinv[p0];
689         SSYNC(r2);
690         r0 = [p1];
691         r0 = r0 & r3;
692         rts;
693 ENDPROC(___raw_atomic_test_asm)
694
695 /*
696  * r0 = ptr
697  * r1 = value
698  *
699  * Swap *ptr with value and return the old 32bit value atomically.
700  * Clobbers: r3:0, p1:0
701  */
702 #define __do_xchg(src, dst)             \
703         p1 = r0;                        \
704         r3 = r1;                        \
705         [--sp] = rets;                  \
706         call _get_core_lock;            \
707         r2 = src;                       \
708         dst = r3;                       \
709         r3 = r2;                        \
710         r1 = p1;                        \
711         call _put_core_lock;            \
712         r0 = r3;                        \
713         rets = [sp++];                  \
714         rts;
715
716 ENTRY(___raw_xchg_1_asm)
717         __do_xchg(b[p1] (z), b[p1])
718 ENDPROC(___raw_xchg_1_asm)
719
720 ENTRY(___raw_xchg_2_asm)
721         __do_xchg(w[p1] (z), w[p1])
722 ENDPROC(___raw_xchg_2_asm)
723
724 ENTRY(___raw_xchg_4_asm)
725         __do_xchg([p1], [p1])
726 ENDPROC(___raw_xchg_4_asm)
727
728 /*
729  * r0 = ptr
730  * r1 = new
731  * r2 = old
732  *
733  * Swap *ptr with new if *ptr == old and return the previous *ptr
734  * value atomically.
735  *
736  * Clobbers: r3:0, p1:0
737  */
738 #define __do_cmpxchg(src, dst)          \
739         [--sp] = rets;                  \
740         [--sp] = r4;                    \
741         p1 = r0;                        \
742         r3 = r1;                        \
743         r4 = r2;                        \
744         call _get_core_lock;            \
745         r2 = src;                       \
746         cc = r2 == r4;                  \
747         if !cc jump 1f;                 \
748         dst = r3;                       \
749      1: r3 = r2;                        \
750         r1 = p1;                        \
751         call _put_core_lock;            \
752         r0 = r3;                        \
753         r4 = [sp++];                    \
754         rets = [sp++];                  \
755         rts;
756
757 ENTRY(___raw_cmpxchg_1_asm)
758         __do_cmpxchg(b[p1] (z), b[p1])
759 ENDPROC(___raw_cmpxchg_1_asm)
760
761 ENTRY(___raw_cmpxchg_2_asm)
762         __do_cmpxchg(w[p1] (z), w[p1])
763 ENDPROC(___raw_cmpxchg_2_asm)
764
765 ENTRY(___raw_cmpxchg_4_asm)
766         __do_cmpxchg([p1], [p1])
767 ENDPROC(___raw_cmpxchg_4_asm)
768
769 /*
770  * r0 = ptr
771  * r1 = bitnr
772  *
773  * Set a bit in a 32bit word and return the old 32bit value atomically.
774  * Clobbers: r3:0, p1:0
775  */
776 ENTRY(___raw_bit_set_asm)
777         r2 = r1;
778         r1 = 1;
779         r1 <<= r2;
780         jump ___raw_atomic_set_asm
781 ENDPROC(___raw_bit_set_asm)
782
783 /*
784  * r0 = ptr
785  * r1 = bitnr
786  *
787  * Clear a bit in a 32bit word and return the old 32bit value atomically.
788  * Clobbers: r3:0, p1:0
789  */
790 ENTRY(___raw_bit_clear_asm)
791         r2 = r1;
792         r1 = 1;
793         r1 <<= r2;
794         jump ___raw_atomic_clear_asm
795 ENDPROC(___raw_bit_clear_asm)
796
797 /*
798  * r0 = ptr
799  * r1 = bitnr
800  *
801  * Toggle a bit in a 32bit word and return the old 32bit value atomically.
802  * Clobbers: r3:0, p1:0
803  */
804 ENTRY(___raw_bit_toggle_asm)
805         r2 = r1;
806         r1 = 1;
807         r1 <<= r2;
808         jump ___raw_atomic_xor_asm
809 ENDPROC(___raw_bit_toggle_asm)
810
811 /*
812  * r0 = ptr
813  * r1 = bitnr
814  *
815  * Test-and-set a bit in a 32bit word and return the old bit value atomically.
816  * Clobbers: r3:0, p1:0
817  */
818 ENTRY(___raw_bit_test_set_asm)
819         [--sp] = rets;
820         [--sp] = r1;
821         call ___raw_bit_set_asm
822         r1 = [sp++];
823         r2 = 1;
824         r2 <<= r1;
825         r0 = r0 & r2;
826         cc = r0 == 0;
827         if cc jump 1f
828         r0 = 1;
829 1:
830         rets = [sp++];
831         rts;
832 ENDPROC(___raw_bit_test_set_asm)
833
834 /*
835  * r0 = ptr
836  * r1 = bitnr
837  *
838  * Test-and-clear a bit in a 32bit word and return the old bit value atomically.
839  * Clobbers: r3:0, p1:0
840  */
841 ENTRY(___raw_bit_test_clear_asm)
842         [--sp] = rets;
843         [--sp] = r1;
844         call ___raw_bit_clear_asm
845         r1 = [sp++];
846         r2 = 1;
847         r2 <<= r1;
848         r0 = r0 & r2;
849         cc = r0 == 0;
850         if cc jump 1f
851         r0 = 1;
852 1:
853         rets = [sp++];
854         rts;
855 ENDPROC(___raw_bit_test_clear_asm)
856
857 /*
858  * r0 = ptr
859  * r1 = bitnr
860  *
861  * Test-and-toggle a bit in a 32bit word,
862  * and return the old bit value atomically.
863  * Clobbers: r3:0, p1:0
864  */
865 ENTRY(___raw_bit_test_toggle_asm)
866         [--sp] = rets;
867         [--sp] = r1;
868         call ___raw_bit_toggle_asm
869         r1 = [sp++];
870         r2 = 1;
871         r2 <<= r1;
872         r0 = r0 & r2;
873         cc = r0 == 0;
874         if cc jump 1f
875         r0 = 1;
876 1:
877         rets = [sp++];
878         rts;
879 ENDPROC(___raw_bit_test_toggle_asm)
880
881 /*
882  * r0 = ptr
883  * r1 = bitnr
884  *
885  * Test a bit in a 32bit word and return its value.
886  * We need this on this architecture in order to invalidate
887  * the local cache before testing.
888  *
889  * Clobbers: r3:0, p1:0
890  */
891 ENTRY(___raw_bit_test_asm)
892         r2 = r1;
893         r1 = 1;
894         r1 <<= r2;
895         jump ___raw_atomic_test_asm
896 ENDPROC(___raw_bit_test_asm)
897
898 /*
899  * r0 = ptr
900  *
901  * Fetch and return an uncached 32bit value.
902  *
903  * Clobbers: r2:0, p1:0
904  */
905 ENTRY(___raw_uncached_fetch_asm)
906         p1 = r0;
907         r1 = -L1_CACHE_BYTES;
908         r1 = r0 & r1;
909         p0 = r1;
910         flushinv[p0];
911         SSYNC(r2);
912         r0 = [p1];
913         rts;
914 ENDPROC(___raw_uncached_fetch_asm)