1/* 2 * Copyright (C) 2004-2006 Atmel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/highmem.h> 10#include <linux/unistd.h> 11 12#include <asm/cacheflush.h> 13#include <asm/cachectl.h> 14#include <asm/processor.h> 15#include <asm/uaccess.h> 16 17/* 18 * If you attempt to flush anything more than this, you need superuser 19 * privileges. The value is completely arbitrary. 20 */ 21#define CACHEFLUSH_MAX_LEN 1024 22 23void invalidate_dcache_region(void *start, size_t size) 24{ 25 unsigned long v, begin, end, linesz, mask; 26 27 linesz = boot_cpu_data.dcache.linesz; 28 mask = linesz - 1; 29 30 /* when first and/or last cachelines are shared, flush them 31 * instead of invalidating ... never discard valid data! 32 */ 33 begin = (unsigned long)start; 34 end = begin + size; 35 36 if (begin & mask) { 37 flush_dcache_line(start); 38 begin += linesz; 39 } 40 if (end & mask) { 41 flush_dcache_line((void *)end); 42 end &= ~mask; 43 } 44 45 /* remaining cachelines only need invalidation */ 46 for (v = begin; v < end; v += linesz) 47 invalidate_dcache_line((void *)v); 48 flush_write_buffer(); 49} 50 51void clean_dcache_region(void *start, size_t size) 52{ 53 unsigned long v, begin, end, linesz; 54 55 linesz = boot_cpu_data.dcache.linesz; 56 begin = (unsigned long)start & ~(linesz - 1); 57 end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); 58 59 for (v = begin; v < end; v += linesz) 60 clean_dcache_line((void *)v); 61 flush_write_buffer(); 62} 63 64void flush_dcache_region(void *start, size_t size) 65{ 66 unsigned long v, begin, end, linesz; 67 68 linesz = boot_cpu_data.dcache.linesz; 69 begin = (unsigned long)start & ~(linesz - 1); 70 end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); 71 72 for (v = begin; v < end; v += linesz) 73 flush_dcache_line((void *)v); 74 flush_write_buffer(); 75} 76 77void invalidate_icache_region(void *start, size_t size) 78{ 79 unsigned long v, begin, end, linesz; 80 81 linesz = boot_cpu_data.icache.linesz; 82 begin = (unsigned long)start & ~(linesz - 1); 83 end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); 84 85 for (v = begin; v < end; v += linesz) 86 invalidate_icache_line((void *)v); 87} 88 89static inline void __flush_icache_range(unsigned long start, unsigned long end) 90{ 91 unsigned long v, linesz; 92 93 linesz = boot_cpu_data.dcache.linesz; 94 for (v = start; v < end; v += linesz) { 95 clean_dcache_line((void *)v); 96 invalidate_icache_line((void *)v); 97 } 98 99 flush_write_buffer(); 100} 101 102/* 103 * This one is called after a module has been loaded. 104 */ 105void flush_icache_range(unsigned long start, unsigned long end) 106{ 107 unsigned long linesz; 108 109 linesz = boot_cpu_data.dcache.linesz; 110 __flush_icache_range(start & ~(linesz - 1), 111 (end + linesz - 1) & ~(linesz - 1)); 112} 113 114/* 115 * This one is called from do_no_page(), do_swap_page() and install_page(). 116 */ 117void flush_icache_page(struct vm_area_struct *vma, struct page *page) 118{ 119 if (vma->vm_flags & VM_EXEC) { 120 void *v = page_address(page); 121 __flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE); 122 } 123} 124 125/* 126 * This one is used by copy_to_user_page() 127 */ 128void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, 129 unsigned long addr, int len) 130{ 131 if (vma->vm_flags & VM_EXEC) 132 flush_icache_range(addr, addr + len); 133} 134 135asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len) 136{ 137 int ret; 138 139 if (len > CACHEFLUSH_MAX_LEN) { 140 ret = -EPERM; 141 if (!capable(CAP_SYS_ADMIN)) 142 goto out; 143 } 144 145 ret = -EFAULT; 146 if (!access_ok(VERIFY_WRITE, addr, len)) 147 goto out; 148 149 switch (operation) { 150 case CACHE_IFLUSH: 151 flush_icache_range((unsigned long)addr, 152 (unsigned long)addr + len); 153 ret = 0; 154 break; 155 default: 156 ret = -EINVAL; 157 } 158 159out: 160 return ret; 161} 162