cache.c revision 9202f32558601c2c99ddc438eb3218131d00d413
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License.  See the file "COPYING" in the main directory of this archive
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1994 - 2003 by Ralf Baechle
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cacheflush.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cpu.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cpu-features.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Cache operations. */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_cache_all)(void);
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*__flush_cache_all)(void);
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_cache_mm)(struct mm_struct *mm);
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long end);
2553de0d471fe8ddbbeca938cffedb4cc94e04da10Ralf Baechlevoid (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
2653de0d471fe8ddbbeca938cffedb4cc94e04da10Ralf Baechle	unsigned long pfn);
27d4264f183967db9c2dae4275abb98eb1f79facb2Atsushi Nemotovoid (*flush_icache_range)(unsigned long start, unsigned long end);
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MIPS specific cache operations */
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_cache_sigtramp)(unsigned long addr);
317e3bfc7cfc402458b0386086ab650ce811720927Ralf Baechlevoid (*local_flush_data_cache_page)(void * addr);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_data_cache_page)(unsigned long addr);
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*flush_icache_all)(void);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
359202f32558601c2c99ddc438eb3218131d00d413Ralf BaechleEXPORT_SYMBOL_GPL(local_flush_data_cache_page);
369ff77c469ed16221c6a4e882e48e4f0dcf451bdaRalf BaechleEXPORT_SYMBOL(flush_data_cache_page);
379ff77c469ed16221c6a4e882e48e4f0dcf451bdaRalf Baechle
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_DMA_NONCOHERENT
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DMA cache operations. */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*_dma_cache_wback)(unsigned long start, unsigned long size);
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid (*_dma_cache_inv)(unsigned long start, unsigned long size);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(_dma_cache_wback_inv);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(_dma_cache_wback);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(_dma_cache_inv);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_DMA_NONCOHERENT */
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We could optimize the case where the cache argument is not BCACHE but
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that seems very atypical use ...
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
55d4264f183967db9c2dae4275abb98eb1f79facb2Atsushi Nemotoasmlinkage int sys_cacheflush(unsigned long addr,
56fe00f943e0ef98b4057abcc2940d631a975b43cdRalf Baechle	unsigned long bytes, unsigned int cache)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
58750ccf687ff9adbf2a16066a3a2757d0f761384cAtsushi Nemoto	if (bytes == 0)
59750ccf687ff9adbf2a16066a3a2757d0f761384cAtsushi Nemoto		return 0;
60fe00f943e0ef98b4057abcc2940d631a975b43cdRalf Baechle	if (!access_ok(VERIFY_WRITE, (void __user *) addr, bytes))
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_icache_range(addr, addr + bytes);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __flush_dcache_page(struct page *page)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct address_space *mapping = page_mapping(page);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle	if (PageHighMem(page))
74585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle		return;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mapping && !mapping_mapped(mapping)) {
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SetPageDcacheDirty(page);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We could delay the flush for the !page_mapping case too.  But that
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * case is for exec env/arg pages and those are %99 certainly going to
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * get faulted into the tlb (and thus flushed) anyways.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	addr = (unsigned long) page_address(page);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_data_cache_page(addr);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(__flush_dcache_page);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __update_cache(struct vm_area_struct *vma, unsigned long address,
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pte_t pte)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page *page;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long pfn, addr;
96585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle	int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pfn = pte_pfn(pte);
99585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle	if (unlikely(!pfn_valid(pfn)))
100585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle		return;
101585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle	page = pfn_to_page(pfn);
102585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle	if (page_mapping(page) && Page_dcache_dirty(page)) {
103585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle		addr = (unsigned long) page_address(page);
104585fa72493edd7d5acb308806e7bb609412c6228Ralf Baechle		if (exec || pages_do_alias(addr, address & PAGE_MASK))
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flush_data_cache_page(addr);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ClearPageDcacheDirty(page);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11002cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle#define __weak __attribute__((weak))
11102cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
11202cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechlestatic char cache_panic[] __initdata = "Yeee, unsupported cache architecture.";
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init cpu_cache_init(void)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11602cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_3k_cache) {
11702cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak r3k_cache_init(void);
11802cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
11902cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		r3k_cache_init();
12002cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
12102cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	}
12202cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_6k_cache) {
12302cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak r6k_cache_init(void);
12402cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
12502cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		r6k_cache_init();
12602cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12802cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_4k_cache) {
12902cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak r4k_cache_init(void);
13002cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
13102cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		r4k_cache_init();
13202cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
13302cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	}
13402cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_8k_cache) {
13502cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak r8k_cache_init(void);
13602cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
13702cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		r8k_cache_init();
13802cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
13902cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	}
14002cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_tx39_cache) {
14102cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak tx39_cache_init(void);
14202cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
14302cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		tx39_cache_init();
14402cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
14502cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	}
14602cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	if (cpu_has_sb1_cache) {
14702cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		extern void __weak sb1_cache_init(void);
14802cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
14902cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		sb1_cache_init();
15002cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle		return;
15102cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	}
15202cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle
15302cf2119684e52e97a8a90bd7630386e0f1a250aRalf Baechle	panic(cache_panic);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
155