1 /* MN10300 CPU cache invalidation routines, using automatic purge registers
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
11 #include <linux/sys.h>
12 #include <linux/linkage.h>
15 #include <asm/cache.h>
16 #include <asm/irqflags.h>
17 #include <asm/cacheflush.h>
19 #define mn10300_local_dcache_inv_range_intr_interval \
20 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
22 #if mn10300_local_dcache_inv_range_intr_interval > 0xff
23 #error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
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
38 mn10300_icache_inv = mn10300_local_icache_inv
39 mn10300_icache_inv_page = mn10300_local_icache_inv_page
40 mn10300_icache_inv_range = mn10300_local_icache_inv_range
41 mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
42 mn10300_dcache_inv = mn10300_local_dcache_inv
43 mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
44 mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
45 mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
47 #endif /* !CONFIG_SMP */
49 ###############################################################################
51 # void mn10300_local_icache_inv(void)
52 # Invalidate the entire icache
54 ###############################################################################
56 .globl mn10300_local_icache_inv
57 .type mn10300_local_icache_inv,@function
58 mn10300_local_icache_inv:
63 beq mn10300_local_icache_inv_end
70 mn10300_local_icache_inv_end:
72 .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
74 ###############################################################################
76 # void mn10300_local_dcache_inv(void)
77 # Invalidate the entire dcache
79 ###############################################################################
81 .globl mn10300_local_dcache_inv
82 .type mn10300_local_dcache_inv,@function
83 mn10300_local_dcache_inv:
88 beq mn10300_local_dcache_inv_end
95 mn10300_local_dcache_inv_end:
97 .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
99 ###############################################################################
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
106 ###############################################################################
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
114 mn10300_local_dcache_inv_page:
115 and ~(PAGE_SIZE-1),d0
117 mn10300_local_dcache_inv_range2:
119 mn10300_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
126 btst ~(L1_CACHE_BYTES-1),d1
129 bra mn10300_local_dcache_flush_inv_range
131 #endif /* CONFIG_MN10300_CACHE_WBACK */
138 beq mn10300_local_dcache_inv_range_end
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
143 #ifndef CONFIG_MN10300_CACHE_WBACK
144 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
147 mov L1_CACHE_BYTES-1,d2
149 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up
150 #endif /* !CONFIG_MN10300_CACHE_WBACK */
152 sub d0,d1,d2 # calculate the total size
153 mov d0,a2 # A2 = start address
154 mov d1,a1 # A1 = end address
158 mov DCPGCR,a0 # make sure the purger isn't busy
161 btst DCPGCR_DCPGBSY,d0
164 # skip initial address alignment calculation if address is zero
170 /* calculate alignsize
172 * alignsize = L1_CACHE_BYTES;
173 * while (! start & alignsize) {
178 mov L1_CACHE_BYTES,d1
189 * if (totalsize > alignsize) {
190 * invsize = alignsize;
192 * invsize = totalsize;
194 * while (! invsize & tmp) {
205 mov 0x80000000,d0 # start from 31bit=1
216 * mask = ~(invsize-1);
227 mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
229 setlb # wait for the purge to complete
231 btst DCPGCR_DCPGBSY,d0
234 sub d1,d2 # decrease size remaining
235 add d1,a2 # increase next start address
237 /* check invalidating of end address
246 LOCAL_IRQ_RESTORE(d3)
248 mn10300_local_dcache_inv_range_end:
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
254 ###############################################################################
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
261 ###############################################################################
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
269 mn10300_local_icache_inv_page:
270 and ~(PAGE_SIZE-1),d0
272 mn10300_local_icache_inv_range2:
274 mn10300_local_icache_inv_range:
280 beq mn10300_local_icache_inv_range_reg_end
282 /* calculate alignsize
284 * alignsize = L1_CACHE_BYTES;
285 * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
290 mov L1_CACHE_BYTES,d2
293 lsr L1_CACHE_SHIFT,d3
307 /* wait for busy bit of area invalidation */
310 btst ICIVCR_ICIVBSY,d1
315 * mask = ~(alignsize-1);
322 /* a2 = mask & start */
328 * ICIVCR = (mask & start) | ICIVCR_ICI
334 /* wait for busy bit of area invalidation */
337 btst ICIVCR_ICIVBSY,d1
340 /* check invalidating of end address
342 * a2 = a2 + alignsize
350 LOCAL_IRQ_RESTORE(d3)
352 mn10300_local_icache_inv_range_reg_end:
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