2005-04-16 15:20:36 -07: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 .
*
2007-10-11 23:46:05 +01:00
* Copyright ( C ) 1994 - 2003 , 06 , 07 by Ralf Baechle ( ralf @ linux - mips . org )
2007-03-23 21:36:37 +00:00
* Copyright ( C ) 2007 MIPS Technologies , Inc .
2005-04-16 15:20:36 -07:00
*/
2007-07-10 17:32:56 +01:00
# include <linux/fs.h>
# include <linux/fcntl.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/kernel.h>
2007-10-11 23:46:05 +01:00
# include <linux/linkage.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/sched.h>
2009-02-08 16:00:26 +00:00
# include <linux/syscalls.h>
2005-04-16 15:20:36 -07:00
# include <linux/mm.h>
# include <asm/cacheflush.h>
# include <asm/processor.h>
# include <asm/cpu.h>
# include <asm/cpu-features.h>
/* Cache operations. */
void ( * flush_cache_all ) ( void ) ;
void ( * __flush_cache_all ) ( void ) ;
void ( * flush_cache_mm ) ( struct mm_struct * mm ) ;
void ( * flush_cache_range ) ( struct vm_area_struct * vma , unsigned long start ,
unsigned long end ) ;
2005-03-18 17:36:42 +00:00
void ( * flush_cache_page ) ( struct vm_area_struct * vma , unsigned long page ,
unsigned long pfn ) ;
2006-01-29 02:27:51 +09:00
void ( * flush_icache_range ) ( unsigned long start , unsigned long end ) ;
2008-08-04 20:53:57 +02:00
void ( * local_flush_icache_range ) ( unsigned long start , unsigned long end ) ;
2005-04-16 15:20:36 -07:00
2008-04-05 15:13:23 +01:00
void ( * __flush_cache_vmap ) ( void ) ;
void ( * __flush_cache_vunmap ) ( void ) ;
2005-04-16 15:20:36 -07:00
/* MIPS specific cache operations */
void ( * flush_cache_sigtramp ) ( unsigned long addr ) ;
2006-04-05 20:42:04 +01:00
void ( * local_flush_data_cache_page ) ( void * addr ) ;
2005-04-16 15:20:36 -07:00
void ( * flush_data_cache_page ) ( unsigned long addr ) ;
void ( * flush_icache_all ) ( void ) ;
2006-12-10 18:43:59 +00:00
EXPORT_SYMBOL_GPL ( local_flush_data_cache_page ) ;
2005-03-08 14:39:39 +00:00
EXPORT_SYMBOL ( flush_data_cache_page ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_DMA_NONCOHERENT
/* DMA cache operations. */
void ( * _dma_cache_wback_inv ) ( unsigned long start , unsigned long size ) ;
void ( * _dma_cache_wback ) ( unsigned long start , unsigned long size ) ;
void ( * _dma_cache_inv ) ( unsigned long start , unsigned long size ) ;
EXPORT_SYMBOL ( _dma_cache_wback_inv ) ;
# endif /* CONFIG_DMA_NONCOHERENT */
/*
* We could optimize the case where the cache argument is not BCACHE but
* that seems very atypical use . . .
*/
2009-02-08 16:00:26 +00:00
SYSCALL_DEFINE3 ( cacheflush , unsigned long , addr , unsigned long , bytes ,
unsigned int , cache )
2005-04-16 15:20:36 -07:00
{
2005-10-19 19:57:14 +09:00
if ( bytes = = 0 )
return 0 ;
2005-03-01 19:22:29 +00:00
if ( ! access_ok ( VERIFY_WRITE , ( void __user * ) addr , bytes ) )
2005-04-16 15:20:36 -07:00
return - EFAULT ;
flush_icache_range ( addr , addr + bytes ) ;
return 0 ;
}
void __flush_dcache_page ( struct page * page )
{
struct address_space * mapping = page_mapping ( page ) ;
unsigned long addr ;
2006-08-12 16:40:08 +01:00
if ( PageHighMem ( page ) )
return ;
2005-04-16 15:20:36 -07:00
if ( mapping & & ! mapping_mapped ( mapping ) ) {
SetPageDcacheDirty ( page ) ;
return ;
}
/*
* We could delay the flush for the ! page_mapping case too . But that
* case is for exec env / arg pages and those are % 99 certainly going to
* get faulted into the tlb ( and thus flushed ) anyways .
*/
addr = ( unsigned long ) page_address ( page ) ;
flush_data_cache_page ( addr ) ;
}
EXPORT_SYMBOL ( __flush_dcache_page ) ;
2007-03-23 21:36:37 +00:00
void __flush_anon_page ( struct page * page , unsigned long vmaddr )
{
2008-02-16 22:34:25 +00:00
unsigned long addr = ( unsigned long ) page_address ( page ) ;
2007-03-23 21:36:37 +00:00
2008-02-16 22:34:25 +00:00
if ( pages_do_alias ( addr , vmaddr ) ) {
if ( page_mapped ( page ) & & ! Page_dcache_dirty ( page ) ) {
void * kaddr ;
kaddr = kmap_coherent ( page , vmaddr ) ;
flush_data_cache_page ( ( unsigned long ) kaddr ) ;
kunmap_coherent ( ) ;
} else
flush_data_cache_page ( addr ) ;
2007-03-23 21:36:37 +00:00
}
}
EXPORT_SYMBOL ( __flush_anon_page ) ;
2005-04-16 15:20:36 -07:00
void __update_cache ( struct vm_area_struct * vma , unsigned long address ,
pte_t pte )
{
struct page * page ;
unsigned long pfn , addr ;
2006-08-12 16:40:08 +01:00
int exec = ( vma - > vm_flags & VM_EXEC ) & & ! cpu_has_ic_fills_f_dc ;
2005-04-16 15:20:36 -07:00
pfn = pte_pfn ( pte ) ;
2006-08-12 16:40:08 +01:00
if ( unlikely ( ! pfn_valid ( pfn ) ) )
return ;
page = pfn_to_page ( pfn ) ;
if ( page_mapping ( page ) & & Page_dcache_dirty ( page ) ) {
addr = ( unsigned long ) page_address ( page ) ;
if ( exec | | pages_do_alias ( addr , address & PAGE_MASK ) )
2005-04-16 15:20:36 -07:00
flush_data_cache_page ( addr ) ;
ClearPageDcacheDirty ( page ) ;
}
}
2007-09-19 00:58:24 +01:00
unsigned long _page_cachable_default ;
2010-03-25 20:48:12 +00:00
EXPORT_SYMBOL ( _page_cachable_default ) ;
2007-09-19 00:58:24 +01:00
static inline void setup_protection_map ( void )
{
2010-02-10 15:12:47 -08:00
if ( kernel_uses_smartmips_rixi ) {
protection_map [ 0 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ ) ;
protection_map [ 1 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC ) ;
protection_map [ 2 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ ) ;
protection_map [ 3 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC ) ;
protection_map [ 4 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ ) ;
protection_map [ 5 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT ) ;
protection_map [ 6 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ ) ;
protection_map [ 7 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT ) ;
protection_map [ 8 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ ) ;
protection_map [ 9 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC ) ;
protection_map [ 10 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ ) ;
protection_map [ 11 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE ) ;
protection_map [ 12 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ ) ;
protection_map [ 13 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT ) ;
protection_map [ 14 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ ) ;
protection_map [ 15 ] = __pgprot ( _page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE ) ;
} else {
protection_map [ 0 ] = PAGE_NONE ;
protection_map [ 1 ] = PAGE_READONLY ;
protection_map [ 2 ] = PAGE_COPY ;
protection_map [ 3 ] = PAGE_COPY ;
protection_map [ 4 ] = PAGE_READONLY ;
protection_map [ 5 ] = PAGE_READONLY ;
protection_map [ 6 ] = PAGE_COPY ;
protection_map [ 7 ] = PAGE_COPY ;
protection_map [ 8 ] = PAGE_NONE ;
protection_map [ 9 ] = PAGE_READONLY ;
protection_map [ 10 ] = PAGE_SHARED ;
protection_map [ 11 ] = PAGE_SHARED ;
protection_map [ 12 ] = PAGE_READONLY ;
protection_map [ 13 ] = PAGE_READONLY ;
protection_map [ 14 ] = PAGE_SHARED ;
protection_map [ 15 ] = PAGE_SHARED ;
}
2007-09-19 00:58:24 +01:00
}
2005-04-16 15:20:36 -07:00
2010-02-04 15:48:49 -08:00
void __cpuinit cpu_cache_init ( void )
2005-04-16 15:20:36 -07:00
{
2005-10-01 13:06:32 +01:00
if ( cpu_has_3k_cache ) {
extern void __weak r3k_cache_init ( void ) ;
r3k_cache_init ( ) ;
}
if ( cpu_has_6k_cache ) {
extern void __weak r6k_cache_init ( void ) ;
r6k_cache_init ( ) ;
2005-04-16 15:20:36 -07:00
}
2005-10-01 13:06:32 +01:00
if ( cpu_has_4k_cache ) {
extern void __weak r4k_cache_init ( void ) ;
r4k_cache_init ( ) ;
}
if ( cpu_has_8k_cache ) {
extern void __weak r8k_cache_init ( void ) ;
r8k_cache_init ( ) ;
}
if ( cpu_has_tx39_cache ) {
extern void __weak tx39_cache_init ( void ) ;
tx39_cache_init ( ) ;
}
2008-12-11 15:33:27 -08:00
if ( cpu_has_octeon_cache ) {
extern void __weak octeon_cache_init ( void ) ;
octeon_cache_init ( ) ;
}
2007-09-19 00:58:24 +01:00
setup_protection_map ( ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-10 17:32:56 +01:00
int __weak __uncached_access ( struct file * file , unsigned long addr )
{
2009-10-27 11:05:28 +01:00
if ( file - > f_flags & O_DSYNC )
2007-07-10 17:32:56 +01:00
return 1 ;
return addr > = __pa ( high_memory ) ;
}