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>
20 #define mn10300_local_dcache_inv_range_intr_interval \
21 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
23 #if mn10300_local_dcache_inv_range_intr_interval > 0xff
24 #error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
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
39 mn10300_icache_inv = mn10300_local_icache_inv
40 mn10300_icache_inv_page = mn10300_local_icache_inv_page
41 mn10300_icache_inv_range = mn10300_local_icache_inv_range
42 mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
43 mn10300_dcache_inv = mn10300_local_dcache_inv
44 mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
45 mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
46 mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
48 #endif /* !CONFIG_SMP */
50 ###############################################################################
52 # void mn10300_local_icache_inv(void)
53 # Invalidate the entire icache
55 ###############################################################################
57 .globl mn10300_local_icache_inv
58 .type mn10300_local_icache_inv,@function
59 mn10300_local_icache_inv:
64 beq mn10300_local_icache_inv_end
68 mn10300_local_icache_inv_end:
70 .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
72 ###############################################################################
74 # void mn10300_local_dcache_inv(void)
75 # Invalidate the entire dcache
77 ###############################################################################
79 .globl mn10300_local_dcache_inv
80 .type mn10300_local_dcache_inv,@function
81 mn10300_local_dcache_inv:
86 beq mn10300_local_dcache_inv_end
90 mn10300_local_dcache_inv_end:
92 .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
94 ###############################################################################
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
101 ###############################################################################
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
109 mn10300_local_dcache_inv_page:
110 and ~(PAGE_SIZE-1),d0
112 mn10300_local_dcache_inv_range2:
114 mn10300_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
121 btst ~(L1_CACHE_BYTES-1),d1
124 bra mn10300_local_dcache_flush_inv_range
126 #endif /* CONFIG_MN10300_CACHE_WBACK */
133 beq mn10300_local_dcache_inv_range_end
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
138 #ifndef CONFIG_MN10300_CACHE_WBACK
139 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
142 mov L1_CACHE_BYTES-1,d2
144 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up
145 #endif /* !CONFIG_MN10300_CACHE_WBACK */
147 sub d0,d1,d2 # calculate the total size
148 mov d0,a2 # A2 = start address
149 mov d1,a1 # A1 = end address
153 mov DCPGCR,a0 # make sure the purger isn't busy
156 btst DCPGCR_DCPGBSY,d0
159 # skip initial address alignment calculation if address is zero
165 /* calculate alignsize
167 * alignsize = L1_CACHE_BYTES;
168 * while (! start & alignsize) {
173 mov L1_CACHE_BYTES,d1
184 * if (totalsize > alignsize) {
185 * invsize = alignsize;
187 * invsize = totalsize;
189 * while (! invsize & tmp) {
200 mov 0x80000000,d0 # start from 31bit=1
211 * mask = ~(invsize-1);
222 mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
224 setlb # wait for the purge to complete
226 btst DCPGCR_DCPGBSY,d0
229 sub d1,d2 # decrease size remaining
230 add d1,a2 # increase next start address
232 /* check invalidating of end address
241 LOCAL_IRQ_RESTORE(d3)
243 mn10300_local_dcache_inv_range_end:
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
249 ###############################################################################
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
256 ###############################################################################
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
264 mn10300_local_icache_inv_page:
265 and ~(PAGE_SIZE-1),d0
267 mn10300_local_icache_inv_range2:
269 mn10300_local_icache_inv_range:
275 beq mn10300_local_icache_inv_range_reg_end
277 /* calculate alignsize
279 * alignsize = L1_CACHE_BYTES;
280 * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
285 mov L1_CACHE_BYTES,d2
288 lsr L1_CACHE_SHIFT,d3
302 /* wait for busy bit of area invalidation */
305 btst ICIVCR_ICIVBSY,d1
310 * mask = ~(alignsize-1);
317 /* a2 = mask & start */
323 * ICIVCR = (mask & start) | ICIVCR_ICI
329 /* wait for busy bit of area invalidation */
332 btst ICIVCR_ICIVBSY,d1
335 /* check invalidating of end address
337 * a2 = a2 + alignsize
345 LOCAL_IRQ_RESTORE(d3)
347 mn10300_local_icache_inv_range_reg_end:
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