2 * File: arch/blackfin/mach-bf561/atomic.S
3 * Author: Philippe Gerum <rpm@xenomai.org>
5 * Copyright 2007 Analog Devices Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <linux/linkage.h>
24 #include <asm/blackfin.h>
25 #include <asm/cache.h>
26 #include <asm/asm-offsets.h>
27 #include <asm/rwlock.h>
32 .macro coreslot_loadaddr reg:req
33 \reg\().l = _corelock;
34 \reg\().h = _corelock;
38 * r0 = address of atomic data to flush and invalidate (32bit).
40 * Clear interrupts and return the old mask.
41 * We assume that no atomic data can span cachelines.
52 if cc jump .Ldone_corelock;
61 ENDPROC(_get_core_lock)
64 * r0 = address of atomic data in uncacheable memory region (32bit).
66 * Clear interrupts and return the old mask.
70 ENTRY(_get_core_lock_noflush)
73 .Lretry_corelock_noflush:
75 if cc jump .Ldone_corelock_noflush;
77 jump .Lretry_corelock_noflush
78 .Ldone_corelock_noflush:
80 ENDPROC(_get_core_lock_noflush)
83 * r0 = interrupt mask to restore.
84 * r1 = address of atomic data to flush and invalidate (32bit).
86 * Interrupts are masked on entry (see _get_core_lock).
90 /* Write-through cache assumed, so no flush needed here. */
97 ENDPROC(_put_core_lock)
99 #ifdef __ARCH_SYNC_CORE_DCACHE
101 ENTRY(___raw_smp_mark_barrier_asm)
107 call _get_core_lock_noflush;
110 * Calculate current core mask
117 * Set bit of other cores in barrier mask. Don't change current core bit.
119 p1.l = _barrier_mask;
120 p1.h = _barrier_mask;
138 ENDPROC(___raw_smp_mark_barrier_asm)
140 ENTRY(___raw_smp_check_barrier_asm)
146 call _get_core_lock_noflush;
149 * Calculate current core mask
156 * Clear current core bit in barrier mask if it is set.
158 p1.l = _barrier_mask;
159 p1.h = _barrier_mask;
172 * Invalidate the entire D-cache of current core.
175 call _resync_core_dcache
187 ENDPROC(___raw_smp_check_barrier_asm)
191 * r1 = address of atomic data
193 * Clobbers: r2:0, p1:0
195 _start_lock_coherent:
203 * Determine whether the atomic data was previously
204 * owned by another CPU (=r6).
212 r1 >>= 28; /* CPU fingerprints are stored in the high nibble. */
220 * Release the core lock now, but keep IRQs disabled while we are
221 * performing the remaining housekeeping chores for the current CPU.
223 coreslot_loadaddr p0;
228 * If another CPU has owned the same atomic section before us,
229 * then our D-cached copy of the shared data protected by the
230 * current spin/write_lock may be obsolete.
233 if cc jump .Lcache_synced
236 * Invalidate the entire D-cache of the current core.
239 call _resync_core_dcache
251 * r1 = address of atomic data
253 * Clobbers: r2:0, p1:0
268 #endif /* __ARCH_SYNC_CORE_DCACHE */
271 * r0 = &spinlock->lock
273 * Clobbers: r3:0, p1:0
275 ENTRY(___raw_spin_is_locked_asm)
280 cc = bittst( r3, 0 );
287 ENDPROC(___raw_spin_is_locked_asm)
290 * r0 = &spinlock->lock
292 * Clobbers: r3:0, p1:0
294 ENTRY(___raw_spin_lock_asm)
301 cc = bittst( r2, 0 );
302 if cc jump .Lbusy_spinlock
303 #ifdef __ARCH_SYNC_CORE_DCACHE
305 bitset ( r2, 0 ); /* Raise the lock bit. */
307 call _start_lock_coherent
317 /* We don't touch the atomic area if busy, so that flush
318 will behave like nop in _put_core_lock. */
322 jump .Lretry_spinlock
323 ENDPROC(___raw_spin_lock_asm)
326 * r0 = &spinlock->lock
328 * Clobbers: r3:0, p1:0
330 ENTRY(___raw_spin_trylock_asm)
336 cc = bittst( r3, 0 );
337 if cc jump .Lfailed_trylock
338 #ifdef __ARCH_SYNC_CORE_DCACHE
339 bitset ( r3, 0 ); /* Raise the lock bit. */
341 call _start_lock_coherent
355 ENDPROC(___raw_spin_trylock_asm)
358 * r0 = &spinlock->lock
360 * Clobbers: r2:0, p1:0
362 ENTRY(___raw_spin_unlock_asm)
370 #ifdef __ARCH_SYNC_CORE_DCACHE
371 call _end_lock_coherent
377 ENDPROC(___raw_spin_unlock_asm)
382 * Clobbers: r2:0, p1:0
384 ENTRY(___raw_read_lock_asm)
393 if cc jump .Lrdlock_failed
395 #ifdef __ARCH_SYNC_CORE_DCACHE
396 call _start_lock_coherent
414 if cc jump .Lrdlock_wait;
416 ENDPROC(___raw_read_lock_asm)
421 * Clobbers: r3:0, p1:0
423 ENTRY(___raw_read_trylock_asm)
429 if cc jump .Lfailed_tryrdlock;
433 #ifdef __ARCH_SYNC_CORE_DCACHE
434 call _start_lock_coherent
447 ENDPROC(___raw_read_trylock_asm)
452 * Note: Processing controlled by a reader lock should not have
453 * any side-effect on cache issues with the other core, so we
454 * just release the core lock and exit (no _end_lock_coherent).
456 * Clobbers: r3:0, p1:0
458 ENTRY(___raw_read_unlock_asm)
469 ENDPROC(___raw_read_unlock_asm)
474 * Clobbers: r3:0, p1:0
476 ENTRY(___raw_write_lock_asm)
478 r3.l = lo(RW_LOCK_BIAS);
479 r3.h = hi(RW_LOCK_BIAS);
485 #ifdef __ARCH_SYNC_CORE_DCACHE
493 if !cc jump .Lwrlock_wait
496 #ifdef __ARCH_SYNC_CORE_DCACHE
497 call _start_lock_coherent
511 #ifdef __ARCH_SYNC_CORE_DCACHE
516 if !cc jump .Lwrlock_wait;
518 ENDPROC(___raw_write_lock_asm)
523 * Clobbers: r3:0, p1:0
525 ENTRY(___raw_write_trylock_asm)
530 r2.l = lo(RW_LOCK_BIAS);
531 r2.h = hi(RW_LOCK_BIAS);
533 if !cc jump .Lfailed_trywrlock;
534 #ifdef __ARCH_SYNC_CORE_DCACHE
542 #ifdef __ARCH_SYNC_CORE_DCACHE
543 call _start_lock_coherent
557 ENDPROC(___raw_write_trylock_asm)
562 * Clobbers: r3:0, p1:0
564 ENTRY(___raw_write_unlock_asm)
566 r3.l = lo(RW_LOCK_BIAS);
567 r3.h = hi(RW_LOCK_BIAS);
574 #ifdef __ARCH_SYNC_CORE_DCACHE
575 call _end_lock_coherent
581 ENDPROC(___raw_write_unlock_asm)
587 * Add a signed value to a 32bit word and return the new value atomically.
588 * Clobbers: r3:0, p1:0
590 ENTRY(___raw_atomic_update_asm)
603 ENDPROC(___raw_atomic_update_asm)
609 * Clear the mask bits from a 32bit word and return the old 32bit value
611 * Clobbers: r3:0, p1:0
613 ENTRY(___raw_atomic_clear_asm)
627 ENDPROC(___raw_atomic_clear_asm)
633 * Set the mask bits into a 32bit word and return the old 32bit value
635 * Clobbers: r3:0, p1:0
637 ENTRY(___raw_atomic_set_asm)
651 ENDPROC(___raw_atomic_set_asm)
657 * XOR the mask bits with a 32bit word and return the old 32bit value
659 * Clobbers: r3:0, p1:0
661 ENTRY(___raw_atomic_xor_asm)
675 ENDPROC(___raw_atomic_xor_asm)
681 * Perform a logical AND between the mask bits and a 32bit word, and
682 * return the masked value. We need this on this architecture in
683 * order to invalidate the local cache before testing.
685 * Clobbers: r3:0, p1:0
687 ENTRY(___raw_atomic_test_asm)
690 r1 = -L1_CACHE_BYTES;
698 ENDPROC(___raw_atomic_test_asm)
704 * Swap *ptr with value and return the old 32bit value atomically.
705 * Clobbers: r3:0, p1:0
707 #define __do_xchg(src, dst) \
711 call _get_core_lock; \
716 call _put_core_lock; \
721 ENTRY(___raw_xchg_1_asm)
722 __do_xchg(b[p1] (z), b[p1])
723 ENDPROC(___raw_xchg_1_asm)
725 ENTRY(___raw_xchg_2_asm)
726 __do_xchg(w[p1] (z), w[p1])
727 ENDPROC(___raw_xchg_2_asm)
729 ENTRY(___raw_xchg_4_asm)
730 __do_xchg([p1], [p1])
731 ENDPROC(___raw_xchg_4_asm)
738 * Swap *ptr with new if *ptr == old and return the previous *ptr
741 * Clobbers: r3:0, p1:0
743 #define __do_cmpxchg(src, dst) \
749 call _get_core_lock; \
756 call _put_core_lock; \
762 ENTRY(___raw_cmpxchg_1_asm)
763 __do_cmpxchg(b[p1] (z), b[p1])
764 ENDPROC(___raw_cmpxchg_1_asm)
766 ENTRY(___raw_cmpxchg_2_asm)
767 __do_cmpxchg(w[p1] (z), w[p1])
768 ENDPROC(___raw_cmpxchg_2_asm)
770 ENTRY(___raw_cmpxchg_4_asm)
771 __do_cmpxchg([p1], [p1])
772 ENDPROC(___raw_cmpxchg_4_asm)
778 * Set a bit in a 32bit word and return the old 32bit value atomically.
779 * Clobbers: r3:0, p1:0
781 ENTRY(___raw_bit_set_asm)
785 jump ___raw_atomic_set_asm
786 ENDPROC(___raw_bit_set_asm)
792 * Clear a bit in a 32bit word and return the old 32bit value atomically.
793 * Clobbers: r3:0, p1:0
795 ENTRY(___raw_bit_clear_asm)
799 jump ___raw_atomic_clear_asm
800 ENDPROC(___raw_bit_clear_asm)
806 * Toggle a bit in a 32bit word and return the old 32bit value atomically.
807 * Clobbers: r3:0, p1:0
809 ENTRY(___raw_bit_toggle_asm)
813 jump ___raw_atomic_xor_asm
814 ENDPROC(___raw_bit_toggle_asm)
820 * Test-and-set a bit in a 32bit word and return the old bit value atomically.
821 * Clobbers: r3:0, p1:0
823 ENTRY(___raw_bit_test_set_asm)
826 call ___raw_bit_set_asm
837 ENDPROC(___raw_bit_test_set_asm)
843 * Test-and-clear a bit in a 32bit word and return the old bit value atomically.
844 * Clobbers: r3:0, p1:0
846 ENTRY(___raw_bit_test_clear_asm)
849 call ___raw_bit_clear_asm
860 ENDPROC(___raw_bit_test_clear_asm)
866 * Test-and-toggle a bit in a 32bit word,
867 * and return the old bit value atomically.
868 * Clobbers: r3:0, p1:0
870 ENTRY(___raw_bit_test_toggle_asm)
873 call ___raw_bit_toggle_asm
884 ENDPROC(___raw_bit_test_toggle_asm)
890 * Test a bit in a 32bit word and return its value.
891 * We need this on this architecture in order to invalidate
892 * the local cache before testing.
894 * Clobbers: r3:0, p1:0
896 ENTRY(___raw_bit_test_asm)
900 jump ___raw_atomic_test_asm
901 ENDPROC(___raw_bit_test_asm)
906 * Fetch and return an uncached 32bit value.
908 * Clobbers: r2:0, p1:0
910 ENTRY(___raw_uncached_fetch_asm)
912 r1 = -L1_CACHE_BYTES;
919 ENDPROC(___raw_uncached_fetch_asm)