xref: /linux/arch/mips/mm/cache.c (revision 9c5a3d729cf430609d091ff610a7db363aafcd47)
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