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> 16dbda6ac0SRalf Baechle #include <linux/syscalls.h> 171da177e4SLinus Torvalds #include <linux/mm.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <asm/cacheflush.h> 201da177e4SLinus Torvalds #include <asm/processor.h> 211da177e4SLinus Torvalds #include <asm/cpu.h> 221da177e4SLinus Torvalds #include <asm/cpu-features.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /* Cache operations. */ 251da177e4SLinus Torvalds void (*flush_cache_all)(void); 261da177e4SLinus Torvalds void (*__flush_cache_all)(void); 271da177e4SLinus Torvalds void (*flush_cache_mm)(struct mm_struct *mm); 281da177e4SLinus Torvalds void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, 291da177e4SLinus Torvalds unsigned long end); 3053de0d47SRalf Baechle void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, 3153de0d47SRalf Baechle unsigned long pfn); 32d4264f18SAtsushi Nemoto void (*flush_icache_range)(unsigned long start, unsigned long end); 33e0cee3eeSThomas Bogendoerfer void (*local_flush_icache_range)(unsigned long start, unsigned long end); 341da177e4SLinus Torvalds 359c5a3d72SRalf Baechle void (*__flush_cache_vmap)(void); 369c5a3d72SRalf Baechle void (*__flush_cache_vunmap)(void); 379c5a3d72SRalf Baechle 38d9cdc901SRalf Baechle void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); 39d9cdc901SRalf Baechle void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size); 40d9cdc901SRalf Baechle 41d9cdc901SRalf Baechle EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); 42d9cdc901SRalf Baechle 431da177e4SLinus Torvalds /* MIPS specific cache operations */ 441da177e4SLinus Torvalds void (*flush_cache_sigtramp)(unsigned long addr); 457e3bfc7cSRalf Baechle void (*local_flush_data_cache_page)(void * addr); 461da177e4SLinus Torvalds void (*flush_data_cache_page)(unsigned long addr); 471da177e4SLinus Torvalds void (*flush_icache_all)(void); 481da177e4SLinus Torvalds 499202f325SRalf Baechle EXPORT_SYMBOL_GPL(local_flush_data_cache_page); 509ff77c46SRalf Baechle EXPORT_SYMBOL(flush_data_cache_page); 519ff77c46SRalf Baechle 521da177e4SLinus Torvalds #ifdef CONFIG_DMA_NONCOHERENT 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* DMA cache operations. */ 551da177e4SLinus Torvalds void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); 561da177e4SLinus Torvalds void (*_dma_cache_wback)(unsigned long start, unsigned long size); 571da177e4SLinus Torvalds void (*_dma_cache_inv)(unsigned long start, unsigned long size); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds EXPORT_SYMBOL(_dma_cache_wback_inv); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #endif /* CONFIG_DMA_NONCOHERENT */ 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * We could optimize the case where the cache argument is not BCACHE but 651da177e4SLinus Torvalds * that seems very atypical use ... 661da177e4SLinus Torvalds */ 67dbda6ac0SRalf Baechle SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, 68dbda6ac0SRalf Baechle unsigned int, cache) 691da177e4SLinus Torvalds { 70750ccf68SAtsushi Nemoto if (bytes == 0) 71750ccf68SAtsushi Nemoto return 0; 72fe00f943SRalf Baechle if (!access_ok(VERIFY_WRITE, (void __user *) addr, bytes)) 731da177e4SLinus Torvalds return -EFAULT; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds flush_icache_range(addr, addr + bytes); 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds return 0; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds void __flush_dcache_page(struct page *page) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds struct address_space *mapping = page_mapping(page); 831da177e4SLinus Torvalds unsigned long addr; 841da177e4SLinus Torvalds 85585fa724SRalf Baechle if (PageHighMem(page)) 86585fa724SRalf Baechle return; 871da177e4SLinus Torvalds if (mapping && !mapping_mapped(mapping)) { 881da177e4SLinus Torvalds SetPageDcacheDirty(page); 891da177e4SLinus Torvalds return; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * We could delay the flush for the !page_mapping case too. But that 941da177e4SLinus Torvalds * case is for exec env/arg pages and those are %99 certainly going to 951da177e4SLinus Torvalds * get faulted into the tlb (and thus flushed) anyways. 961da177e4SLinus Torvalds */ 971da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 981da177e4SLinus Torvalds flush_data_cache_page(addr); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds EXPORT_SYMBOL(__flush_dcache_page); 1021da177e4SLinus Torvalds 1037575a49fSRalf Baechle void __flush_anon_page(struct page *page, unsigned long vmaddr) 1047575a49fSRalf Baechle { 1059a74b3ebSRalf Baechle unsigned long addr = (unsigned long) page_address(page); 1069a74b3ebSRalf Baechle 1079a74b3ebSRalf Baechle if (pages_do_alias(addr, vmaddr)) { 1089a74b3ebSRalf Baechle if (page_mapped(page) && !Page_dcache_dirty(page)) { 1097575a49fSRalf Baechle void *kaddr; 1107575a49fSRalf Baechle 1117575a49fSRalf Baechle kaddr = kmap_coherent(page, vmaddr); 1127575a49fSRalf Baechle flush_data_cache_page((unsigned long)kaddr); 113eacb9d61SRalf Baechle kunmap_coherent(); 1149a74b3ebSRalf Baechle } else 1159a74b3ebSRalf Baechle flush_data_cache_page(addr); 1167575a49fSRalf Baechle } 1177575a49fSRalf Baechle } 1187575a49fSRalf Baechle 1197575a49fSRalf Baechle EXPORT_SYMBOL(__flush_anon_page); 1207575a49fSRalf Baechle 1211da177e4SLinus Torvalds void __update_cache(struct vm_area_struct *vma, unsigned long address, 1221da177e4SLinus Torvalds pte_t pte) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds struct page *page; 1251da177e4SLinus Torvalds unsigned long pfn, addr; 126585fa724SRalf Baechle int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds pfn = pte_pfn(pte); 129585fa724SRalf Baechle if (unlikely(!pfn_valid(pfn))) 130585fa724SRalf Baechle return; 131585fa724SRalf Baechle page = pfn_to_page(pfn); 132585fa724SRalf Baechle if (page_mapping(page) && Page_dcache_dirty(page)) { 1331da177e4SLinus Torvalds addr = (unsigned long) page_address(page); 134585fa724SRalf Baechle if (exec || pages_do_alias(addr, address & PAGE_MASK)) 1351da177e4SLinus Torvalds flush_data_cache_page(addr); 1361da177e4SLinus Torvalds ClearPageDcacheDirty(page); 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 14035133692SChris Dearman unsigned long _page_cachable_default; 1417b3e543dSAnton Altaparmakov EXPORT_SYMBOL(_page_cachable_default); 14235133692SChris Dearman 14335133692SChris Dearman static inline void setup_protection_map(void) 14435133692SChris Dearman { 1456dd9344cSDavid Daney if (kernel_uses_smartmips_rixi) { 1466dd9344cSDavid Daney protection_map[0] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); 1476dd9344cSDavid Daney protection_map[1] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); 1486dd9344cSDavid Daney protection_map[2] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); 1496dd9344cSDavid Daney protection_map[3] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); 1506dd9344cSDavid Daney protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); 1516dd9344cSDavid Daney protection_map[5] = __pgprot(_page_cachable_default | _PAGE_PRESENT); 1526dd9344cSDavid Daney protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); 1536dd9344cSDavid Daney protection_map[7] = __pgprot(_page_cachable_default | _PAGE_PRESENT); 1546dd9344cSDavid Daney 1556dd9344cSDavid Daney protection_map[8] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); 1566dd9344cSDavid Daney protection_map[9] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); 1576dd9344cSDavid Daney protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ); 1586dd9344cSDavid Daney protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE); 1596dd9344cSDavid Daney protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); 1606dd9344cSDavid Daney protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT); 1616dd9344cSDavid Daney protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ); 1626dd9344cSDavid Daney protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); 1636dd9344cSDavid Daney 1646dd9344cSDavid Daney } else { 16535133692SChris Dearman protection_map[0] = PAGE_NONE; 16635133692SChris Dearman protection_map[1] = PAGE_READONLY; 16735133692SChris Dearman protection_map[2] = PAGE_COPY; 16835133692SChris Dearman protection_map[3] = PAGE_COPY; 16935133692SChris Dearman protection_map[4] = PAGE_READONLY; 17035133692SChris Dearman protection_map[5] = PAGE_READONLY; 17135133692SChris Dearman protection_map[6] = PAGE_COPY; 17235133692SChris Dearman protection_map[7] = PAGE_COPY; 17335133692SChris Dearman protection_map[8] = PAGE_NONE; 17435133692SChris Dearman protection_map[9] = PAGE_READONLY; 17535133692SChris Dearman protection_map[10] = PAGE_SHARED; 17635133692SChris Dearman protection_map[11] = PAGE_SHARED; 17735133692SChris Dearman protection_map[12] = PAGE_READONLY; 17835133692SChris Dearman protection_map[13] = PAGE_READONLY; 17935133692SChris Dearman protection_map[14] = PAGE_SHARED; 18035133692SChris Dearman protection_map[15] = PAGE_SHARED; 18135133692SChris Dearman } 1826dd9344cSDavid Daney } 1831da177e4SLinus Torvalds 18463731c96SDavid Daney void __cpuinit cpu_cache_init(void) 1851da177e4SLinus Torvalds { 18602cf2119SRalf Baechle if (cpu_has_3k_cache) { 18702cf2119SRalf Baechle extern void __weak r3k_cache_init(void); 1881da177e4SLinus Torvalds 18902cf2119SRalf Baechle r3k_cache_init(); 1901da177e4SLinus Torvalds } 19102cf2119SRalf Baechle if (cpu_has_6k_cache) { 19202cf2119SRalf Baechle extern void __weak r6k_cache_init(void); 19302cf2119SRalf Baechle 19402cf2119SRalf Baechle r6k_cache_init(); 19502cf2119SRalf Baechle } 19602cf2119SRalf Baechle if (cpu_has_4k_cache) { 19702cf2119SRalf Baechle extern void __weak r4k_cache_init(void); 19802cf2119SRalf Baechle 19902cf2119SRalf Baechle r4k_cache_init(); 20002cf2119SRalf Baechle } 20102cf2119SRalf Baechle if (cpu_has_8k_cache) { 20202cf2119SRalf Baechle extern void __weak r8k_cache_init(void); 20302cf2119SRalf Baechle 20402cf2119SRalf Baechle r8k_cache_init(); 20502cf2119SRalf Baechle } 20602cf2119SRalf Baechle if (cpu_has_tx39_cache) { 20702cf2119SRalf Baechle extern void __weak tx39_cache_init(void); 20802cf2119SRalf Baechle 20902cf2119SRalf Baechle tx39_cache_init(); 21002cf2119SRalf Baechle } 21102cf2119SRalf Baechle 21247d979ecSDavid Daney if (cpu_has_octeon_cache) { 21347d979ecSDavid Daney extern void __weak octeon_cache_init(void); 21447d979ecSDavid Daney 21547d979ecSDavid Daney octeon_cache_init(); 21647d979ecSDavid Daney } 21747d979ecSDavid Daney 21835133692SChris Dearman setup_protection_map(); 2191da177e4SLinus Torvalds } 22024e9d0b9SRalf Baechle 22124e9d0b9SRalf Baechle int __weak __uncached_access(struct file *file, unsigned long addr) 22224e9d0b9SRalf Baechle { 2236b2f3d1fSChristoph Hellwig if (file->f_flags & O_DSYNC) 22424e9d0b9SRalf Baechle return 1; 22524e9d0b9SRalf Baechle 22624e9d0b9SRalf Baechle return addr >= __pa(high_memory); 22724e9d0b9SRalf Baechle } 228