2008-10-31 16:08:02 +03:00
/*
* linux / arch / arm / mm / copypage - feroceon . S
*
* Copyright ( C ) 2008 Marvell Semiconductors
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
2008-10-31 18:08:35 +03:00
* This handles copy_user_highpage and clear_user_page on Feroceon
2008-10-31 16:08:02 +03:00
* more optimally than the generic implementations .
*/
# include <linux/init.h>
2008-10-31 18:08:35 +03:00
# include <linux/highmem.h>
2008-10-31 16:08:02 +03:00
2009-03-12 20:03:16 +03:00
static void __naked
2008-10-31 18:08:35 +03:00
feroceon_copy_user_page ( void * kto , const void * kfrom )
2008-10-31 16:08:02 +03:00
{
asm ( " \
stmfd sp ! , { r4 - r9 , lr } \ n \
2010-06-04 07:05:15 +04:00
mov ip , % 2 \ n \
2008-10-31 16:08:02 +03:00
1 : mov lr , r1 \ n \
ldmia r1 ! , { r2 - r9 } \ n \
pld [ lr , # 32 ] \ n \
pld [ lr , # 64 ] \ n \
pld [ lr , # 96 ] \ n \
pld [ lr , # 128 ] \ n \
pld [ lr , # 160 ] \ n \
pld [ lr , # 192 ] \ n \
pld [ lr , # 224 ] \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
ldmia r1 ! , { r2 - r9 } \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
stmia r0 , { r2 - r9 } \ n \
subs ip , ip , # ( 32 * 8 ) \ n \
mcr p15 , 0 , r0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
add r0 , r0 , # 32 \ n \
bne 1 b \ n \
mcr p15 , 0 , ip , c7 , c10 , 4 @ drain WB \ n \
ldmfd sp ! , { r4 - r9 , pc } "
:
2010-06-04 07:05:15 +04:00
: " r " ( kto ) , " r " ( kfrom ) , " I " ( PAGE_SIZE ) ) ;
2008-10-31 16:08:02 +03:00
}
2008-10-31 18:08:35 +03:00
void feroceon_copy_user_highpage ( struct page * to , struct page * from ,
2009-10-05 18:17:45 +04:00
unsigned long vaddr , struct vm_area_struct * vma )
2008-10-31 18:08:35 +03:00
{
void * kto , * kfrom ;
kto = kmap_atomic ( to , KM_USER0 ) ;
kfrom = kmap_atomic ( from , KM_USER1 ) ;
2009-10-05 18:34:22 +04:00
flush_cache_page ( vma , vaddr , page_to_pfn ( from ) ) ;
2008-10-31 18:08:35 +03:00
feroceon_copy_user_page ( kto , kfrom ) ;
kunmap_atomic ( kfrom , KM_USER1 ) ;
kunmap_atomic ( kto , KM_USER0 ) ;
}
2008-10-31 19:32:19 +03:00
void feroceon_clear_user_highpage ( struct page * page , unsigned long vaddr )
2008-10-31 16:08:02 +03:00
{
2008-11-04 10:42:27 +03:00
void * ptr , * kaddr = kmap_atomic ( page , KM_USER0 ) ;
asm volatile ( " \
mov r1 , % 2 \ n \
2008-10-31 16:08:02 +03:00
mov r2 , # 0 \ n \
mov r3 , # 0 \ n \
mov r4 , # 0 \ n \
mov r5 , # 0 \ n \
mov r6 , # 0 \ n \
mov r7 , # 0 \ n \
mov ip , # 0 \ n \
mov lr , # 0 \ n \
2008-10-31 19:32:19 +03:00
1 : stmia % 0 , { r2 - r7 , ip , lr } \ n \
2008-10-31 16:08:02 +03:00
subs r1 , r1 , # 1 \ n \
2008-10-31 19:32:19 +03:00
mcr p15 , 0 , % 0 , c7 , c14 , 1 @ clean and invalidate D line \ n \
2008-11-04 10:42:27 +03:00
add % 0 , % 0 , # 32 \ n \
2008-10-31 16:08:02 +03:00
bne 1 b \ n \
2008-10-31 19:32:19 +03:00
mcr p15 , 0 , r1 , c7 , c10 , 4 @ drain WB "
2008-11-04 10:42:27 +03:00
: " =r " ( ptr )
: " 0 " ( kaddr ) , " I " ( PAGE_SIZE / 32 )
2008-10-31 19:32:19 +03:00
: " r1 " , " r2 " , " r3 " , " r4 " , " r5 " , " r6 " , " r7 " , " ip " , " lr " ) ;
kunmap_atomic ( kaddr , KM_USER0 ) ;
2008-10-31 16:08:02 +03:00
}
struct cpu_user_fns feroceon_user_fns __initdata = {
2008-10-31 19:32:19 +03:00
. cpu_clear_user_highpage = feroceon_clear_user_highpage ,
2008-10-31 18:08:35 +03:00
. cpu_copy_user_highpage = feroceon_copy_user_highpage ,
2008-10-31 16:08:02 +03:00
} ;