aboutsummaryrefslogtreecommitdiffstats
path: root/arch/score/mm/cache.c
diff options
context:
space:
mode:
authorChen Liqin <liqin.chen@sunplusct.com>2009-06-12 10:01:00 -0400
committerArnd Bergmann <arnd@arndb.de>2009-06-19 05:38:47 -0400
commit6bc9a3966f0395419b09b2ec90f89f7f00341b37 (patch)
tree9c0d9d5376020266f5602501c8376d4a4f13142d /arch/score/mm/cache.c
parent0732f87761dbe417cb6e084b712d07e879e876ef (diff)
score: Add support for Sunplus S+core architecture
This is the complete set of new arch Score's files for linux. Score instruction set support 16bits, 32bits and 64bits instruction, Score SOC had been used in game machine and LCD TV. Signed-off-by: Chen Liqin <liqin.chen@sunplusct.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/score/mm/cache.c')
-rw-r--r--arch/score/mm/cache.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/arch/score/mm/cache.c b/arch/score/mm/cache.c
new file mode 100644
index 000000000000..1ebc67f18c6d
--- /dev/null
+++ b/arch/score/mm/cache.c
@@ -0,0 +1,308 @@
1/*
2 * arch/score/mm/cache.c
3 *
4 * Score Processor version.
5 *
6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7 * Lennox Wu <lennox.wu@sunplusct.com>
8 * Chen Liqin <liqin.chen@sunplusct.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see the file COPYING, or write
22 * to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <linux/init.h>
27#include <linux/linkage.h>
28#include <linux/kernel.h>
29#include <linux/mm.h>
30#include <linux/module.h>
31#include <linux/sched.h>
32
33#include <asm/mmu_context.h>
34
35/* Cache operations. */
36void (*flush_cache_all)(void);
37void (*__flush_cache_all)(void);
38void (*flush_cache_mm)(struct mm_struct *mm);
39void (*flush_cache_range)(struct vm_area_struct *vma,
40 unsigned long start, unsigned long end);
41void (*flush_cache_page)(struct vm_area_struct *vma,
42 unsigned long page, unsigned long pfn);
43void (*flush_icache_range)(unsigned long start, unsigned long end);
44void (*__flush_cache_vmap)(void);
45void (*__flush_cache_vunmap)(void);
46void (*flush_cache_sigtramp)(unsigned long addr);
47void (*flush_data_cache_page)(unsigned long addr);
48EXPORT_SYMBOL(flush_data_cache_page);
49void (*flush_icache_all)(void);
50
51/*Score 7 cache operations*/
52static inline void s7___flush_cache_all(void);
53static void s7_flush_cache_mm(struct mm_struct *mm);
54static void s7_flush_cache_range(struct vm_area_struct *vma,
55 unsigned long start, unsigned long end);
56static void s7_flush_cache_page(struct vm_area_struct *vma,
57 unsigned long page, unsigned long pfn);
58static void s7_flush_icache_range(unsigned long start, unsigned long end);
59static void s7_flush_cache_sigtramp(unsigned long addr);
60static void s7_flush_data_cache_page(unsigned long addr);
61static void s7_flush_dcache_range(unsigned long start, unsigned long end);
62
63void __update_cache(struct vm_area_struct *vma, unsigned long address,
64 pte_t pte)
65{
66 struct page *page;
67 unsigned long pfn, addr;
68 int exec = (vma->vm_flags & VM_EXEC);
69
70 pfn = pte_pfn(pte);
71 if (unlikely(!pfn_valid(pfn)))
72 return;
73 page = pfn_to_page(pfn);
74 if (page_mapping(page) && test_bit(PG_arch_1, &page->flags)) {
75 addr = (unsigned long) page_address(page);
76 if (exec)
77 s7_flush_data_cache_page(addr);
78 clear_bit(PG_arch_1, &page->flags);
79 }
80}
81
82static inline void setup_protection_map(void)
83{
84 protection_map[0] = PAGE_NONE;
85 protection_map[1] = PAGE_READONLY;
86 protection_map[2] = PAGE_COPY;
87 protection_map[3] = PAGE_COPY;
88 protection_map[4] = PAGE_READONLY;
89 protection_map[5] = PAGE_READONLY;
90 protection_map[6] = PAGE_COPY;
91 protection_map[7] = PAGE_COPY;
92 protection_map[8] = PAGE_NONE;
93 protection_map[9] = PAGE_READONLY;
94 protection_map[10] = PAGE_SHARED;
95 protection_map[11] = PAGE_SHARED;
96 protection_map[12] = PAGE_READONLY;
97 protection_map[13] = PAGE_READONLY;
98 protection_map[14] = PAGE_SHARED;
99 protection_map[15] = PAGE_SHARED;
100}
101
102void __devinit cpu_cache_init(void)
103{
104 flush_cache_all = s7_flush_cache_all;
105 __flush_cache_all = s7___flush_cache_all;
106 flush_cache_mm = s7_flush_cache_mm;
107 flush_cache_range = s7_flush_cache_range;
108 flush_cache_page = s7_flush_cache_page;
109 flush_icache_range = s7_flush_icache_range;
110 flush_cache_sigtramp = s7_flush_cache_sigtramp;
111 flush_data_cache_page = s7_flush_data_cache_page;
112
113 setup_protection_map();
114}
115
116void s7_flush_icache_all(void)
117{
118 __asm__ __volatile__(
119 "la r8, s7_flush_icache_all\n"
120 "cache 0x10, [r8, 0]\n"
121 "nop\nnop\nnop\nnop\nnop\nnop\n"
122 : : : "r8");
123}
124
125void s7_flush_dcache_all(void)
126{
127 __asm__ __volatile__(
128 "la r8, s7_flush_dcache_all\n"
129 "cache 0x1f, [r8, 0]\n"
130 "nop\nnop\nnop\nnop\nnop\nnop\n"
131 "cache 0x1a, [r8, 0]\n"
132 "nop\nnop\nnop\nnop\nnop\nnop\n"
133 : : : "r8");
134}
135
136void s7_flush_cache_all(void)
137{
138 __asm__ __volatile__(
139 "la r8, s7_flush_cache_all\n"
140 "cache 0x10, [r8, 0]\n"
141 "nop\nnop\nnop\nnop\nnop\nnop\n"
142 "cache 0x1f, [r8, 0]\n"
143 "nop\nnop\nnop\nnop\nnop\nnop\n"
144 "cache 0x1a, [r8, 0]\n"
145 "nop\nnop\nnop\nnop\nnop\nnop\n"
146 : : : "r8");
147}
148
149void s7___flush_cache_all(void)
150{
151 __asm__ __volatile__(
152 "la r8, s7_flush_cache_all\n"
153 "cache 0x10, [r8, 0]\n"
154 "nop\nnop\nnop\nnop\nnop\nnop\n"
155 "cache 0x1f, [r8, 0]\n"
156 "nop\nnop\nnop\nnop\nnop\nnop\n"
157 "cache 0x1a, [r8, 0]\n"
158 "nop\nnop\nnop\nnop\nnop\nnop\n"
159 : : : "r8");
160}
161
162static void s7_flush_cache_mm(struct mm_struct *mm)
163{
164 if (!(mm->context))
165 return;
166 s7_flush_cache_all();
167}
168
169/*if we flush a range precisely , the processing may be very long.
170We must check each page in the range whether present. If the page is present,
171we can flush the range in the page. Be careful, the range may be cross two
172page, a page is present and another is not present.
173*/
174/*
175The interface is provided in hopes that the port can find
176a suitably efficient method for removing multiple page
177sized regions from the cache.
178*/
179static void
180s7_flush_cache_range(struct vm_area_struct *vma,
181 unsigned long start, unsigned long end)
182{
183 struct mm_struct *mm = vma->vm_mm;
184 int exec = vma->vm_flags & VM_EXEC;
185 pgd_t *pgdp;
186 pud_t *pudp;
187 pmd_t *pmdp;
188 pte_t *ptep;
189
190 if (!(mm->context))
191 return;
192
193 pgdp = pgd_offset(mm, start);
194 pudp = pud_offset(pgdp, start);
195 pmdp = pmd_offset(pudp, start);
196 ptep = pte_offset(pmdp, start);
197
198 while (start <= end) {
199 unsigned long tmpend;
200 pgdp = pgd_offset(mm, start);
201 pudp = pud_offset(pgdp, start);
202 pmdp = pmd_offset(pudp, start);
203 ptep = pte_offset(pmdp, start);
204
205 if (!(pte_val(*ptep) & _PAGE_PRESENT)) {
206 start = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
207 continue;
208 }
209 tmpend = (start | (PAGE_SIZE-1)) > end ?
210 end : (start | (PAGE_SIZE-1));
211
212 s7_flush_dcache_range(start, tmpend);
213 if (exec)
214 s7_flush_icache_range(start, tmpend);
215 start = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
216 }
217}
218
219static void
220s7_flush_cache_page(struct vm_area_struct *vma,
221 unsigned long addr, unsigned long pfn)
222{
223 int exec = vma->vm_flags & VM_EXEC;
224 unsigned long kaddr = 0xa0000000 | (pfn << PAGE_SHIFT);
225
226 s7_flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
227
228 if (exec)
229 s7_flush_icache_range(kaddr, kaddr + PAGE_SIZE);
230}
231
232static void s7_flush_cache_sigtramp(unsigned long addr)
233{
234 __asm__ __volatile__(
235 "cache 0x02, [%0, 0]\n"
236 "nop\nnop\nnop\nnop\nnop\n"
237 "cache 0x02, [%0, 0x4]\n"
238 "nop\nnop\nnop\nnop\nnop\n"
239
240 "cache 0x0d, [%0, 0]\n"
241 "nop\nnop\nnop\nnop\nnop\n"
242 "cache 0x0d, [%0, 0x4]\n"
243 "nop\nnop\nnop\nnop\nnop\n"
244
245 "cache 0x1a, [%0, 0]\n"
246 "nop\nnop\nnop\nnop\nnop\n"
247 : : "r" (addr));
248}
249
250/*
251Just flush entire Dcache!!
252You must ensure the page doesn't include instructions, because
253the function will not flush the Icache.
254The addr must be cache aligned.
255*/
256static void s7_flush_data_cache_page(unsigned long addr)
257{
258 unsigned int i;
259 for (i = 0; i < (PAGE_SIZE / L1_CACHE_BYTES); i += L1_CACHE_BYTES) {
260 __asm__ __volatile__(
261 "cache 0x0e, [%0, 0]\n"
262 "cache 0x1a, [%0, 0]\n"
263 "nop\n"
264 : : "r" (addr));
265 addr += L1_CACHE_BYTES;
266 }
267}
268
269/*
2701. WB and invalid a cache line of Dcache
2712. Drain Write Buffer
272the range must be smaller than PAGE_SIZE
273*/
274static void s7_flush_dcache_range(unsigned long start, unsigned long end)
275{
276 int size, i;
277
278 start = start & ~(L1_CACHE_BYTES - 1);
279 end = end & ~(L1_CACHE_BYTES - 1);
280 size = end - start;
281 /* flush dcache to ram, and invalidate dcache lines. */
282 for (i = 0; i < size; i += L1_CACHE_BYTES) {
283 __asm__ __volatile__(
284 "cache 0x0e, [%0, 0]\n"
285 "nop\nnop\nnop\nnop\nnop\n"
286 "cache 0x1a, [%0, 0]\n"
287 "nop\nnop\nnop\nnop\nnop\n"
288 : : "r" (start));
289 start += L1_CACHE_BYTES;
290 }
291}
292
293static void s7_flush_icache_range(unsigned long start, unsigned long end)
294{
295 int size, i;
296 start = start & ~(L1_CACHE_BYTES - 1);
297 end = end & ~(L1_CACHE_BYTES - 1);
298
299 size = end - start;
300 /* invalidate icache lines. */
301 for (i = 0; i < size; i += L1_CACHE_BYTES) {
302 __asm__ __volatile__(
303 "cache 0x02, [%0, 0]\n"
304 "nop\nnop\nnop\nnop\nnop\n"
305 : : "r" (start));
306 start += L1_CACHE_BYTES;
307 }
308}