11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 41da177e4SLinus Torvalds * for more details. 51da177e4SLinus Torvalds * 6641e97f3SRalf Baechle * Copyright (C) 1994 - 2003, 06, 07 by Ralf Baechle (ralf@linux-mips.org) 77575a49fSRalf Baechle * Copyright (C) 2007 MIPS Technologies, Inc. 81da177e4SLinus Torvalds */ 924e9d0b9SRalf Baechle #include <linux/fs.h> 1024e9d0b9SRalf Baechle #include <linux/fcntl.h> 111da177e4SLinus Torvalds #include <linux/init.h> 121da177e4SLinus Torvalds #include <linux/kernel.h> 13641e97f3SRalf Baechle #include <linux/linkage.h> 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/sched.h> 161da177e4SLinus Torvalds #include <linux/mm.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <asm/cacheflush.h> 191da177e4SLinus Torvalds #include <asm/processor.h> 201da177e4SLinus Torvalds #include <asm/cpu.h> 211da177e4SLinus Torvalds #include <asm/cpu-features.h> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds /* Cache operations. */ 241da177e4SLinus Torvalds void (*flush_cache_all)(void); 251da177e4SLinus Torvalds void (*__flush_cache_all)(void); 261da177e4SLinus Torvalds void (*flush_cache_mm)(struct mm_struct *mm); 271da177e4SLinus Torvalds void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, 281da177e4SLinus Torvalds unsigned long end); 2953de0d47SRalf Baechle void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, 3053de0d47SRalf Baechle unsigned long pfn); 31d4264f18SAtsushi Nemoto void (*flush_icache_range)(unsigned long start, unsigned long end); 32e0cee3eeSThomas Bogendoerfer void (*local_flush_icache_range)(unsigned long start, unsigned long end); 331da177e4SLinus Torvalds 349c5a3d72SRalf Baechle void (*__flush_cache_vmap)(void); 359c5a3d72SRalf Baechle void (*__flush_cache_vunmap)(void); 369c5a3d72SRalf Baechle 371da177e4SLinus Torvalds /* MIPS specific cache operations */ 381da177e4SLinus Torvalds void (*flush_cache_sigtramp)(unsigned long addr); 397e3bfc7cSRalf Baechle void (*local_flush_data_cache_page)(void * addr); 401da177e4SLinus Torvalds void (*flush_data_cache_page)(unsigned long addr); 411da177e4SLinus Torvalds void (*flush_icache_all)(void); 421da177e4SLinus Torvalds 439202f325SRalf Baechle EXPORT_SYMBOL_GPL(local_flush_data_cache_page); 449ff77c46SRalf Baechle EXPORT_SYMBOL(flush_data_cache_page); 459ff77c46SRalf Baechle 461da177e4SLinus Torvalds #ifdef CONFIG_DMA_NONCOHERENT 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* DMA cache operations. */ 491da177e4SLinus Torvalds void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); 501da177e4SLinus Torvalds void (*_dma_cache_wback)(unsigned long start, unsigned long size); 511da177e4SLinus Torvalds void (*_dma_cache_inv)(unsigned long start, unsigned long size); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds EXPORT_SYMBOL(_dma_cache_wback_inv); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds #endif /* CONFIG_DMA_NONCOHERENT */ 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * We could optimize the case where the cache argument is not BCACHE but 591da177e4SLinus Torvalds * that seems very atypical use ... 601da177e4SLinus Torvalds */ 61d4264f18SAtsushi Nemoto asmlinkage int sys_cacheflush(unsigned long addr, 62fe00f943SRalf Baechle unsigned long bytes, unsigned int cache) 631da177e4SLinus Torvalds { 64750ccf68SAtsushi Nemoto if (bytes == 0) 65750ccf68SAtsushi Nemoto return 0; 66fe00f943SRalf Baechle if (!access_ok(VERIFY_WRITE, (void __user *) addr, bytes)) 671da177e4SLinus Torvalds return -EFAULT; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds flush_icache_range(addr, addr + bytes); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds return 0; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds void __flush_dcache_page(struct page *page) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds struct address_space *mapping = page_mapping(page); 771da177e4SLinus Torvalds unsigned long addr; 781da177e4SLinus Torvalds 79585fa724SRalf Baechle if (PageHighMem(page)) 80585fa724SRalf Baechle return; 811da177e4SLinus Torvalds if (mapping && !mapping_mapped(mapping)) { 821da177e4SLinus Torvalds SetPageDcacheDirty(page); 831da177e4SLinus Torvalds return; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * We could delay the flush for the !page_mapping case too. But that 881da177e4SLinus Torvalds * case is for exec env/arg pages and those are %99 certainly going to 891da177e4SLinus Torvalds * get faulted into the tlb (and thus flushed) anyways. 901da177e4SLinus Torvalds */ 911da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 921da177e4SLinus Torvalds flush_data_cache_page(addr); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds EXPORT_SYMBOL(__flush_dcache_page); 961da177e4SLinus Torvalds 977575a49fSRalf Baechle void __flush_anon_page(struct page *page, unsigned long vmaddr) 987575a49fSRalf Baechle { 999a74b3ebSRalf Baechle unsigned long addr = (unsigned long) page_address(page); 1009a74b3ebSRalf Baechle 1019a74b3ebSRalf Baechle if (pages_do_alias(addr, vmaddr)) { 1029a74b3ebSRalf Baechle if (page_mapped(page) && !Page_dcache_dirty(page)) { 1037575a49fSRalf Baechle void *kaddr; 1047575a49fSRalf Baechle 1057575a49fSRalf Baechle kaddr = kmap_coherent(page, vmaddr); 1067575a49fSRalf Baechle flush_data_cache_page((unsigned long)kaddr); 107eacb9d61SRalf Baechle kunmap_coherent(); 1089a74b3ebSRalf Baechle } else 1099a74b3ebSRalf Baechle flush_data_cache_page(addr); 1107575a49fSRalf Baechle } 1117575a49fSRalf Baechle } 1127575a49fSRalf Baechle 1137575a49fSRalf Baechle EXPORT_SYMBOL(__flush_anon_page); 1147575a49fSRalf Baechle 1151da177e4SLinus Torvalds void __update_cache(struct vm_area_struct *vma, unsigned long address, 1161da177e4SLinus Torvalds pte_t pte) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds struct page *page; 1191da177e4SLinus Torvalds unsigned long pfn, addr; 120585fa724SRalf Baechle int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds pfn = pte_pfn(pte); 123585fa724SRalf Baechle if (unlikely(!pfn_valid(pfn))) 124585fa724SRalf Baechle return; 125585fa724SRalf Baechle page = pfn_to_page(pfn); 126585fa724SRalf Baechle if (page_mapping(page) && Page_dcache_dirty(page)) { 1271da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 128585fa724SRalf Baechle if (exec || pages_do_alias(addr, address & PAGE_MASK)) 1291da177e4SLinus Torvalds flush_data_cache_page(addr); 1301da177e4SLinus Torvalds ClearPageDcacheDirty(page); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 13435133692SChris Dearman unsigned long _page_cachable_default; 13535133692SChris Dearman EXPORT_SYMBOL_GPL(_page_cachable_default); 13635133692SChris Dearman 13735133692SChris Dearman static inline void setup_protection_map(void) 13835133692SChris Dearman { 13935133692SChris Dearman protection_map[0] = PAGE_NONE; 14035133692SChris Dearman protection_map[1] = PAGE_READONLY; 14135133692SChris Dearman protection_map[2] = PAGE_COPY; 14235133692SChris Dearman protection_map[3] = PAGE_COPY; 14335133692SChris Dearman protection_map[4] = PAGE_READONLY; 14435133692SChris Dearman protection_map[5] = PAGE_READONLY; 14535133692SChris Dearman protection_map[6] = PAGE_COPY; 14635133692SChris Dearman protection_map[7] = PAGE_COPY; 14735133692SChris Dearman protection_map[8] = PAGE_NONE; 14835133692SChris Dearman protection_map[9] = PAGE_READONLY; 14935133692SChris Dearman protection_map[10] = PAGE_SHARED; 15035133692SChris Dearman protection_map[11] = PAGE_SHARED; 15135133692SChris Dearman protection_map[12] = PAGE_READONLY; 15235133692SChris Dearman protection_map[13] = PAGE_READONLY; 15335133692SChris Dearman protection_map[14] = PAGE_SHARED; 15435133692SChris Dearman protection_map[15] = PAGE_SHARED; 15535133692SChris Dearman } 1561da177e4SLinus Torvalds 157234fcd14SRalf Baechle void __devinit cpu_cache_init(void) 1581da177e4SLinus Torvalds { 15902cf2119SRalf Baechle if (cpu_has_3k_cache) { 16002cf2119SRalf Baechle extern void __weak r3k_cache_init(void); 1611da177e4SLinus Torvalds 16202cf2119SRalf Baechle r3k_cache_init(); 1631da177e4SLinus Torvalds } 16402cf2119SRalf Baechle if (cpu_has_6k_cache) { 16502cf2119SRalf Baechle extern void __weak r6k_cache_init(void); 16602cf2119SRalf Baechle 16702cf2119SRalf Baechle r6k_cache_init(); 16802cf2119SRalf Baechle } 16902cf2119SRalf Baechle if (cpu_has_4k_cache) { 17002cf2119SRalf Baechle extern void __weak r4k_cache_init(void); 17102cf2119SRalf Baechle 17202cf2119SRalf Baechle r4k_cache_init(); 17302cf2119SRalf Baechle } 17402cf2119SRalf Baechle if (cpu_has_8k_cache) { 17502cf2119SRalf Baechle extern void __weak r8k_cache_init(void); 17602cf2119SRalf Baechle 17702cf2119SRalf Baechle r8k_cache_init(); 17802cf2119SRalf Baechle } 17902cf2119SRalf Baechle if (cpu_has_tx39_cache) { 18002cf2119SRalf Baechle extern void __weak tx39_cache_init(void); 18102cf2119SRalf Baechle 18202cf2119SRalf Baechle tx39_cache_init(); 18302cf2119SRalf Baechle } 18402cf2119SRalf Baechle 185*47d979ecSDavid Daney if (cpu_has_octeon_cache) { 186*47d979ecSDavid Daney extern void __weak octeon_cache_init(void); 187*47d979ecSDavid Daney 188*47d979ecSDavid Daney octeon_cache_init(); 189*47d979ecSDavid Daney } 190*47d979ecSDavid Daney 19135133692SChris Dearman setup_protection_map(); 1921da177e4SLinus Torvalds } 19324e9d0b9SRalf Baechle 19424e9d0b9SRalf Baechle int __weak __uncached_access(struct file *file, unsigned long addr) 19524e9d0b9SRalf Baechle { 19624e9d0b9SRalf Baechle if (file->f_flags & O_SYNC) 19724e9d0b9SRalf Baechle return 1; 19824e9d0b9SRalf Baechle 19924e9d0b9SRalf Baechle return addr >= __pa(high_memory); 20024e9d0b9SRalf Baechle } 201