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); 321da177e4SLinus Torvalds 33*9c5a3d72SRalf Baechle void (*__flush_cache_vmap)(void); 34*9c5a3d72SRalf Baechle void (*__flush_cache_vunmap)(void); 35*9c5a3d72SRalf Baechle 361da177e4SLinus Torvalds /* MIPS specific cache operations */ 371da177e4SLinus Torvalds void (*flush_cache_sigtramp)(unsigned long addr); 387e3bfc7cSRalf Baechle void (*local_flush_data_cache_page)(void * addr); 391da177e4SLinus Torvalds void (*flush_data_cache_page)(unsigned long addr); 401da177e4SLinus Torvalds void (*flush_icache_all)(void); 411da177e4SLinus Torvalds 429202f325SRalf Baechle EXPORT_SYMBOL_GPL(local_flush_data_cache_page); 439ff77c46SRalf Baechle EXPORT_SYMBOL(flush_data_cache_page); 449ff77c46SRalf Baechle 451da177e4SLinus Torvalds #ifdef CONFIG_DMA_NONCOHERENT 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* DMA cache operations. */ 481da177e4SLinus Torvalds void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); 491da177e4SLinus Torvalds void (*_dma_cache_wback)(unsigned long start, unsigned long size); 501da177e4SLinus Torvalds void (*_dma_cache_inv)(unsigned long start, unsigned long size); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds EXPORT_SYMBOL(_dma_cache_wback_inv); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #endif /* CONFIG_DMA_NONCOHERENT */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * We could optimize the case where the cache argument is not BCACHE but 581da177e4SLinus Torvalds * that seems very atypical use ... 591da177e4SLinus Torvalds */ 60d4264f18SAtsushi Nemoto asmlinkage int sys_cacheflush(unsigned long addr, 61fe00f943SRalf Baechle unsigned long bytes, unsigned int cache) 621da177e4SLinus Torvalds { 63750ccf68SAtsushi Nemoto if (bytes == 0) 64750ccf68SAtsushi Nemoto return 0; 65fe00f943SRalf Baechle if (!access_ok(VERIFY_WRITE, (void __user *) addr, bytes)) 661da177e4SLinus Torvalds return -EFAULT; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds flush_icache_range(addr, addr + bytes); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds return 0; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds void __flush_dcache_page(struct page *page) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds struct address_space *mapping = page_mapping(page); 761da177e4SLinus Torvalds unsigned long addr; 771da177e4SLinus Torvalds 78585fa724SRalf Baechle if (PageHighMem(page)) 79585fa724SRalf Baechle return; 801da177e4SLinus Torvalds if (mapping && !mapping_mapped(mapping)) { 811da177e4SLinus Torvalds SetPageDcacheDirty(page); 821da177e4SLinus Torvalds return; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* 861da177e4SLinus Torvalds * We could delay the flush for the !page_mapping case too. But that 871da177e4SLinus Torvalds * case is for exec env/arg pages and those are %99 certainly going to 881da177e4SLinus Torvalds * get faulted into the tlb (and thus flushed) anyways. 891da177e4SLinus Torvalds */ 901da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 911da177e4SLinus Torvalds flush_data_cache_page(addr); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds EXPORT_SYMBOL(__flush_dcache_page); 951da177e4SLinus Torvalds 967575a49fSRalf Baechle void __flush_anon_page(struct page *page, unsigned long vmaddr) 977575a49fSRalf Baechle { 989a74b3ebSRalf Baechle unsigned long addr = (unsigned long) page_address(page); 999a74b3ebSRalf Baechle 1009a74b3ebSRalf Baechle if (pages_do_alias(addr, vmaddr)) { 1019a74b3ebSRalf Baechle if (page_mapped(page) && !Page_dcache_dirty(page)) { 1027575a49fSRalf Baechle void *kaddr; 1037575a49fSRalf Baechle 1047575a49fSRalf Baechle kaddr = kmap_coherent(page, vmaddr); 1057575a49fSRalf Baechle flush_data_cache_page((unsigned long)kaddr); 106eacb9d61SRalf Baechle kunmap_coherent(); 1079a74b3ebSRalf Baechle } else 1089a74b3ebSRalf Baechle flush_data_cache_page(addr); 1097575a49fSRalf Baechle } 1107575a49fSRalf Baechle } 1117575a49fSRalf Baechle 1127575a49fSRalf Baechle EXPORT_SYMBOL(__flush_anon_page); 1137575a49fSRalf Baechle 1141da177e4SLinus Torvalds void __update_cache(struct vm_area_struct *vma, unsigned long address, 1151da177e4SLinus Torvalds pte_t pte) 1161da177e4SLinus Torvalds { 1171da177e4SLinus Torvalds struct page *page; 1181da177e4SLinus Torvalds unsigned long pfn, addr; 119585fa724SRalf Baechle int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds pfn = pte_pfn(pte); 122585fa724SRalf Baechle if (unlikely(!pfn_valid(pfn))) 123585fa724SRalf Baechle return; 124585fa724SRalf Baechle page = pfn_to_page(pfn); 125585fa724SRalf Baechle if (page_mapping(page) && Page_dcache_dirty(page)) { 1261da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 127585fa724SRalf Baechle if (exec || pages_do_alias(addr, address & PAGE_MASK)) 1281da177e4SLinus Torvalds flush_data_cache_page(addr); 1291da177e4SLinus Torvalds ClearPageDcacheDirty(page); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133234fcd14SRalf Baechle static char cache_panic[] __cpuinitdata = 134234fcd14SRalf Baechle "Yeee, unsupported cache architecture."; 1351da177e4SLinus Torvalds 136234fcd14SRalf Baechle void __devinit cpu_cache_init(void) 1371da177e4SLinus Torvalds { 13802cf2119SRalf Baechle if (cpu_has_3k_cache) { 13902cf2119SRalf Baechle extern void __weak r3k_cache_init(void); 1401da177e4SLinus Torvalds 14102cf2119SRalf Baechle r3k_cache_init(); 14202cf2119SRalf Baechle return; 1431da177e4SLinus Torvalds } 14402cf2119SRalf Baechle if (cpu_has_6k_cache) { 14502cf2119SRalf Baechle extern void __weak r6k_cache_init(void); 14602cf2119SRalf Baechle 14702cf2119SRalf Baechle r6k_cache_init(); 14802cf2119SRalf Baechle return; 14902cf2119SRalf Baechle } 15002cf2119SRalf Baechle if (cpu_has_4k_cache) { 15102cf2119SRalf Baechle extern void __weak r4k_cache_init(void); 15202cf2119SRalf Baechle 15302cf2119SRalf Baechle r4k_cache_init(); 15402cf2119SRalf Baechle return; 15502cf2119SRalf Baechle } 15602cf2119SRalf Baechle if (cpu_has_8k_cache) { 15702cf2119SRalf Baechle extern void __weak r8k_cache_init(void); 15802cf2119SRalf Baechle 15902cf2119SRalf Baechle r8k_cache_init(); 16002cf2119SRalf Baechle return; 16102cf2119SRalf Baechle } 16202cf2119SRalf Baechle if (cpu_has_tx39_cache) { 16302cf2119SRalf Baechle extern void __weak tx39_cache_init(void); 16402cf2119SRalf Baechle 16502cf2119SRalf Baechle tx39_cache_init(); 16602cf2119SRalf Baechle return; 16702cf2119SRalf Baechle } 16802cf2119SRalf Baechle 16902cf2119SRalf Baechle panic(cache_panic); 1701da177e4SLinus Torvalds } 17124e9d0b9SRalf Baechle 17224e9d0b9SRalf Baechle int __weak __uncached_access(struct file *file, unsigned long addr) 17324e9d0b9SRalf Baechle { 17424e9d0b9SRalf Baechle if (file->f_flags & O_SYNC) 17524e9d0b9SRalf Baechle return 1; 17624e9d0b9SRalf Baechle 17724e9d0b9SRalf Baechle return addr >= __pa(high_memory); 17824e9d0b9SRalf Baechle } 179