cache.c revision b920de1b77b72ca9432ac3f97edb26541e65e5dd
1/* MN10300 Cache flushing routines 2 * 3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11#include <linux/module.h> 12#include <linux/mm.h> 13#include <linux/mman.h> 14#include <linux/threads.h> 15#include <asm/page.h> 16#include <asm/pgtable.h> 17#include <asm/processor.h> 18#include <asm/cacheflush.h> 19#include <asm/io.h> 20#include <asm/uaccess.h> 21 22EXPORT_SYMBOL(mn10300_icache_inv); 23EXPORT_SYMBOL(mn10300_dcache_inv); 24EXPORT_SYMBOL(mn10300_dcache_inv_range); 25EXPORT_SYMBOL(mn10300_dcache_inv_range2); 26EXPORT_SYMBOL(mn10300_dcache_inv_page); 27 28#ifdef CONFIG_MN10300_CACHE_WBACK 29EXPORT_SYMBOL(mn10300_dcache_flush); 30EXPORT_SYMBOL(mn10300_dcache_flush_inv); 31EXPORT_SYMBOL(mn10300_dcache_flush_inv_range); 32EXPORT_SYMBOL(mn10300_dcache_flush_inv_range2); 33EXPORT_SYMBOL(mn10300_dcache_flush_inv_page); 34EXPORT_SYMBOL(mn10300_dcache_flush_range); 35EXPORT_SYMBOL(mn10300_dcache_flush_range2); 36EXPORT_SYMBOL(mn10300_dcache_flush_page); 37#endif 38 39/* 40 * write a page back from the dcache and invalidate the icache so that we can 41 * run code from it that we've just written into it 42 */ 43void flush_icache_page(struct vm_area_struct *vma, struct page *page) 44{ 45 mn10300_dcache_flush_page(page_to_phys(page)); 46 mn10300_icache_inv(); 47} 48EXPORT_SYMBOL(flush_icache_page); 49 50/* 51 * write some code we've just written back from the dcache and invalidate the 52 * icache so that we can run that code 53 */ 54void flush_icache_range(unsigned long start, unsigned long end) 55{ 56#ifdef CONFIG_MN10300_CACHE_WBACK 57 unsigned long addr, size, off; 58 struct page *page; 59 pgd_t *pgd; 60 pud_t *pud; 61 pmd_t *pmd; 62 pte_t *ppte, pte; 63 64 for (; start < end; start += size) { 65 /* work out how much of the page to flush */ 66 off = start & (PAGE_SIZE - 1); 67 68 size = end - start; 69 if (size > PAGE_SIZE - off) 70 size = PAGE_SIZE - off; 71 72 /* get the physical address the page is mapped to from the page 73 * tables */ 74 pgd = pgd_offset(current->mm, start); 75 if (!pgd || !pgd_val(*pgd)) 76 continue; 77 78 pud = pud_offset(pgd, start); 79 if (!pud || !pud_val(*pud)) 80 continue; 81 82 pmd = pmd_offset(pud, start); 83 if (!pmd || !pmd_val(*pmd)) 84 continue; 85 86 ppte = pte_offset_map(pmd, start); 87 if (!ppte) 88 continue; 89 pte = *ppte; 90 pte_unmap(ppte); 91 92 if (pte_none(pte)) 93 continue; 94 95 page = pte_page(pte); 96 if (!page) 97 continue; 98 99 addr = page_to_phys(page); 100 101 /* flush the dcache and invalidate the icache coverage on that 102 * region */ 103 mn10300_dcache_flush_range2(addr + off, size); 104 } 105#endif 106 107 mn10300_icache_inv(); 108} 109EXPORT_SYMBOL(flush_icache_range); 110 111/* 112 * allow userspace to flush the instruction cache 113 */ 114asmlinkage long sys_cacheflush(unsigned long start, unsigned long end) 115{ 116 if (end < start) 117 return -EINVAL; 118 119 flush_icache_range(start, end); 120 return 0; 121} 122