MN10300: The icache invalidate functions should disable the icache first
[linux-2.6/x86.git] / arch / mn10300 / mm / cache-inv-by-reg.S
blobd1f363a8d36b945f4d106d79ed310d53b00517b0
1 /* 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 #include "cache.inc"
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
25 #endif
27         .am33_2
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
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 ###############################################################################
56         ALIGN
57         .globl  mn10300_local_icache_inv
58         .type   mn10300_local_icache_inv,@function
59 mn10300_local_icache_inv:
60         mov     CHCTR,a0
62         movhu   (a0),d0
63         btst    CHCTR_ICEN,d0
64         beq     mn10300_local_icache_inv_end
66         invalidate_icache 1
68 mn10300_local_icache_inv_end:
69         ret     [],0
70         .size   mn10300_local_icache_inv,.-mn10300_local_icache_inv
72 ###############################################################################
74 # void mn10300_local_dcache_inv(void)
75 # Invalidate the entire dcache
77 ###############################################################################
78         ALIGN
79         .globl  mn10300_local_dcache_inv
80         .type   mn10300_local_dcache_inv,@function
81 mn10300_local_dcache_inv:
82         mov     CHCTR,a0
84         movhu   (a0),d0
85         btst    CHCTR_DCEN,d0
86         beq     mn10300_local_dcache_inv_end
88         invalidate_dcache 1
89         
90 mn10300_local_dcache_inv_end:
91         ret     [],0
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 ###############################################################################
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
109 mn10300_local_dcache_inv_page:
110         and     ~(PAGE_SIZE-1),d0
111         mov     PAGE_SIZE,d1
112 mn10300_local_dcache_inv_range2:
113         add     d0,d1
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
120         bne     1f
121         btst    ~(L1_CACHE_BYTES-1),d1
122         beq     2f
124         bra     mn10300_local_dcache_flush_inv_range
126 #endif /* CONFIG_MN10300_CACHE_WBACK */
128         movm    [d2,d3,a2],(sp)
130         mov     CHCTR,a0
131         movhu   (a0),d2
132         btst    CHCTR_DCEN,d2
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
137         # now
138 #ifndef CONFIG_MN10300_CACHE_WBACK
139         and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0      # round start
140                                                                 # addr down
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 */
147         sub     d0,d1,d2                # calculate the total size
148         mov     d0,a2                   # A2 = start address
149         mov     d1,a1                   # A1 = end address
151         LOCAL_CLI_SAVE(d3)
153         mov     DCPGCR,a0               # make sure the purger isn't busy
154         setlb
155         mov     (a0),d0
156         btst    DCPGCR_DCPGBSY,d0
157         lne
159         # skip initial address alignment calculation if address is zero
160         mov     d2,d1
161         cmp     0,a2
162         beq     1f
164 dcivloop:
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
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
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
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)
219         # invalidate area
220         mov     a2,d0
221         or      DCPGCR_DCI,d0
222         mov     d0,(a0)                 # DCPGCR = (mask & start) | DCPGCR_DCI
224         setlb                           # wait for the purge to complete
225         mov     (a0),d0
226         btst    DCPGCR_DCPGBSY,d0
227         lne
229         sub     d1,d2                   # decrease size remaining
230         add     d1,a2                   # increase next start address
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
241         LOCAL_IRQ_RESTORE(d3)
243 mn10300_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
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 ###############################################################################
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
264 mn10300_local_icache_inv_page:
265         and     ~(PAGE_SIZE-1),d0
266         mov     PAGE_SIZE,d1
267 mn10300_local_icache_inv_range2:
268         add     d0,d1
269 mn10300_local_icache_inv_range:
270         movm    [d2,d3,a2],(sp)
272         mov     CHCTR,a0
273         movhu   (a0),d2
274         btst    CHCTR_ICEN,d2
275         beq     mn10300_local_icache_inv_range_reg_end
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
291         add     d2,d2
292         lsr     1,d3
293         bne     1b
296         /* a1 = end */
297         mov     d1,a1
299         LOCAL_CLI_SAVE(d3)
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
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
320 icivloop:
321         /* area invalidate
322          *
323          * ICIVCR = (mask & start) | ICIVCR_ICI
324          */
325         mov     a2,d0
326         or      ICIVCR_ICI,d0
327         mov     d0,(a0)
329         /* wait for busy bit of area invalidation */
330         setlb
331         mov     (a0),d1
332         btst    ICIVCR_ICIVBSY,d1
333         lne
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
345         LOCAL_IRQ_RESTORE(d3)
347 mn10300_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