2006-09-27 15:13:36 +09:00
/*
* TLB flushing operations for SH with an MMU .
*
* Copyright ( C ) 1999 Niibe Yutaka
2007-03-05 19:46:47 +09:00
* Copyright ( C ) 2003 Paul Mundt
2006-09-27 15:13:36 +09:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include <linux/mm.h>
# include <asm/mmu_context.h>
# include <asm/tlbflush.h>
2006-12-25 19:28:54 +09:00
void local_flush_tlb_page ( struct vm_area_struct * vma , unsigned long page )
2006-09-27 15:13:36 +09:00
{
2006-12-25 09:51:47 +09:00
unsigned int cpu = smp_processor_id ( ) ;
if ( vma - > vm_mm & & cpu_context ( cpu , vma - > vm_mm ) ! = NO_CONTEXT ) {
2006-09-27 15:13:36 +09:00
unsigned long flags ;
unsigned long asid ;
unsigned long saved_asid = MMU_NO_ASID ;
2006-12-25 09:51:47 +09:00
asid = cpu_asid ( cpu , vma - > vm_mm ) ;
2006-09-27 15:13:36 +09:00
page & = PAGE_MASK ;
local_irq_save ( flags ) ;
if ( vma - > vm_mm ! = current - > mm ) {
saved_asid = get_asid ( ) ;
set_asid ( asid ) ;
}
2006-12-25 19:37:56 +09:00
local_flush_tlb_one ( asid , page ) ;
2006-09-27 15:13:36 +09:00
if ( saved_asid ! = MMU_NO_ASID )
set_asid ( saved_asid ) ;
local_irq_restore ( flags ) ;
}
}
2006-12-25 19:28:54 +09:00
void local_flush_tlb_range ( struct vm_area_struct * vma , unsigned long start ,
unsigned long end )
2006-09-27 15:13:36 +09:00
{
struct mm_struct * mm = vma - > vm_mm ;
2006-12-25 09:51:47 +09:00
unsigned int cpu = smp_processor_id ( ) ;
2006-09-27 15:13:36 +09:00
2006-12-25 09:51:47 +09:00
if ( cpu_context ( cpu , mm ) ! = NO_CONTEXT ) {
2006-09-27 15:13:36 +09:00
unsigned long flags ;
int size ;
local_irq_save ( flags ) ;
size = ( end - start + ( PAGE_SIZE - 1 ) ) > > PAGE_SHIFT ;
if ( size > ( MMU_NTLB_ENTRIES / 4 ) ) { /* Too many TLB to flush */
2006-12-25 09:51:47 +09:00
cpu_context ( cpu , mm ) = NO_CONTEXT ;
2006-09-27 15:13:36 +09:00
if ( mm = = current - > mm )
2006-12-25 09:51:47 +09:00
activate_context ( mm , cpu ) ;
2006-09-27 15:13:36 +09:00
} else {
2006-09-27 18:33:49 +09:00
unsigned long asid ;
2006-09-27 15:13:36 +09:00
unsigned long saved_asid = MMU_NO_ASID ;
2006-12-25 09:51:47 +09:00
asid = cpu_asid ( cpu , mm ) ;
2006-09-27 15:13:36 +09:00
start & = PAGE_MASK ;
end + = ( PAGE_SIZE - 1 ) ;
end & = PAGE_MASK ;
if ( mm ! = current - > mm ) {
saved_asid = get_asid ( ) ;
set_asid ( asid ) ;
}
while ( start < end ) {
2006-12-25 19:37:56 +09:00
local_flush_tlb_one ( asid , start ) ;
2006-09-27 15:13:36 +09:00
start + = PAGE_SIZE ;
}
if ( saved_asid ! = MMU_NO_ASID )
set_asid ( saved_asid ) ;
}
local_irq_restore ( flags ) ;
}
}
2006-12-25 19:28:54 +09:00
void local_flush_tlb_kernel_range ( unsigned long start , unsigned long end )
2006-09-27 15:13:36 +09:00
{
2006-12-25 09:51:47 +09:00
unsigned int cpu = smp_processor_id ( ) ;
2006-09-27 15:13:36 +09:00
unsigned long flags ;
int size ;
local_irq_save ( flags ) ;
size = ( end - start + ( PAGE_SIZE - 1 ) ) > > PAGE_SHIFT ;
if ( size > ( MMU_NTLB_ENTRIES / 4 ) ) { /* Too many TLB to flush */
2006-12-25 19:28:54 +09:00
local_flush_tlb_all ( ) ;
2006-09-27 15:13:36 +09:00
} else {
2006-09-27 18:33:49 +09:00
unsigned long asid ;
2006-09-27 15:13:36 +09:00
unsigned long saved_asid = get_asid ( ) ;
2006-12-25 09:51:47 +09:00
asid = cpu_asid ( cpu , & init_mm ) ;
2006-09-27 15:13:36 +09:00
start & = PAGE_MASK ;
end + = ( PAGE_SIZE - 1 ) ;
end & = PAGE_MASK ;
set_asid ( asid ) ;
while ( start < end ) {
2006-12-25 19:37:56 +09:00
local_flush_tlb_one ( asid , start ) ;
2006-09-27 15:13:36 +09:00
start + = PAGE_SIZE ;
}
set_asid ( saved_asid ) ;
}
local_irq_restore ( flags ) ;
}
2006-12-25 19:28:54 +09:00
void local_flush_tlb_mm ( struct mm_struct * mm )
2006-09-27 15:13:36 +09:00
{
2006-12-25 09:51:47 +09:00
unsigned int cpu = smp_processor_id ( ) ;
2006-09-27 15:13:36 +09:00
/* Invalidate all TLB of this process. */
/* Instead of invalidating each TLB, we get new MMU context. */
2006-12-25 09:51:47 +09:00
if ( cpu_context ( cpu , mm ) ! = NO_CONTEXT ) {
2006-09-27 15:13:36 +09:00
unsigned long flags ;
local_irq_save ( flags ) ;
2006-12-25 09:51:47 +09:00
cpu_context ( cpu , mm ) = NO_CONTEXT ;
2006-09-27 15:13:36 +09:00
if ( mm = = current - > mm )
2006-12-25 09:51:47 +09:00
activate_context ( mm , cpu ) ;
2006-09-27 15:13:36 +09:00
local_irq_restore ( flags ) ;
}
}
2010-07-02 15:44:09 +09:00
void __flush_tlb_global ( void )
{
unsigned long flags ;
local_irq_save ( flags ) ;
/*
* This is the most destructive of the TLB flushing options ,
* and will tear down all of the UTLB / ITLB mappings , including
* wired entries .
*/
__raw_writel ( __raw_readl ( MMUCR ) | MMUCR_TI , MMUCR ) ;
local_irq_restore ( flags ) ;
}