Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/avr32/mm/cache.c
10817 views
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
#include <asm/syscalls.h>
17
18
/*
19
* If you attempt to flush anything more than this, you need superuser
20
* privileges. The value is completely arbitrary.
21
*/
22
#define CACHEFLUSH_MAX_LEN 1024
23
24
void invalidate_dcache_region(void *start, size_t size)
25
{
26
unsigned long v, begin, end, linesz, mask;
27
28
linesz = boot_cpu_data.dcache.linesz;
29
mask = linesz - 1;
30
31
/* when first and/or last cachelines are shared, flush them
32
* instead of invalidating ... never discard valid data!
33
*/
34
begin = (unsigned long)start;
35
end = begin + size;
36
37
if (begin & mask) {
38
flush_dcache_line(start);
39
begin += linesz;
40
}
41
if (end & mask) {
42
flush_dcache_line((void *)end);
43
end &= ~mask;
44
}
45
46
/* remaining cachelines only need invalidation */
47
for (v = begin; v < end; v += linesz)
48
invalidate_dcache_line((void *)v);
49
flush_write_buffer();
50
}
51
52
void clean_dcache_region(void *start, size_t size)
53
{
54
unsigned long v, begin, end, linesz;
55
56
linesz = boot_cpu_data.dcache.linesz;
57
begin = (unsigned long)start & ~(linesz - 1);
58
end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
59
60
for (v = begin; v < end; v += linesz)
61
clean_dcache_line((void *)v);
62
flush_write_buffer();
63
}
64
65
void flush_dcache_region(void *start, size_t size)
66
{
67
unsigned long v, begin, end, linesz;
68
69
linesz = boot_cpu_data.dcache.linesz;
70
begin = (unsigned long)start & ~(linesz - 1);
71
end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
72
73
for (v = begin; v < end; v += linesz)
74
flush_dcache_line((void *)v);
75
flush_write_buffer();
76
}
77
78
void invalidate_icache_region(void *start, size_t size)
79
{
80
unsigned long v, begin, end, linesz;
81
82
linesz = boot_cpu_data.icache.linesz;
83
begin = (unsigned long)start & ~(linesz - 1);
84
end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
85
86
for (v = begin; v < end; v += linesz)
87
invalidate_icache_line((void *)v);
88
}
89
90
static inline void __flush_icache_range(unsigned long start, unsigned long end)
91
{
92
unsigned long v, linesz;
93
94
linesz = boot_cpu_data.dcache.linesz;
95
for (v = start; v < end; v += linesz) {
96
clean_dcache_line((void *)v);
97
invalidate_icache_line((void *)v);
98
}
99
100
flush_write_buffer();
101
}
102
103
/*
104
* This one is called after a module has been loaded.
105
*/
106
void flush_icache_range(unsigned long start, unsigned long end)
107
{
108
unsigned long linesz;
109
110
linesz = boot_cpu_data.dcache.linesz;
111
__flush_icache_range(start & ~(linesz - 1),
112
(end + linesz - 1) & ~(linesz - 1));
113
}
114
115
/*
116
* This one is called from __do_fault() and do_swap_page().
117
*/
118
void flush_icache_page(struct vm_area_struct *vma, struct page *page)
119
{
120
if (vma->vm_flags & VM_EXEC) {
121
void *v = page_address(page);
122
__flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE);
123
}
124
}
125
126
asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
127
{
128
int ret;
129
130
if (len > CACHEFLUSH_MAX_LEN) {
131
ret = -EPERM;
132
if (!capable(CAP_SYS_ADMIN))
133
goto out;
134
}
135
136
ret = -EFAULT;
137
if (!access_ok(VERIFY_WRITE, addr, len))
138
goto out;
139
140
switch (operation) {
141
case CACHE_IFLUSH:
142
flush_icache_range((unsigned long)addr,
143
(unsigned long)addr + len);
144
ret = 0;
145
break;
146
default:
147
ret = -EINVAL;
148
}
149
150
out:
151
return ret;
152
}
153
154
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
155
unsigned long vaddr, void *dst, const void *src,
156
unsigned long len)
157
{
158
memcpy(dst, src, len);
159
if (vma->vm_flags & VM_EXEC)
160
flush_icache_range((unsigned long)dst,
161
(unsigned long)dst + len);
162
}
163
164