2005-09-04 02:57:09 +04:00
/*
* linux / arch / m68k / mm / cache . c
*
* Instruction cache handling
*
* Copyright ( C ) 1995 Hamish Macdonald
*/
# include <linux/module.h>
# include <asm/pgalloc.h>
# include <asm/traps.h>
static unsigned long virt_to_phys_slow ( unsigned long vaddr )
{
if ( CPU_IS_060 ) {
unsigned long paddr ;
/* The PLPAR instruction causes an access error if the translation
* is not possible . To catch this we use the same exception mechanism
* as for user space accesses in < asm / uaccess . h > . */
asm volatile ( " .chip 68060 \n "
" 1: plpar (%0) \n "
" .chip 68k \n "
" 2: \n "
" .section .fixup, \" ax \" \n "
" .even \n "
" 3: sub.l %0,%0 \n "
" jra 2b \n "
" .previous \n "
" .section __ex_table, \" a \" \n "
" .align 4 \n "
" .long 1b,3b \n "
" .previous "
: " =a " ( paddr )
: " 0 " ( vaddr ) ) ;
return paddr ;
} else if ( CPU_IS_040 ) {
unsigned long mmusr ;
asm volatile ( " .chip 68040 \n \t "
" ptestr (%1) \n \t "
" movec %%mmusr, %0 \n \t "
" .chip 68k "
: " =r " ( mmusr )
: " a " ( vaddr ) ) ;
if ( mmusr & MMU_R_040 )
return ( mmusr & PAGE_MASK ) | ( vaddr & ~ PAGE_MASK ) ;
} else {
unsigned short mmusr ;
unsigned long * descaddr ;
asm volatile ( " ptestr %3,%2@,#7,%0 \n \t "
2012-01-09 18:10:15 +04:00
" pmove %%psr,%1 "
: " =a& " ( descaddr ) , " =m " ( mmusr )
: " a " ( vaddr ) , " d " ( get_fs ( ) . seg ) ) ;
2005-09-04 02:57:09 +04:00
if ( mmusr & ( MMU_I | MMU_B | MMU_L ) )
return 0 ;
descaddr = phys_to_virt ( ( unsigned long ) descaddr ) ;
switch ( mmusr & MMU_NUM ) {
case 1 :
return ( * descaddr & 0xfe000000 ) | ( vaddr & 0x01ffffff ) ;
case 2 :
return ( * descaddr & 0xfffc0000 ) | ( vaddr & 0x0003ffff ) ;
case 3 :
return ( * descaddr & PAGE_MASK ) | ( vaddr & ~ PAGE_MASK ) ;
}
}
return 0 ;
}
/* Push n pages at kernel virtual address and clear the icache */
/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
void flush_icache_range ( unsigned long address , unsigned long endaddr )
{
2011-10-17 08:38:09 +04:00
if ( CPU_IS_COLDFIRE ) {
unsigned long start , end ;
start = address & ICACHE_SET_MASK ;
end = endaddr & ICACHE_SET_MASK ;
if ( start > end ) {
flush_cf_icache ( 0 , end ) ;
end = ICACHE_MAX_ADDR ;
}
flush_cf_icache ( start , end ) ;
} else if ( CPU_IS_040_OR_060 ) {
2005-09-04 02:57:09 +04:00
address & = PAGE_MASK ;
do {
asm volatile ( " nop \n \t "
" .chip 68040 \n \t "
" cpushp %%bc,(%0) \n \t "
" .chip 68k "
: : " a " ( virt_to_phys_slow ( address ) ) ) ;
address + = PAGE_SIZE ;
} while ( address < endaddr ) ;
} else {
unsigned long tmp ;
asm volatile ( " movec %%cacr,%0 \n \t "
" orw %1,%0 \n \t "
" movec %0,%%cacr "
: " =&d " ( tmp )
: " di " ( FLUSH_I ) ) ;
}
}
EXPORT_SYMBOL ( flush_icache_range ) ;
void flush_icache_user_range ( struct vm_area_struct * vma , struct page * page ,
unsigned long addr , int len )
{
2011-10-17 08:38:09 +04:00
if ( CPU_IS_COLDFIRE ) {
unsigned long start , end ;
start = addr & ICACHE_SET_MASK ;
end = ( addr + len ) & ICACHE_SET_MASK ;
if ( start > end ) {
flush_cf_icache ( 0 , end ) ;
end = ICACHE_MAX_ADDR ;
}
flush_cf_icache ( start , end ) ;
} else if ( CPU_IS_040_OR_060 ) {
2005-09-04 02:57:09 +04:00
asm volatile ( " nop \n \t "
" .chip 68040 \n \t "
" cpushp %%bc,(%0) \n \t "
" .chip 68k "
: : " a " ( page_to_phys ( page ) ) ) ;
} else {
unsigned long tmp ;
asm volatile ( " movec %%cacr,%0 \n \t "
" orw %1,%0 \n \t "
" movec %0,%%cacr "
: " =&d " ( tmp )
: " di " ( FLUSH_I ) ) ;
}
}