2009-03-17 11:49:49 +03:00
/*
* arch / sh / mm / tlb - pteaex . c
*
* TLB operations for SH - X3 CPUs featuring PTE ASID Extensions .
*
* Copyright ( C ) 2009 Paul Mundt
*
* 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/kernel.h>
# include <linux/mm.h>
# include <linux/io.h>
# include <asm/mmu_context.h>
# include <asm/cacheflush.h>
2009-07-28 19:12:17 +04:00
void __update_tlb ( struct vm_area_struct * vma , unsigned long address , pte_t pte )
2009-03-17 11:49:49 +03:00
{
2009-07-28 19:12:17 +04:00
unsigned long flags , pteval , vpn ;
2009-03-17 11:49:49 +03:00
2009-07-28 19:12:17 +04:00
/*
* Handle debugger faulting in for debugee .
*/
2009-07-29 17:06:58 +04:00
if ( vma & & current - > active_mm ! = vma - > vm_mm )
2009-03-17 11:49:49 +03:00
return ;
local_irq_save ( flags ) ;
/* Set PTEH register */
vpn = address & MMU_VPN_MASK ;
__raw_writel ( vpn , MMU_PTEH ) ;
/* Set PTEAEX */
__raw_writel ( get_asid ( ) , MMU_PTEAEX ) ;
pteval = pte . pte_low ;
/* Set PTEA register */
# ifdef CONFIG_X2TLB
/*
* For the extended mode TLB this is trivial , only the ESZ and
* EPR bits need to be written out to PTEA , with the remainder of
* the protection bits ( with the exception of the compat - mode SZ
* and PR bits , which are cleared ) being written out in PTEL .
*/
__raw_writel ( pte . pte_high , MMU_PTEA ) ;
# endif
/* Set PTEL register */
pteval & = _PAGE_FLAGS_HARDWARE_MASK ; /* drop software flags */
# ifdef CONFIG_CACHE_WRITETHROUGH
pteval | = _PAGE_WT ;
# endif
/* conveniently, we want all the software flags to be 0 anyway */
__raw_writel ( pteval , MMU_PTEL ) ;
/* Load the TLB */
asm volatile ( " ldtlb " : /* no output */ : /* no input */ : " memory " ) ;
local_irq_restore ( flags ) ;
}
/*
* While SH - X2 extended TLB mode splits out the memory - mapped I / UTLB
* data arrays , SH - X3 cores with PTEAEX split out the memory - mapped
* address arrays . In compat mode the second array is inaccessible , while
* in extended mode , the legacy 8 - bit ASID field in address array 1 has
* undefined behaviour .
*/
2010-01-21 10:05:25 +03:00
void local_flush_tlb_one ( unsigned long asid , unsigned long page )
2009-03-17 11:49:49 +03:00
{
jump_to_uncached ( ) ;
__raw_writel ( page , MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT ) ;
__raw_writel ( asid , MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT ) ;
2010-03-21 22:51:43 +03:00
__raw_writel ( page , MMU_ITLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT ) ;
__raw_writel ( asid , MMU_ITLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT ) ;
2009-03-17 11:49:49 +03:00
back_to_cached ( ) ;
}
2010-04-02 11:13:27 +04:00
void local_flush_tlb_all ( void )
{
unsigned long flags , status ;
int i ;
/*
* Flush all the TLB .
*/
local_irq_save ( flags ) ;
jump_to_uncached ( ) ;
status = __raw_readl ( MMUCR ) ;
status = ( ( status & MMUCR_URB ) > > MMUCR_URB_SHIFT ) ;
if ( status = = 0 )
status = MMUCR_URB_NENTRIES ;
for ( i = 0 ; i < status ; i + + )
__raw_writel ( 0x0 , MMU_UTLB_ADDRESS_ARRAY | ( i < < 8 ) ) ;
for ( i = 0 ; i < 4 ; i + + )
__raw_writel ( 0x0 , MMU_ITLB_ADDRESS_ARRAY | ( i < < 8 ) ) ;
back_to_cached ( ) ;
ctrl_barrier ( ) ;
local_irq_restore ( flags ) ;
}