xref: /openbmc/linux/arch/arm/mm/copypage-v6.c (revision 1b2e2b73b4c84c918686c04a00724197036c0847)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/arm/mm/copypage-v6.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds  * it under the terms of the GNU General Public License version 2 as
81da177e4SLinus Torvalds  * published by the Free Software Foundation.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/spinlock.h>
121da177e4SLinus Torvalds #include <linux/mm.h>
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <asm/page.h>
151da177e4SLinus Torvalds #include <asm/pgtable.h>
161da177e4SLinus Torvalds #include <asm/shmparam.h>
171da177e4SLinus Torvalds #include <asm/tlbflush.h>
181da177e4SLinus Torvalds #include <asm/cacheflush.h>
191da177e4SLinus Torvalds 
20*1b2e2b73SRussell King #include "mm.h"
21*1b2e2b73SRussell King 
221da177e4SLinus Torvalds #if SHMLBA > 16384
231da177e4SLinus Torvalds #error FIX ME
241da177e4SLinus Torvalds #endif
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define from_address	(0xffff8000)
271da177e4SLinus Torvalds #define to_address	(0xffffc000)
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds static DEFINE_SPINLOCK(v6_lock);
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds /*
321da177e4SLinus Torvalds  * Copy the user page.  No aliasing to deal with so we can just
331da177e4SLinus Torvalds  * attack the kernel's existing mapping of these pages.
341da177e4SLinus Torvalds  */
35b4c2803cSRussell King static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	copy_page(kto, kfrom);
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds /*
411da177e4SLinus Torvalds  * Clear the user page.  No aliasing to deal with so we can just
421da177e4SLinus Torvalds  * attack the kernel's existing mapping of this page.
431da177e4SLinus Torvalds  */
44b4c2803cSRussell King static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds 	clear_page(kaddr);
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds /*
501da177e4SLinus Torvalds  * Copy the page, taking account of the cache colour.
511da177e4SLinus Torvalds  */
52b4c2803cSRussell King static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
531da177e4SLinus Torvalds {
54b8a9b66fSRussell King 	unsigned int offset = CACHE_COLOUR(vaddr);
551da177e4SLinus Torvalds 	unsigned long from, to;
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	/*
581da177e4SLinus Torvalds 	 * Discard data in the kernel mapping for the new page.
591da177e4SLinus Torvalds 	 * FIXME: needs this MCRR to be supported.
601da177e4SLinus Torvalds 	 */
611da177e4SLinus Torvalds 	__asm__("mcrr	p15, 0, %1, %0, c6	@ 0xec401f06"
621da177e4SLinus Torvalds 	   :
631da177e4SLinus Torvalds 	   : "r" (kto),
641da177e4SLinus Torvalds 	     "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
651da177e4SLinus Torvalds 	   : "cc");
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	/*
681da177e4SLinus Torvalds 	 * Now copy the page using the same cache colour as the
691da177e4SLinus Torvalds 	 * pages ultimate destination.
701da177e4SLinus Torvalds 	 */
711da177e4SLinus Torvalds 	spin_lock(&v6_lock);
721da177e4SLinus Torvalds 
73b4c2803cSRussell King 	set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL));
74b4c2803cSRussell King 	set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL));
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	from = from_address + (offset << PAGE_SHIFT);
771da177e4SLinus Torvalds 	to   = to_address + (offset << PAGE_SHIFT);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	flush_tlb_kernel_page(from);
801da177e4SLinus Torvalds 	flush_tlb_kernel_page(to);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	copy_page((void *)to, (void *)from);
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 	spin_unlock(&v6_lock);
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds  * Clear the user page.  We need to deal with the aliasing issues,
891da177e4SLinus Torvalds  * so remap the kernel page into the same cache colour as the user
901da177e4SLinus Torvalds  * page.
911da177e4SLinus Torvalds  */
92b4c2803cSRussell King static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
931da177e4SLinus Torvalds {
94b8a9b66fSRussell King 	unsigned int offset = CACHE_COLOUR(vaddr);
951da177e4SLinus Torvalds 	unsigned long to = to_address + (offset << PAGE_SHIFT);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	/*
981da177e4SLinus Torvalds 	 * Discard data in the kernel mapping for the new page
991da177e4SLinus Torvalds 	 * FIXME: needs this MCRR to be supported.
1001da177e4SLinus Torvalds 	 */
1011da177e4SLinus Torvalds 	__asm__("mcrr	p15, 0, %1, %0, c6	@ 0xec401f06"
1021da177e4SLinus Torvalds 	   :
1031da177e4SLinus Torvalds 	   : "r" (kaddr),
1041da177e4SLinus Torvalds 	     "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES)
1051da177e4SLinus Torvalds 	   : "cc");
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	/*
1081da177e4SLinus Torvalds 	 * Now clear the page using the same cache colour as
1091da177e4SLinus Torvalds 	 * the pages ultimate destination.
1101da177e4SLinus Torvalds 	 */
1111da177e4SLinus Torvalds 	spin_lock(&v6_lock);
1121da177e4SLinus Torvalds 
113b4c2803cSRussell King 	set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL));
1141da177e4SLinus Torvalds 	flush_tlb_kernel_page(to);
1151da177e4SLinus Torvalds 	clear_page((void *)to);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	spin_unlock(&v6_lock);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds struct cpu_user_fns v6_user_fns __initdata = {
1211da177e4SLinus Torvalds 	.cpu_clear_user_page	= v6_clear_user_page_nonaliasing,
1221da177e4SLinus Torvalds 	.cpu_copy_user_page	= v6_copy_user_page_nonaliasing,
1231da177e4SLinus Torvalds };
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds static int __init v6_userpage_init(void)
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 	if (cache_is_vipt_aliasing()) {
1281da177e4SLinus Torvalds 		cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
1291da177e4SLinus Torvalds 		cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
1301da177e4SLinus Torvalds 	}
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	return 0;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
13508ee4e4cSRussell King core_initcall(v6_userpage_init);
136