2 * Copyright (C) 2004-2006 Atmel Corporation
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.
9 #include <linux/highmem.h>
10 #include <linux/unistd.h>
12 #include <asm/cacheflush.h>
13 #include <asm/cachectl.h>
14 #include <asm/processor.h>
15 #include <asm/uaccess.h>
18 * If you attempt to flush anything more than this, you need superuser
19 * privileges. The value is completely arbitrary.
21 #define CACHEFLUSH_MAX_LEN 1024
23 void invalidate_dcache_region(void *start
, size_t size
)
25 unsigned long v
, begin
, end
, linesz
;
27 linesz
= boot_cpu_data
.dcache
.linesz
;
29 //printk("invalidate dcache: %p + %u\n", start, size);
31 /* You asked for it, you got it */
32 begin
= (unsigned long)start
& ~(linesz
- 1);
33 end
= ((unsigned long)start
+ size
+ linesz
- 1) & ~(linesz
- 1);
35 for (v
= begin
; v
< end
; v
+= linesz
)
36 invalidate_dcache_line((void *)v
);
39 void clean_dcache_region(void *start
, size_t size
)
41 unsigned long v
, begin
, end
, linesz
;
43 linesz
= boot_cpu_data
.dcache
.linesz
;
44 begin
= (unsigned long)start
& ~(linesz
- 1);
45 end
= ((unsigned long)start
+ size
+ linesz
- 1) & ~(linesz
- 1);
47 for (v
= begin
; v
< end
; v
+= linesz
)
48 clean_dcache_line((void *)v
);
52 void flush_dcache_region(void *start
, size_t size
)
54 unsigned long v
, begin
, end
, linesz
;
56 linesz
= boot_cpu_data
.dcache
.linesz
;
57 begin
= (unsigned long)start
& ~(linesz
- 1);
58 end
= ((unsigned long)start
+ size
+ linesz
- 1) & ~(linesz
- 1);
60 for (v
= begin
; v
< end
; v
+= linesz
)
61 flush_dcache_line((void *)v
);
65 void invalidate_icache_region(void *start
, size_t size
)
67 unsigned long v
, begin
, end
, linesz
;
69 linesz
= boot_cpu_data
.icache
.linesz
;
70 begin
= (unsigned long)start
& ~(linesz
- 1);
71 end
= ((unsigned long)start
+ size
+ linesz
- 1) & ~(linesz
- 1);
73 for (v
= begin
; v
< end
; v
+= linesz
)
74 invalidate_icache_line((void *)v
);
77 static inline void __flush_icache_range(unsigned long start
, unsigned long end
)
79 unsigned long v
, linesz
;
81 linesz
= boot_cpu_data
.dcache
.linesz
;
82 for (v
= start
; v
< end
; v
+= linesz
) {
83 clean_dcache_line((void *)v
);
84 invalidate_icache_line((void *)v
);
91 * This one is called after a module has been loaded.
93 void flush_icache_range(unsigned long start
, unsigned long end
)
97 linesz
= boot_cpu_data
.dcache
.linesz
;
98 __flush_icache_range(start
& ~(linesz
- 1),
99 (end
+ linesz
- 1) & ~(linesz
- 1));
103 * This one is called from do_no_page(), do_swap_page() and install_page().
105 void flush_icache_page(struct vm_area_struct
*vma
, struct page
*page
)
107 if (vma
->vm_flags
& VM_EXEC
) {
108 void *v
= kmap(page
);
109 __flush_icache_range((unsigned long)v
, (unsigned long)v
+ PAGE_SIZE
);
115 * This one is used by copy_to_user_page()
117 void flush_icache_user_range(struct vm_area_struct
*vma
, struct page
*page
,
118 unsigned long addr
, int len
)
120 if (vma
->vm_flags
& VM_EXEC
)
121 flush_icache_range(addr
, addr
+ len
);
124 asmlinkage
int sys_cacheflush(int operation
, void __user
*addr
, size_t len
)
128 if (len
> CACHEFLUSH_MAX_LEN
) {
130 if (!capable(CAP_SYS_ADMIN
))
135 if (!access_ok(VERIFY_WRITE
, addr
, len
))
140 flush_icache_range((unsigned long)addr
,
141 (unsigned long)addr
+ len
);