^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/lib/copypage-xscale.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1995-2005 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This handles the mini data cache, as found on SA11x0 and XScale
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * processors. When we copy a user page page, we map it in such a way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * that accesses to this page will not touch the main data cache, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * will be cached in the mini data cache. This prevents us thrashing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * the main data cache on page faults.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/highmem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "mm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) L_PTE_MT_MINICACHE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static DEFINE_RAW_SPINLOCK(minicache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * XScale mini-dcache optimised copy_user_highpage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * We flush the destination cache lines just before we write the data into the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * corresponding address. Since the Dcache is read-allocate, this removes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Dcache aliasing issue. The writes will be forwarded to the write buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * and merged as appropriate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static void mc_copy_user_page(void *from, void *to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * Strangely enough, best performance is achieved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * when prefetching destination as well. (NP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) asm volatile ("\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .arch xscale \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) pld [%0, #0] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pld [%0, #32] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) pld [%1, #0] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) pld [%1, #32] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) 1: pld [%0, #64] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) pld [%0, #96] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) pld [%1, #64] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) pld [%1, #96] \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) 2: ldrd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ldrd r4, r5, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) mov ip, %1 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) strd r2, r3, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ldrd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) strd r4, r5, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ldrd r4, r5, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) strd r2, r3, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) strd r4, r5, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) ldrd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ldrd r4, r5, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) mov ip, %1 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) strd r2, r3, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ldrd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) strd r4, r5, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ldrd r4, r5, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) strd r2, r3, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) strd r4, r5, [%1], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) subs %2, %2, #1 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bgt 1b \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) beq 2b "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) : "+&r" (from), "+&r" (to), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) : "2" (PAGE_SIZE / 64 - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) : "r2", "r3", "r4", "r5", "ip");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned long vaddr, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) void *kto = kmap_atomic(to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!test_and_set_bit(PG_dcache_clean, &from->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) __flush_dcache_page(page_mapping_file(from), from);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) raw_spin_lock(&minicache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) raw_spin_unlock(&minicache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) kunmap_atomic(kto);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * XScale optimised clear_user_page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) void *ptr, *kaddr = kmap_atomic(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) asm volatile("\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .arch xscale \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) mov r1, %2 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mov r2, #0 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) mov r3, #0 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 1: mov ip, %0 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) strd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) strd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) strd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) strd r2, r3, [%0], #8 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) subs r1, r1, #1 \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) bne 1b"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) : "=r" (ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) : "0" (kaddr), "I" (PAGE_SIZE / 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) : "r1", "r2", "r3", "ip");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) kunmap_atomic(kaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct cpu_user_fns xscale_mc_user_fns __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .cpu_clear_user_highpage = xscale_mc_clear_user_highpage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .cpu_copy_user_highpage = xscale_mc_copy_user_highpage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };