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