2010-05-28 23:09:12 -04:00
/*
* Copyright 2010 Tilera Corporation . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
*
*/
# include <linux/cpumask.h>
# include <linux/module.h>
2012-04-01 14:04:21 -04:00
# include <linux/hugetlb.h>
2010-05-28 23:09:12 -04:00
# include <asm/tlbflush.h>
# include <asm/homecache.h>
# include <hv/hypervisor.h>
/* From tlbflush.h */
DEFINE_PER_CPU ( int , current_asid ) ;
int min_asid , max_asid ;
/*
* Note that we flush the L1I ( for VM_EXEC pages ) as well as the TLB
* so that when we are unmapping an executable page , we also flush it .
* Combined with flushing the L1I at context switch time , this means
* we don ' t have to do any other icache flushes .
*/
void flush_tlb_mm ( struct mm_struct * mm )
{
HV_Remote_ASID asids [ NR_CPUS ] ;
int i = 0 , cpu ;
2011-04-18 21:18:11 +09:00
for_each_cpu ( cpu , mm_cpumask ( mm ) ) {
2010-05-28 23:09:12 -04:00
HV_Remote_ASID * asid = & asids [ i + + ] ;
asid - > y = cpu / smp_topology . width ;
asid - > x = cpu % smp_topology . width ;
asid - > asid = per_cpu ( current_asid , cpu ) ;
}
2011-04-18 21:18:11 +09:00
flush_remote ( 0 , HV_FLUSH_EVICT_L1I , mm_cpumask ( mm ) ,
2010-05-28 23:09:12 -04:00
0 , 0 , 0 , NULL , asids , i ) ;
}
void flush_tlb_current_task ( void )
{
flush_tlb_mm ( current - > mm ) ;
}
2012-04-01 14:04:21 -04:00
void flush_tlb_page_mm ( struct vm_area_struct * vma , struct mm_struct * mm ,
2010-05-28 23:09:12 -04:00
unsigned long va )
{
2012-04-01 14:04:21 -04:00
unsigned long size = vma_kernel_pagesize ( vma ) ;
2010-05-28 23:09:12 -04:00
int cache = ( vma - > vm_flags & VM_EXEC ) ? HV_FLUSH_EVICT_L1I : 0 ;
2011-04-18 21:18:11 +09:00
flush_remote ( 0 , cache , mm_cpumask ( mm ) ,
va , size , size , mm_cpumask ( mm ) , NULL , 0 ) ;
2010-05-28 23:09:12 -04:00
}
2012-04-01 14:04:21 -04:00
void flush_tlb_page ( struct vm_area_struct * vma , unsigned long va )
2010-05-28 23:09:12 -04:00
{
flush_tlb_page_mm ( vma , vma - > vm_mm , va ) ;
}
EXPORT_SYMBOL ( flush_tlb_page ) ;
2012-04-01 14:04:21 -04:00
void flush_tlb_range ( struct vm_area_struct * vma ,
2010-05-28 23:09:12 -04:00
unsigned long start , unsigned long end )
{
2012-04-01 14:04:21 -04:00
unsigned long size = vma_kernel_pagesize ( vma ) ;
2010-05-28 23:09:12 -04:00
struct mm_struct * mm = vma - > vm_mm ;
int cache = ( vma - > vm_flags & VM_EXEC ) ? HV_FLUSH_EVICT_L1I : 0 ;
2011-04-18 21:18:11 +09:00
flush_remote ( 0 , cache , mm_cpumask ( mm ) , start , end - start , size ,
mm_cpumask ( mm ) , NULL , 0 ) ;
2010-05-28 23:09:12 -04:00
}
void flush_tlb_all ( void )
{
int i ;
for ( i = 0 ; ; + + i ) {
HV_VirtAddrRange r = hv_inquire_virtual ( i ) ;
if ( r . size = = 0 )
break ;
flush_remote ( 0 , HV_FLUSH_EVICT_L1I , cpu_online_mask ,
r . start , r . size , PAGE_SIZE , cpu_online_mask ,
NULL , 0 ) ;
flush_remote ( 0 , 0 , NULL ,
r . start , r . size , HPAGE_SIZE , cpu_online_mask ,
NULL , 0 ) ;
}
}
2013-08-09 16:09:41 -04:00
/*
* Callers need to flush the L1I themselves if necessary , e . g . for
* kernel module unload . Otherwise we assume callers are not using
* executable pgprot_t ' s . Using EVICT_L1I means that dataplane cpus
* will get an unnecessary interrupt otherwise .
*/
2010-05-28 23:09:12 -04:00
void flush_tlb_kernel_range ( unsigned long start , unsigned long end )
{
2013-08-09 16:09:41 -04:00
flush_remote ( 0 , 0 , NULL ,
2010-05-28 23:09:12 -04:00
start , end - start , PAGE_SIZE , cpu_online_mask , NULL , 0 ) ;
}