diff options
Diffstat (limited to 'arch/xtensa/mm/misc.S')
| -rw-r--r-- | arch/xtensa/mm/misc.S | 556 |
1 files changed, 339 insertions, 217 deletions
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S index 327c0f17187..1f68558dbcc 100644 --- a/arch/xtensa/mm/misc.S +++ b/arch/xtensa/mm/misc.S @@ -7,30 +7,34 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. * * Chris Zankel <chris@zankel.net> */ -/* Note: we might want to implement some of the loops as zero-overhead-loops, - * where applicable and if supported by the processor. - */ #include <linux/linkage.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/asmmacro.h> +#include <asm/cacheasm.h> +#include <asm/tlbflush.h> -#include <xtensa/cacheasm.h> -#include <xtensa/cacheattrasm.h> -/* clear_page (page) */ +/* + * clear_page and clear_user_page are the same for non-cache-aliased configs. + * + * clear_page (unsigned long page) + * a2 + */ ENTRY(clear_page) + entry a1, 16 - addi a4, a2, PAGE_SIZE - movi a3, 0 -1: s32i a3, a2, 0 + movi a3, 0 + __loopi a2, a7, PAGE_SIZE, 32 + s32i a3, a2, 0 s32i a3, a2, 4 s32i a3, a2, 8 s32i a3, a2, 12 @@ -38,337 +42,455 @@ ENTRY(clear_page) s32i a3, a2, 20 s32i a3, a2, 24 s32i a3, a2, 28 - addi a2, a2, 32 - blt a2, a4, 1b + __endla a2, a7, 32 retw +ENDPROC(clear_page) + /* + * copy_page and copy_user_page are the same for non-cache-aliased configs. + * * copy_page (void *to, void *from) - * a2 a3 + * a2 a3 */ ENTRY(copy_page) + entry a1, 16 - addi a4, a2, PAGE_SIZE - -1: l32i a5, a3, 0 - l32i a6, a3, 4 - l32i a7, a3, 8 - s32i a5, a2, 0 - s32i a6, a2, 4 - s32i a7, a2, 8 - l32i a5, a3, 12 - l32i a6, a3, 16 - l32i a7, a3, 20 - s32i a5, a2, 12 - s32i a6, a2, 16 - s32i a7, a2, 20 - l32i a5, a3, 24 - l32i a6, a3, 28 - s32i a5, a2, 24 - s32i a6, a2, 28 - addi a2, a2, 32 - addi a3, a3, 32 - blt a2, a4, 1b - retw + __loopi a2, a4, PAGE_SIZE, 32 + l32i a8, a3, 0 + l32i a9, a3, 4 + s32i a8, a2, 0 + s32i a9, a2, 4 -/* - * void __flush_invalidate_cache_all(void) - */ + l32i a8, a3, 8 + l32i a9, a3, 12 + s32i a8, a2, 8 + s32i a9, a2, 12 -ENTRY(__flush_invalidate_cache_all) - entry sp, 16 - dcache_writeback_inv_all a2, a3 - icache_invalidate_all a2, a3 - retw + l32i a8, a3, 16 + l32i a9, a3, 20 + s32i a8, a2, 16 + s32i a9, a2, 20 -/* - * void __invalidate_icache_all(void) - */ + l32i a8, a3, 24 + l32i a9, a3, 28 + s32i a8, a2, 24 + s32i a9, a2, 28 -ENTRY(__invalidate_icache_all) - entry sp, 16 - icache_invalidate_all a2, a3 - retw + addi a2, a2, 32 + addi a3, a3, 32 -/* - * void __flush_invalidate_dcache_all(void) - */ + __endl a2, a4 -ENTRY(__flush_invalidate_dcache_all) - entry sp, 16 - dcache_writeback_inv_all a2, a3 retw +ENDPROC(copy_page) +#ifdef CONFIG_MMU /* - * void __flush_invalidate_cache_range(ulong start, ulong size) + * If we have to deal with cache aliasing, we use temporary memory mappings + * to ensure that the source and destination pages have the same color as + * the virtual address. We use way 0 and 1 for temporary mappings in such cases. + * + * The temporary DTLB entries shouldn't be flushed by interrupts, but are + * flushed by preemptive task switches. Special code in the + * fast_second_level_miss handler re-established the temporary mapping. + * It requires that the PPNs for the destination and source addresses are + * in a6, and a7, respectively. */ -ENTRY(__flush_invalidate_cache_range) - entry sp, 16 - mov a4, a2 - mov a5, a3 - dcache_writeback_inv_region a4, a5, a6 - icache_invalidate_region a2, a3, a4 - retw +/* TLB miss exceptions are treated special in the following region */ + +ENTRY(__tlbtemp_mapping_start) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) /* - * void __invalidate_icache_page(ulong start) + * clear_user_page (void *addr, unsigned long vaddr, struct page *page) + * a2 a3 a4 */ -ENTRY(__invalidate_icache_page) - entry sp, 16 - movi a3, PAGE_SIZE - icache_invalidate_region a2, a3, a4 +ENTRY(clear_user_page) + + entry a1, 32 + + /* Mark page dirty and determine alias. */ + + movi a7, (1 << PG_ARCH_1) + l32i a5, a4, PAGE_FLAGS + xor a6, a2, a3 + extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER + or a5, a5, a7 + slli a3, a3, PAGE_SHIFT + s32i a5, a4, PAGE_FLAGS + + /* Skip setting up a temporary DTLB if not aliased. */ + + beqz a6, 1f + + /* Invalidate kernel page. */ + + mov a10, a2 + call8 __invalidate_dcache_page + + /* Setup a temporary DTLB with the color of the VPN */ + + movi a4, ((PAGE_KERNEL | _PAGE_HW_WRITE) - PAGE_OFFSET) & 0xffffffff + movi a5, TLBTEMP_BASE_1 # virt + add a6, a2, a4 # ppn + add a2, a5, a3 # add 'color' + + wdtlb a6, a2 + dsync + +1: movi a3, 0 + __loopi a2, a7, PAGE_SIZE, 32 + s32i a3, a2, 0 + s32i a3, a2, 4 + s32i a3, a2, 8 + s32i a3, a2, 12 + s32i a3, a2, 16 + s32i a3, a2, 20 + s32i a3, a2, 24 + s32i a3, a2, 28 + __endla a2, a7, 32 + + bnez a6, 1f retw -/* - * void __invalidate_dcache_page(ulong start) - */ + /* We need to invalidate the temporary idtlb entry, if any. */ + +1: addi a2, a2, -PAGE_SIZE + idtlb a2 + dsync -ENTRY(__invalidate_dcache_page) - entry sp, 16 - movi a3, PAGE_SIZE - dcache_invalidate_region a2, a3, a4 retw +ENDPROC(clear_user_page) + /* - * void __invalidate_icache_range(ulong start, ulong size) + * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page) + * a2 a3 a4 a5 */ -ENTRY(__invalidate_icache_range) - entry sp, 16 - icache_invalidate_region a2, a3, a4 +ENTRY(copy_user_page) + + entry a1, 32 + + /* Mark page dirty and determine alias for destination. */ + + movi a8, (1 << PG_ARCH_1) + l32i a9, a5, PAGE_FLAGS + xor a6, a2, a4 + xor a7, a3, a4 + extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER + extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER + or a9, a9, a8 + slli a4, a4, PAGE_SHIFT + s32i a9, a5, PAGE_FLAGS + movi a5, ((PAGE_KERNEL | _PAGE_HW_WRITE) - PAGE_OFFSET) & 0xffffffff + + beqz a6, 1f + + /* Invalidate dcache */ + + mov a10, a2 + call8 __invalidate_dcache_page + + /* Setup a temporary DTLB with a matching color. */ + + movi a8, TLBTEMP_BASE_1 # base + add a6, a2, a5 # ppn + add a2, a8, a4 # add 'color' + + wdtlb a6, a2 + dsync + + /* Skip setting up a temporary DTLB for destination if not aliased. */ + +1: beqz a7, 1f + + /* Setup a temporary DTLB with a matching color. */ + + movi a8, TLBTEMP_BASE_2 # base + add a7, a3, a5 # ppn + add a3, a8, a4 + addi a8, a3, 1 # way1 + + wdtlb a7, a8 + dsync + +1: __loopi a2, a4, PAGE_SIZE, 32 + + l32i a8, a3, 0 + l32i a9, a3, 4 + s32i a8, a2, 0 + s32i a9, a2, 4 + + l32i a8, a3, 8 + l32i a9, a3, 12 + s32i a8, a2, 8 + s32i a9, a2, 12 + + l32i a8, a3, 16 + l32i a9, a3, 20 + s32i a8, a2, 16 + s32i a9, a2, 20 + + l32i a8, a3, 24 + l32i a9, a3, 28 + s32i a8, a2, 24 + s32i a9, a2, 28 + + addi a2, a2, 32 + addi a3, a3, 32 + + __endl a2, a4 + + /* We need to invalidate any temporary mapping! */ + + bnez a6, 1f + bnez a7, 2f retw -/* - * void __invalidate_dcache_range(ulong start, ulong size) - */ +1: addi a2, a2, -PAGE_SIZE + idtlb a2 + dsync + bnez a7, 2f + retw + +2: addi a3, a3, -PAGE_SIZE+1 + idtlb a3 + dsync -ENTRY(__invalidate_dcache_range) - entry sp, 16 - dcache_invalidate_region a2, a3, a4 retw +ENDPROC(copy_user_page) + +#endif + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) + /* - * void __flush_dcache_page(ulong start) + * void __flush_invalidate_dcache_page_alias (addr, phys) + * a2 a3 */ -ENTRY(__flush_dcache_page) +ENTRY(__flush_invalidate_dcache_page_alias) + entry sp, 16 - movi a3, PAGE_SIZE - dcache_writeback_region a2, a3, a4 + + movi a7, 0 # required for exception handler + addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE) + mov a4, a2 + wdtlb a6, a2 + dsync + + ___flush_invalidate_dcache_page a2 a3 + + idtlb a4 + dsync + retw -/* - * void __flush_invalidate_dcache_page(ulong start) - */ +ENDPROC(__flush_invalidate_dcache_page_alias) +#endif + +ENTRY(__tlbtemp_mapping_itlb) + +#if (ICACHE_WAY_SIZE > PAGE_SIZE) + +ENTRY(__invalidate_icache_page_alias) -ENTRY(__flush_invalidate_dcache_page) entry sp, 16 - movi a3, PAGE_SIZE - dcache_writeback_inv_region a2, a3, a4 + + addi a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE) + mov a4, a2 + witlb a6, a2 + isync + + ___invalidate_icache_page a2 a3 + + iitlb a4 + isync retw +ENDPROC(__invalidate_icache_page_alias) + +#endif + +/* End of special treatment in tlb miss exception */ + +ENTRY(__tlbtemp_mapping_end) + +#endif /* CONFIG_MMU + /* - * void __flush_invalidate_dcache_range(ulong start, ulong size) + * void __invalidate_icache_page(ulong start) */ -ENTRY(__flush_invalidate_dcache_range) +ENTRY(__invalidate_icache_page) + entry sp, 16 - dcache_writeback_inv_region a2, a3, a4 + + ___invalidate_icache_page a2 a3 + isync + retw +ENDPROC(__invalidate_icache_page) + /* - * void __invalidate_dcache_all(void) + * void __invalidate_dcache_page(ulong start) */ -ENTRY(__invalidate_dcache_all) +ENTRY(__invalidate_dcache_page) + entry sp, 16 - dcache_invalidate_all a2, a3 + + ___invalidate_dcache_page a2 a3 + dsync + retw +ENDPROC(__invalidate_dcache_page) + /* - * void __flush_invalidate_dcache_page_phys(ulong start) + * void __flush_invalidate_dcache_page(ulong start) */ -ENTRY(__flush_invalidate_dcache_page_phys) - entry sp, 16 +ENTRY(__flush_invalidate_dcache_page) - movi a3, XCHAL_DCACHE_SIZE - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 + entry sp, 16 -1: addi a3, a3, -XCHAL_DCACHE_LINESIZE + ___flush_invalidate_dcache_page a2 a3 - ldct a6, a3 dsync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a3, 2, 1b retw -2: diwbi a3, 0 - bgeui a3, 2, 1b - retw +ENDPROC(__flush_invalidate_dcache_page) -ENTRY(check_dcache_low0) - entry sp, 16 +/* + * void __flush_dcache_page(ulong start) + */ - movi a3, XCHAL_DCACHE_SIZE / 4 - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 +ENTRY(__flush_dcache_page) + + entry sp, 16 -1: addi a3, a3, -XCHAL_DCACHE_LINESIZE + ___flush_dcache_page a2 a3 - ldct a6, a3 dsync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a3, 2, 1b retw -2: j 2b +ENDPROC(__flush_dcache_page) -ENTRY(check_dcache_high0) - entry sp, 16 +/* + * void __invalidate_icache_range(ulong start, ulong size) + */ - movi a5, XCHAL_DCACHE_SIZE / 4 - movi a3, XCHAL_DCACHE_SIZE / 2 - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 +ENTRY(__invalidate_icache_range) -1: addi a3, a3, -XCHAL_DCACHE_LINESIZE - addi a5, a5, -XCHAL_DCACHE_LINESIZE + entry sp, 16 + + ___invalidate_icache_range a2 a3 a4 + isync - ldct a6, a3 - dsync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a5, 2, 1b retw -2: j 2b +ENDPROC(__invalidate_icache_range) -ENTRY(check_dcache_low1) - entry sp, 16 +/* + * void __flush_invalidate_dcache_range(ulong start, ulong size) + */ - movi a5, XCHAL_DCACHE_SIZE / 4 - movi a3, XCHAL_DCACHE_SIZE * 3 / 4 - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 +ENTRY(__flush_invalidate_dcache_range) -1: addi a3, a3, -XCHAL_DCACHE_LINESIZE - addi a5, a5, -XCHAL_DCACHE_LINESIZE + entry sp, 16 - ldct a6, a3 + ___flush_invalidate_dcache_range a2 a3 a4 dsync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a5, 2, 1b + retw -2: j 2b +ENDPROC(__flush_invalidate_dcache_range) -ENTRY(check_dcache_high1) - entry sp, 16 +/* + * void _flush_dcache_range(ulong start, ulong size) + */ - movi a5, XCHAL_DCACHE_SIZE / 4 - movi a3, XCHAL_DCACHE_SIZE - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 +ENTRY(__flush_dcache_range) -1: addi a3, a3, -XCHAL_DCACHE_LINESIZE - addi a5, a5, -XCHAL_DCACHE_LINESIZE + entry sp, 16 - ldct a6, a3 + ___flush_dcache_range a2 a3 a4 dsync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a5, 2, 1b - retw -2: j 2b + retw +ENDPROC(__flush_dcache_range) /* - * void __invalidate_icache_page_phys(ulong start) + * void _invalidate_dcache_range(ulong start, ulong size) */ -ENTRY(__invalidate_icache_page_phys) - entry sp, 16 - - movi a3, XCHAL_ICACHE_SIZE - movi a4, PAGE_MASK | 1 - addi a2, a2, 1 +ENTRY(__invalidate_dcache_range) -1: addi a3, a3, -XCHAL_ICACHE_LINESIZE + entry sp, 16 - lict a6, a3 - isync - and a6, a6, a4 - beq a6, a2, 2f - bgeui a3, 2, 1b - retw + ___invalidate_dcache_range a2 a3 a4 -2: iii a3, 0 - bgeui a3, 2, 1b retw +ENDPROC(__invalidate_dcache_range) -#if 0 - - movi a3, XCHAL_DCACHE_WAYS - 1 - movi a4, PAGE_SIZE - -1: mov a5, a2 - add a6, a2, a4 +/* + * void _invalidate_icache_all(void) + */ -2: diwbi a5, 0 - diwbi a5, XCHAL_DCACHE_LINESIZE - diwbi a5, XCHAL_DCACHE_LINESIZE * 2 - diwbi a5, XCHAL_DCACHE_LINESIZE * 3 +ENTRY(__invalidate_icache_all) - addi a5, a5, XCHAL_DCACHE_LINESIZE * 4 - blt a5, a6, 2b + entry sp, 16 - addi a3, a3, -1 - addi a2, a2, XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS - bgez a3, 1b + ___invalidate_icache_all a2 a3 + isync retw -ENTRY(__invalidate_icache_page_index) - entry sp, 16 - - movi a3, XCHAL_ICACHE_WAYS - 1 - movi a4, PAGE_SIZE +ENDPROC(__invalidate_icache_all) -1: mov a5, a2 - add a6, a2, a4 +/* + * void _flush_invalidate_dcache_all(void) + */ -2: iii a5, 0 - iii a5, XCHAL_ICACHE_LINESIZE - iii a5, XCHAL_ICACHE_LINESIZE * 2 - iii a5, XCHAL_ICACHE_LINESIZE * 3 +ENTRY(__flush_invalidate_dcache_all) - addi a5, a5, XCHAL_ICACHE_LINESIZE * 4 - blt a5, a6, 2b + entry sp, 16 - addi a3, a3, -1 - addi a2, a2, XCHAL_ICACHE_SIZE / XCHAL_ICACHE_WAYS - bgez a3, 2b + ___flush_invalidate_dcache_all a2 a3 + dsync retw -#endif +ENDPROC(__flush_invalidate_dcache_all) +/* + * void _invalidate_dcache_all(void) + */ +ENTRY(__invalidate_dcache_all) + entry sp, 16 + ___invalidate_dcache_all a2 a3 + dsync + retw +ENDPROC(__invalidate_dcache_all) |
