162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/lib/copypage-xscale.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995-2005 Russell King 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This handles the mini data cache, as found on SA11x0 and XScale 862306a36Sopenharmony_ci * processors. When we copy a user page page, we map it in such a way 962306a36Sopenharmony_ci * that accesses to this page will not touch the main data cache, but 1062306a36Sopenharmony_ci * will be cached in the mini data cache. This prevents us thrashing 1162306a36Sopenharmony_ci * the main data cache on page faults. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/mm.h> 1562306a36Sopenharmony_ci#include <linux/highmem.h> 1662306a36Sopenharmony_ci#include <linux/pagemap.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/tlbflush.h> 1962306a36Sopenharmony_ci#include <asm/cacheflush.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "mm.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ 2462306a36Sopenharmony_ci L_PTE_MT_MINICACHE) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(minicache_lock); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * XScale mini-dcache optimised copy_user_highpage 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * We flush the destination cache lines just before we write the data into the 3262306a36Sopenharmony_ci * corresponding address. Since the Dcache is read-allocate, this removes the 3362306a36Sopenharmony_ci * Dcache aliasing issue. The writes will be forwarded to the write buffer, 3462306a36Sopenharmony_ci * and merged as appropriate. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic void mc_copy_user_page(void *from, void *to) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int tmp; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * Strangely enough, best performance is achieved 4262306a36Sopenharmony_ci * when prefetching destination as well. (NP) 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci asm volatile ("\ 4562306a36Sopenharmony_ci.arch xscale \n\ 4662306a36Sopenharmony_ci pld [%0, #0] \n\ 4762306a36Sopenharmony_ci pld [%0, #32] \n\ 4862306a36Sopenharmony_ci pld [%1, #0] \n\ 4962306a36Sopenharmony_ci pld [%1, #32] \n\ 5062306a36Sopenharmony_ci1: pld [%0, #64] \n\ 5162306a36Sopenharmony_ci pld [%0, #96] \n\ 5262306a36Sopenharmony_ci pld [%1, #64] \n\ 5362306a36Sopenharmony_ci pld [%1, #96] \n\ 5462306a36Sopenharmony_ci2: ldrd r2, r3, [%0], #8 \n\ 5562306a36Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 5662306a36Sopenharmony_ci mov ip, %1 \n\ 5762306a36Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 5862306a36Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 5962306a36Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 6062306a36Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 6162306a36Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 6262306a36Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 6362306a36Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 6462306a36Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 6562306a36Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 6662306a36Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 6762306a36Sopenharmony_ci mov ip, %1 \n\ 6862306a36Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 6962306a36Sopenharmony_ci ldrd r2, r3, [%0], #8 \n\ 7062306a36Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 7162306a36Sopenharmony_ci ldrd r4, r5, [%0], #8 \n\ 7262306a36Sopenharmony_ci strd r2, r3, [%1], #8 \n\ 7362306a36Sopenharmony_ci strd r4, r5, [%1], #8 \n\ 7462306a36Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 7562306a36Sopenharmony_ci subs %2, %2, #1 \n\ 7662306a36Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 7762306a36Sopenharmony_ci bgt 1b \n\ 7862306a36Sopenharmony_ci beq 2b " 7962306a36Sopenharmony_ci : "+&r" (from), "+&r" (to), "=&r" (tmp) 8062306a36Sopenharmony_ci : "2" (PAGE_SIZE / 64 - 1) 8162306a36Sopenharmony_ci : "r2", "r3", "r4", "r5", "ip"); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_civoid xscale_mc_copy_user_highpage(struct page *to, struct page *from, 8562306a36Sopenharmony_ci unsigned long vaddr, struct vm_area_struct *vma) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct folio *src = page_folio(from); 8862306a36Sopenharmony_ci void *kto = kmap_atomic(to); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!test_and_set_bit(PG_dcache_clean, &src->flags)) 9162306a36Sopenharmony_ci __flush_dcache_folio(folio_flush_mapping(src), src); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci raw_spin_lock(&minicache_lock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot)); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci raw_spin_unlock(&minicache_lock); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci kunmap_atomic(kto); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * XScale optimised clear_user_page 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_civoid 10862306a36Sopenharmony_cixscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci void *ptr, *kaddr = kmap_atomic(page); 11162306a36Sopenharmony_ci asm volatile("\ 11262306a36Sopenharmony_ci.arch xscale \n\ 11362306a36Sopenharmony_ci mov r1, %2 \n\ 11462306a36Sopenharmony_ci mov r2, #0 \n\ 11562306a36Sopenharmony_ci mov r3, #0 \n\ 11662306a36Sopenharmony_ci1: mov ip, %0 \n\ 11762306a36Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 11862306a36Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 11962306a36Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 12062306a36Sopenharmony_ci strd r2, r3, [%0], #8 \n\ 12162306a36Sopenharmony_ci mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ 12262306a36Sopenharmony_ci subs r1, r1, #1 \n\ 12362306a36Sopenharmony_ci mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ 12462306a36Sopenharmony_ci bne 1b" 12562306a36Sopenharmony_ci : "=r" (ptr) 12662306a36Sopenharmony_ci : "0" (kaddr), "I" (PAGE_SIZE / 32) 12762306a36Sopenharmony_ci : "r1", "r2", "r3", "ip"); 12862306a36Sopenharmony_ci kunmap_atomic(kaddr); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct cpu_user_fns xscale_mc_user_fns __initdata = { 13262306a36Sopenharmony_ci .cpu_clear_user_highpage = xscale_mc_clear_user_highpage, 13362306a36Sopenharmony_ci .cpu_copy_user_highpage = xscale_mc_copy_user_highpage, 13462306a36Sopenharmony_ci}; 135