Blame view

arch/avr32/mm/cache.c 3.73 KB
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Copyright (C) 2004-2006 Atmel Corporation
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/highmem.h>
  #include <linux/unistd.h>
  
  #include <asm/cacheflush.h>
  #include <asm/cachectl.h>
  #include <asm/processor.h>
  #include <asm/uaccess.h>
c80ce2d52   Jaswinder Singh   avr32: Introducin...
16
  #include <asm/syscalls.h>
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
17
18
19
20
21
22
23
24
25
  
  /*
   * If you attempt to flush anything more than this, you need superuser
   * privileges.  The value is completely arbitrary.
   */
  #define CACHEFLUSH_MAX_LEN	1024
  
  void invalidate_dcache_region(void *start, size_t size)
  {
212868d38   David Brownell   [AVR32] Fix incor...
26
  	unsigned long v, begin, end, linesz, mask;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
27
28
  
  	linesz = boot_cpu_data.dcache.linesz;
212868d38   David Brownell   [AVR32] Fix incor...
29
  	mask = linesz - 1;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
30

212868d38   David Brownell   [AVR32] Fix incor...
31
32
33
34
  	/* when first and/or last cachelines are shared, flush them
  	 * instead of invalidating ... never discard valid data!
  	 */
  	begin = (unsigned long)start;
ab61f7d21   Haavard Skinnemoen   [AVR32] Fix bug i...
35
  	end = begin + size;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
36

212868d38   David Brownell   [AVR32] Fix incor...
37
38
39
  	if (begin & mask) {
  		flush_dcache_line(start);
  		begin += linesz;
212868d38   David Brownell   [AVR32] Fix incor...
40
  	}
ab61f7d21   Haavard Skinnemoen   [AVR32] Fix bug i...
41
  	if (end & mask) {
212868d38   David Brownell   [AVR32] Fix incor...
42
  		flush_dcache_line((void *)end);
ab61f7d21   Haavard Skinnemoen   [AVR32] Fix bug i...
43
  		end &= ~mask;
212868d38   David Brownell   [AVR32] Fix incor...
44
  	}
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
45

212868d38   David Brownell   [AVR32] Fix incor...
46
  	/* remaining cachelines only need invalidation */
ab61f7d21   Haavard Skinnemoen   [AVR32] Fix bug i...
47
  	for (v = begin; v < end; v += linesz)
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
48
  		invalidate_dcache_line((void *)v);
ab61f7d21   Haavard Skinnemoen   [AVR32] Fix bug i...
49
  	flush_write_buffer();
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  }
  
  void clean_dcache_region(void *start, size_t size)
  {
  	unsigned long v, begin, end, linesz;
  
  	linesz = boot_cpu_data.dcache.linesz;
  	begin = (unsigned long)start & ~(linesz - 1);
  	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
  
  	for (v = begin; v < end; v += linesz)
  		clean_dcache_line((void *)v);
  	flush_write_buffer();
  }
  
  void flush_dcache_region(void *start, size_t size)
  {
  	unsigned long v, begin, end, linesz;
  
  	linesz = boot_cpu_data.dcache.linesz;
  	begin = (unsigned long)start & ~(linesz - 1);
  	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
  
  	for (v = begin; v < end; v += linesz)
  		flush_dcache_line((void *)v);
  	flush_write_buffer();
  }
  
  void invalidate_icache_region(void *start, size_t size)
  {
  	unsigned long v, begin, end, linesz;
  
  	linesz = boot_cpu_data.icache.linesz;
  	begin = (unsigned long)start & ~(linesz - 1);
  	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
  
  	for (v = begin; v < end; v += linesz)
  		invalidate_icache_line((void *)v);
  }
  
  static inline void __flush_icache_range(unsigned long start, unsigned long end)
  {
  	unsigned long v, linesz;
  
  	linesz = boot_cpu_data.dcache.linesz;
  	for (v = start; v < end; v += linesz) {
  		clean_dcache_line((void *)v);
  		invalidate_icache_line((void *)v);
  	}
  
  	flush_write_buffer();
  }
  
  /*
   * This one is called after a module has been loaded.
   */
  void flush_icache_range(unsigned long start, unsigned long end)
  {
  	unsigned long linesz;
  
  	linesz = boot_cpu_data.dcache.linesz;
  	__flush_icache_range(start & ~(linesz - 1),
  			     (end + linesz - 1) & ~(linesz - 1));
  }
  
  /*
a335b2e17   Ryota Ozaki   mm: Fix out-of-da...
116
   * This one is called from __do_fault() and do_swap_page().
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
117
118
119
120
   */
  void flush_icache_page(struct vm_area_struct *vma, struct page *page)
  {
  	if (vma->vm_flags & VM_EXEC) {
28c1d39db   Haavard Skinnemoen   [AVR32] Don't use...
121
  		void *v = page_address(page);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
122
  		__flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
123
124
  	}
  }
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
  {
  	int ret;
  
  	if (len > CACHEFLUSH_MAX_LEN) {
  		ret = -EPERM;
  		if (!capable(CAP_SYS_ADMIN))
  			goto out;
  	}
  
  	ret = -EFAULT;
  	if (!access_ok(VERIFY_WRITE, addr, len))
  		goto out;
  
  	switch (operation) {
  	case CACHE_IFLUSH:
  		flush_icache_range((unsigned long)addr,
  				   (unsigned long)addr + len);
  		ret = 0;
  		break;
  	default:
  		ret = -EINVAL;
  	}
  
  out:
  	return ret;
  }
68ca3e537   Haavard Skinnemoen   [AVR32] Fix copy_...
152
153
154
155
156
157
158
159
160
161
  
  void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
  		unsigned long vaddr, void *dst, const void *src,
  		unsigned long len)
  {
  	memcpy(dst, src, len);
  	if (vma->vm_flags & VM_EXEC)
  		flush_icache_range((unsigned long)dst,
  				(unsigned long)dst + len);
  }