18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/lib/copypage-xscale.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995-2005 Russell King 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This handles the mini data cache, as found on SA11x0 and XScale 88c2ecf20Sopenharmony_ci * processors. When we copy a user page page, we map it in such a way 98c2ecf20Sopenharmony_ci * that accesses to this page will not touch the main data cache, but 108c2ecf20Sopenharmony_ci * will be cached in the mini data cache. This prevents us thrashing 118c2ecf20Sopenharmony_ci * the main data cache on page faults. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/highmem.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 188c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mm.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ 238c2ecf20Sopenharmony_ci L_PTE_MT_MINICACHE) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(minicache_lock); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * XScale mini-dcache optimised copy_user_highpage 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * We flush the destination cache lines just before we write the data into the 318c2ecf20Sopenharmony_ci * corresponding address. Since the Dcache is read-allocate, this removes the 328c2ecf20Sopenharmony_ci * Dcache aliasing issue. The writes will be forwarded to the write buffer, 338c2ecf20Sopenharmony_ci * and merged as appropriate. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic void mc_copy_user_page(void *from, void *to) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int tmp; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Strangely enough, best performance is achieved 418c2ecf20Sopenharmony_ci * when prefetching destination as well. (NP) 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci asm volatile ("\ 448c2ecf20Sopenharmony_ci.arch xscale \n\ 458c2ecf20Sopenharmony_ci pld [%0, #0] \n\ 468c2ecf20Sopenharmony_ci pld [%0, #32] \n\ 478c2ecf20Sopenharmony_ci pld [%1, #0] \n\ 488c2ecf20Sopenharmony_ci pld [%1, #32] \n\ 498c2ecf20Sopenharmony_ci1: pld [%0, #64] \n\ 508c2ecf20Sopenharmony_ci pld [%0, #96] \n\ 518c2ecf20Sopenharmony_ci pld [%1, #64] \n\ 528c2ecf20Sopenharmony_ci pld [%1, #96] \n\ 538c2ecf20Sopenharmony_ci2: ldrd r2, r3, [%0], #8 \n\ 548c2ecf20Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 558c2ecf20Sopenharmony_ci mov ip, %1 \n\ 568c2ecf20Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 578c2ecf20Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 588c2ecf20Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 598c2ecf20Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 608c2ecf20Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 618c2ecf20Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 628c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 638c2ecf20Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 648c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 658c2ecf20Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 668c2ecf20Sopenharmony_ci mov ip, %1 \n\ 678c2ecf20Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 688c2ecf20Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 698c2ecf20Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 708c2ecf20Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 718c2ecf20Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 728c2ecf20Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 738c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 748c2ecf20Sopenharmony_ci subs %2, %2, #1 \n\ 758c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 768c2ecf20Sopenharmony_ci bgt 1b \n\ 778c2ecf20Sopenharmony_ci beq 2b " 788c2ecf20Sopenharmony_ci : "+&r" (from), "+&r" (to), "=&r" (tmp) 798c2ecf20Sopenharmony_ci : "2" (PAGE_SIZE / 64 - 1) 808c2ecf20Sopenharmony_ci : "r2", "r3", "r4", "r5", "ip"); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid xscale_mc_copy_user_highpage(struct page *to, struct page *from, 848c2ecf20Sopenharmony_ci unsigned long vaddr, struct vm_area_struct *vma) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci void *kto = kmap_atomic(to); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!test_and_set_bit(PG_dcache_clean, &from->flags)) 898c2ecf20Sopenharmony_ci __flush_dcache_page(page_mapping_file(from), from); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci raw_spin_lock(&minicache_lock); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot)); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci raw_spin_unlock(&minicache_lock); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci kunmap_atomic(kto); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * XScale optimised clear_user_page 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_civoid 1068c2ecf20Sopenharmony_cixscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci void *ptr, *kaddr = kmap_atomic(page); 1098c2ecf20Sopenharmony_ci asm volatile("\ 1108c2ecf20Sopenharmony_ci.arch xscale \n\ 1118c2ecf20Sopenharmony_ci mov r1, %2 \n\ 1128c2ecf20Sopenharmony_ci mov r2, #0 \n\ 1138c2ecf20Sopenharmony_ci mov r3, #0 \n\ 1148c2ecf20Sopenharmony_ci1: mov ip, %0 \n\ 1158c2ecf20Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 1168c2ecf20Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 1178c2ecf20Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 1188c2ecf20Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 1198c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 1208c2ecf20Sopenharmony_ci subs r1, r1, #1 \n\ 1218c2ecf20Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 1228c2ecf20Sopenharmony_ci bne 1b" 1238c2ecf20Sopenharmony_ci : "=r" (ptr) 1248c2ecf20Sopenharmony_ci : "0" (kaddr), "I" (PAGE_SIZE / 32) 1258c2ecf20Sopenharmony_ci : "r1", "r2", "r3", "ip"); 1268c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct cpu_user_fns xscale_mc_user_fns __initdata = { 1308c2ecf20Sopenharmony_ci .cpu_clear_user_highpage = xscale_mc_clear_user_highpage, 1318c2ecf20Sopenharmony_ci .cpu_copy_user_highpage = xscale_mc_copy_user_highpage, 1328c2ecf20Sopenharmony_ci}; 133