blob: c8950861ed779c5da127fbc562bc03ee58a72d55 [file] [log] [blame]
Akira Takeuchi9731d232010-10-27 17:28:45 +01001/* MN10300 CPU cache invalidation routines, using automatic purge registers
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sys.h>
12#include <linux/linkage.h>
13#include <asm/smp.h>
14#include <asm/page.h>
15#include <asm/cache.h>
16#include <asm/irqflags.h>
17#include <asm/cacheflush.h>
18
19#define mn10300_local_dcache_inv_range_intr_interval \
20 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
21
22#if mn10300_local_dcache_inv_range_intr_interval > 0xff
23#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
24#endif
25
26 .am33_2
27
28#ifndef CONFIG_SMP
29 .globl mn10300_icache_inv
30 .globl mn10300_icache_inv_page
31 .globl mn10300_icache_inv_range
32 .globl mn10300_icache_inv_range2
33 .globl mn10300_dcache_inv
34 .globl mn10300_dcache_inv_page
35 .globl mn10300_dcache_inv_range
36 .globl mn10300_dcache_inv_range2
37
38mn10300_icache_inv = mn10300_local_icache_inv
39mn10300_icache_inv_page = mn10300_local_icache_inv_page
40mn10300_icache_inv_range = mn10300_local_icache_inv_range
41mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
42mn10300_dcache_inv = mn10300_local_dcache_inv
43mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
44mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
45mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
46
47#endif /* !CONFIG_SMP */
48
49###############################################################################
50#
51# void mn10300_local_icache_inv(void)
52# Invalidate the entire icache
53#
54###############################################################################
55 ALIGN
56 .globl mn10300_local_icache_inv
57 .type mn10300_local_icache_inv,@function
58mn10300_local_icache_inv:
59 mov CHCTR,a0
60
61 movhu (a0),d0
62 btst CHCTR_ICEN,d0
63 beq mn10300_local_icache_inv_end
64
65 # invalidate
66 or CHCTR_ICINV,d0
67 movhu d0,(a0)
68 movhu (a0),d0
69
70mn10300_local_icache_inv_end:
71 ret [],0
72 .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
73
74###############################################################################
75#
76# void mn10300_local_dcache_inv(void)
77# Invalidate the entire dcache
78#
79###############################################################################
80 ALIGN
81 .globl mn10300_local_dcache_inv
82 .type mn10300_local_dcache_inv,@function
83mn10300_local_dcache_inv:
84 mov CHCTR,a0
85
86 movhu (a0),d0
87 btst CHCTR_DCEN,d0
88 beq mn10300_local_dcache_inv_end
89
90 # invalidate
91 or CHCTR_DCINV,d0
92 movhu d0,(a0)
93 movhu (a0),d0
94
95mn10300_local_dcache_inv_end:
96 ret [],0
97 .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
98
99###############################################################################
100#
101# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
102# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
103# void mn10300_local_dcache_inv_page(unsigned long start)
104# Invalidate a range of addresses on a page in the dcache
105#
106###############################################################################
107 ALIGN
108 .globl mn10300_local_dcache_inv_page
109 .globl mn10300_local_dcache_inv_range
110 .globl mn10300_local_dcache_inv_range2
111 .type mn10300_local_dcache_inv_page,@function
112 .type mn10300_local_dcache_inv_range,@function
113 .type mn10300_local_dcache_inv_range2,@function
114mn10300_local_dcache_inv_page:
115 and ~(PAGE_SIZE-1),d0
116 mov PAGE_SIZE,d1
117mn10300_local_dcache_inv_range2:
118 add d0,d1
119mn10300_local_dcache_inv_range:
120 # If we are in writeback mode we check the start and end alignments,
121 # and if they're not cacheline-aligned, we must flush any bits outside
122 # the range that share cachelines with stuff inside the range
123#ifdef CONFIG_MN10300_CACHE_WBACK
124 btst ~(L1_CACHE_BYTES-1),d0
125 bne 1f
126 btst ~(L1_CACHE_BYTES-1),d1
127 beq 2f
1281:
129 bra mn10300_local_dcache_flush_inv_range
1302:
131#endif /* CONFIG_MN10300_CACHE_WBACK */
132
133 movm [d2,d3,a2],(sp)
134
135 mov CHCTR,a0
136 movhu (a0),d2
137 btst CHCTR_DCEN,d2
138 beq mn10300_local_dcache_inv_range_end
139
140 # round the addresses out to be full cachelines, unless we're in
141 # writeback mode, in which case we would be in flush and invalidate by
142 # now
143#ifndef CONFIG_MN10300_CACHE_WBACK
144 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
145 # addr down
146
147 mov L1_CACHE_BYTES-1,d2
148 add d2,d1
149 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up
150#endif /* !CONFIG_MN10300_CACHE_WBACK */
151
152 sub d0,d1,d2 # calculate the total size
153 mov d0,a2 # A2 = start address
154 mov d1,a1 # A1 = end address
155
156 LOCAL_CLI_SAVE(d3)
157
158 mov DCPGCR,a0 # make sure the purger isn't busy
159 setlb
160 mov (a0),d0
161 btst DCPGCR_DCPGBSY,d0
162 lne
163
164 # skip initial address alignment calculation if address is zero
165 mov d2,d1
166 cmp 0,a2
167 beq 1f
168
169dcivloop:
170 /* calculate alignsize
171 *
172 * alignsize = L1_CACHE_BYTES;
173 * while (! start & alignsize) {
174 * alignsize <<=1;
175 * }
176 * d1 = alignsize;
177 */
178 mov L1_CACHE_BYTES,d1
179 lsr 1,d1
180 setlb
181 add d1,d1
182 mov d1,d0
183 and a2,d0
184 leq
185
1861:
187 /* calculate invsize
188 *
189 * if (totalsize > alignsize) {
190 * invsize = alignsize;
191 * } else {
192 * invsize = totalsize;
193 * tmp = 0x80000000;
194 * while (! invsize & tmp) {
195 * tmp >>= 1;
196 * }
197 * invsize = tmp;
198 * }
199 * d1 = invsize
200 */
201 cmp d2,d1
202 bns 2f
203 mov d2,d1
204
205 mov 0x80000000,d0 # start from 31bit=1
206 setlb
207 lsr 1,d0
208 mov d0,e0
209 and d1,e0
210 leq
211 mov d0,d1
212
2132:
214 /* set mask
215 *
216 * mask = ~(invsize-1);
217 * DCPGMR = mask;
218 */
219 mov d1,d0
220 add -1,d0
221 not d0
222 mov d0,(DCPGMR)
223
224 # invalidate area
225 mov a2,d0
226 or DCPGCR_DCI,d0
227 mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
228
229 setlb # wait for the purge to complete
230 mov (a0),d0
231 btst DCPGCR_DCPGBSY,d0
232 lne
233
234 sub d1,d2 # decrease size remaining
235 add d1,a2 # increase next start address
236
237 /* check invalidating of end address
238 *
239 * a2 = a2 + invsize
240 * if (a2 < end) {
241 * goto dcivloop;
242 * } */
243 cmp a1,a2
244 bns dcivloop
245
246 LOCAL_IRQ_RESTORE(d3)
247
248mn10300_local_dcache_inv_range_end:
249 ret [d2,d3,a2],12
250 .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
251 .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
252 .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
253
254###############################################################################
255#
256# void mn10300_local_icache_inv_page(unsigned long start)
257# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
258# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
259# Invalidate a range of addresses on a page in the icache
260#
261###############################################################################
262 ALIGN
263 .globl mn10300_local_icache_inv_page
264 .globl mn10300_local_icache_inv_range
265 .globl mn10300_local_icache_inv_range2
266 .type mn10300_local_icache_inv_page,@function
267 .type mn10300_local_icache_inv_range,@function
268 .type mn10300_local_icache_inv_range2,@function
269mn10300_local_icache_inv_page:
270 and ~(PAGE_SIZE-1),d0
271 mov PAGE_SIZE,d1
272mn10300_local_icache_inv_range2:
273 add d0,d1
274mn10300_local_icache_inv_range:
275 movm [d2,d3,a2],(sp)
276
277 mov CHCTR,a0
278 movhu (a0),d2
279 btst CHCTR_ICEN,d2
280 beq mn10300_local_icache_inv_range_reg_end
281
282 /* calculate alignsize
283 *
284 * alignsize = L1_CACHE_BYTES;
285 * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
286 * alignsize <<= 1;
287 * }
288 * d2 = alignsize;
289 */
290 mov L1_CACHE_BYTES,d2
291 sub d0,d1,d3
292 add -1,d3
293 lsr L1_CACHE_SHIFT,d3
294 beq 2f
2951:
296 add d2,d2
297 lsr 1,d3
298 bne 1b
2992:
300
301 /* a1 = end */
302 mov d1,a1
303
304 LOCAL_CLI_SAVE(d3)
305
306 mov ICIVCR,a0
307 /* wait for busy bit of area invalidation */
308 setlb
309 mov (a0),d1
310 btst ICIVCR_ICIVBSY,d1
311 lne
312
313 /* set mask
314 *
315 * mask = ~(alignsize-1);
316 * ICIVMR = mask;
317 */
318 mov d2,d1
319 add -1,d1
320 not d1
321 mov d1,(ICIVMR)
322 /* a2 = mask & start */
323 and d1,d0,a2
324
325icivloop:
326 /* area invalidate
327 *
328 * ICIVCR = (mask & start) | ICIVCR_ICI
329 */
330 mov a2,d0
331 or ICIVCR_ICI,d0
332 mov d0,(a0)
333
334 /* wait for busy bit of area invalidation */
335 setlb
336 mov (a0),d1
337 btst ICIVCR_ICIVBSY,d1
338 lne
339
340 /* check invalidating of end address
341 *
342 * a2 = a2 + alignsize
343 * if (a2 < end) {
344 * goto icivloop;
345 * } */
346 add d2,a2
347 cmp a1,a2
348 bns icivloop
349
350 LOCAL_IRQ_RESTORE(d3)
351
352mn10300_local_icache_inv_range_reg_end:
353 ret [d2,d3,a2],12
354 .size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
355 .size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
356 .size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2