Merge branches 'irq-core-for-linus' and 'core-locking-for-linus' of git://git.kernel...
[pandora-kernel.git] / arch / mn10300 / mm / cache-inv-by-tag.S
1 /* MN10300 CPU core caching routines
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         .globl  mn10300_local_icache_inv_page
29         .globl  mn10300_local_icache_inv_range
30         .globl  mn10300_local_icache_inv_range2
31
32 mn10300_local_icache_inv_page   = mn10300_local_icache_inv
33 mn10300_local_icache_inv_range  = mn10300_local_icache_inv
34 mn10300_local_icache_inv_range2 = mn10300_local_icache_inv
35
36 #ifndef CONFIG_SMP
37         .globl  mn10300_icache_inv
38         .globl  mn10300_icache_inv_page
39         .globl  mn10300_icache_inv_range
40         .globl  mn10300_icache_inv_range2
41         .globl  mn10300_dcache_inv
42         .globl  mn10300_dcache_inv_page
43         .globl  mn10300_dcache_inv_range
44         .globl  mn10300_dcache_inv_range2
45
46 mn10300_icache_inv              = mn10300_local_icache_inv
47 mn10300_icache_inv_page         = mn10300_local_icache_inv_page
48 mn10300_icache_inv_range        = mn10300_local_icache_inv_range
49 mn10300_icache_inv_range2       = mn10300_local_icache_inv_range2
50 mn10300_dcache_inv              = mn10300_local_dcache_inv
51 mn10300_dcache_inv_page         = mn10300_local_dcache_inv_page
52 mn10300_dcache_inv_range        = mn10300_local_dcache_inv_range
53 mn10300_dcache_inv_range2       = mn10300_local_dcache_inv_range2
54
55 #endif /* !CONFIG_SMP */
56
57 ###############################################################################
58 #
59 # void mn10300_local_icache_inv(void)
60 # Invalidate the entire icache
61 #
62 ###############################################################################
63         ALIGN
64         .globl  mn10300_local_icache_inv
65         .type   mn10300_local_icache_inv,@function
66 mn10300_local_icache_inv:
67         mov     CHCTR,a0
68
69         movhu   (a0),d0
70         btst    CHCTR_ICEN,d0
71         beq     mn10300_local_icache_inv_end
72
73 #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
74         LOCAL_CLI_SAVE(d1)
75
76         # disable the icache
77         and     ~CHCTR_ICEN,d0
78         movhu   d0,(a0)
79
80         # and wait for it to calm down
81         setlb
82         movhu   (a0),d0
83         btst    CHCTR_ICBUSY,d0
84         lne
85
86         # invalidate
87         or      CHCTR_ICINV,d0
88         movhu   d0,(a0)
89
90         # wait for the cache to finish
91         mov     CHCTR,a0
92         setlb
93         movhu   (a0),d0
94         btst    CHCTR_ICBUSY,d0
95         lne
96
97         # and reenable it
98         and     ~CHCTR_ICINV,d0
99         or      CHCTR_ICEN,d0
100         movhu   d0,(a0)
101         movhu   (a0),d0
102
103         LOCAL_IRQ_RESTORE(d1)
104 #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
105         # invalidate
106         or      CHCTR_ICINV,d0
107         movhu   d0,(a0)
108         movhu   (a0),d0
109 #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
110
111 mn10300_local_icache_inv_end:
112         ret     [],0
113         .size   mn10300_local_icache_inv,.-mn10300_local_icache_inv
114
115 ###############################################################################
116 #
117 # void mn10300_local_dcache_inv(void)
118 # Invalidate the entire dcache
119 #
120 ###############################################################################
121         ALIGN
122         .globl  mn10300_local_dcache_inv
123         .type   mn10300_local_dcache_inv,@function
124 mn10300_local_dcache_inv:
125         mov     CHCTR,a0
126
127         movhu   (a0),d0
128         btst    CHCTR_DCEN,d0
129         beq     mn10300_local_dcache_inv_end
130
131 #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
132         LOCAL_CLI_SAVE(d1)
133
134         # disable the dcache
135         and     ~CHCTR_DCEN,d0
136         movhu   d0,(a0)
137
138         # and wait for it to calm down
139         setlb
140         movhu   (a0),d0
141         btst    CHCTR_DCBUSY,d0
142         lne
143
144         # invalidate
145         or      CHCTR_DCINV,d0
146         movhu   d0,(a0)
147
148         # wait for the cache to finish
149         mov     CHCTR,a0
150         setlb
151         movhu   (a0),d0
152         btst    CHCTR_DCBUSY,d0
153         lne
154
155         # and reenable it
156         and     ~CHCTR_DCINV,d0
157         or      CHCTR_DCEN,d0
158         movhu   d0,(a0)
159         movhu   (a0),d0
160
161         LOCAL_IRQ_RESTORE(d1)
162 #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
163         # invalidate
164         or      CHCTR_DCINV,d0
165         movhu   d0,(a0)
166         movhu   (a0),d0
167 #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
168
169 mn10300_local_dcache_inv_end:
170         ret     [],0
171         .size   mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
172
173 ###############################################################################
174 #
175 # void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
176 # void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
177 # void mn10300_local_dcache_inv_page(unsigned long start)
178 # Invalidate a range of addresses on a page in the dcache
179 #
180 ###############################################################################
181         ALIGN
182         .globl  mn10300_local_dcache_inv_page
183         .globl  mn10300_local_dcache_inv_range
184         .globl  mn10300_local_dcache_inv_range2
185         .type   mn10300_local_dcache_inv_page,@function
186         .type   mn10300_local_dcache_inv_range,@function
187         .type   mn10300_local_dcache_inv_range2,@function
188 mn10300_local_dcache_inv_page:
189         and     ~(PAGE_SIZE-1),d0
190         mov     PAGE_SIZE,d1
191 mn10300_local_dcache_inv_range2:
192         add     d0,d1
193 mn10300_local_dcache_inv_range:
194         # If we are in writeback mode we check the start and end alignments,
195         # and if they're not cacheline-aligned, we must flush any bits outside
196         # the range that share cachelines with stuff inside the range
197 #ifdef CONFIG_MN10300_CACHE_WBACK
198         btst    ~(L1_CACHE_BYTES-1),d0
199         bne     1f
200         btst    ~(L1_CACHE_BYTES-1),d1
201         beq     2f
202 1:
203         bra     mn10300_local_dcache_flush_inv_range
204 2:
205 #endif /* CONFIG_MN10300_CACHE_WBACK */
206
207         movm    [d2,d3,a2],(sp)
208
209         mov     CHCTR,a2
210         movhu   (a2),d2
211         btst    CHCTR_DCEN,d2
212         beq     mn10300_local_dcache_inv_range_end
213
214 #ifndef CONFIG_MN10300_CACHE_WBACK
215         and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0      # round start
216                                                                 # addr down
217
218         add     L1_CACHE_BYTES,d1               # round end addr up
219         and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
220 #endif /* !CONFIG_MN10300_CACHE_WBACK */
221         mov     d0,a1
222
223         clr     d2                              # we're going to clear tag RAM
224                                                 # entries
225
226         # read the tags from the tag RAM, and if they indicate a valid dirty
227         # cache line then invalidate that line
228         mov     DCACHE_TAG(0,0),a0
229         mov     a1,d0
230         and     L1_CACHE_TAG_ENTRY,d0
231         add     d0,a0                           # starting dcache tag RAM
232                                                 # access address
233
234         sub     a1,d1
235         lsr     L1_CACHE_SHIFT,d1               # total number of entries to
236                                                 # examine
237
238         and     ~(L1_CACHE_DISPARITY-1),a1      # determine comparator base
239
240 mn10300_local_dcache_inv_range_outer_loop:
241         LOCAL_CLI_SAVE(d3)
242
243         # disable the dcache
244         movhu   (a2),d0
245         and     ~CHCTR_DCEN,d0
246         movhu   d0,(a2)
247
248         # and wait for it to calm down
249         setlb
250         movhu   (a2),d0
251         btst    CHCTR_DCBUSY,d0
252         lne
253
254 mn10300_local_dcache_inv_range_loop:
255
256         # process the way 0 slot
257         mov     (L1_CACHE_WAYDISP*0,a0),d0      # read the tag in the way 0 slot
258         btst    L1_CACHE_TAG_VALID,d0
259         beq     mn10300_local_dcache_inv_range_skip_0   # jump if this cacheline
260                                                 # is not valid
261
262         xor     a1,d0
263         lsr     12,d0
264         bne     mn10300_local_dcache_inv_range_skip_0   # jump if not this cacheline
265
266         mov     d2,(L1_CACHE_WAYDISP*0,a0)      # kill the tag
267
268 mn10300_local_dcache_inv_range_skip_0:
269
270         # process the way 1 slot
271         mov     (L1_CACHE_WAYDISP*1,a0),d0      # read the tag in the way 1 slot
272         btst    L1_CACHE_TAG_VALID,d0
273         beq     mn10300_local_dcache_inv_range_skip_1   # jump if this cacheline
274                                                 # is not valid
275
276         xor     a1,d0
277         lsr     12,d0
278         bne     mn10300_local_dcache_inv_range_skip_1   # jump if not this cacheline
279
280         mov     d2,(L1_CACHE_WAYDISP*1,a0)      # kill the tag
281
282 mn10300_local_dcache_inv_range_skip_1:
283
284         # process the way 2 slot
285         mov     (L1_CACHE_WAYDISP*2,a0),d0      # read the tag in the way 2 slot
286         btst    L1_CACHE_TAG_VALID,d0
287         beq     mn10300_local_dcache_inv_range_skip_2   # jump if this cacheline
288                                                 # is not valid
289
290         xor     a1,d0
291         lsr     12,d0
292         bne     mn10300_local_dcache_inv_range_skip_2   # jump if not this cacheline
293
294         mov     d2,(L1_CACHE_WAYDISP*2,a0)      # kill the tag
295
296 mn10300_local_dcache_inv_range_skip_2:
297
298         # process the way 3 slot
299         mov     (L1_CACHE_WAYDISP*3,a0),d0      # read the tag in the way 3 slot
300         btst    L1_CACHE_TAG_VALID,d0
301         beq     mn10300_local_dcache_inv_range_skip_3   # jump if this cacheline
302                                                 # is not valid
303
304         xor     a1,d0
305         lsr     12,d0
306         bne     mn10300_local_dcache_inv_range_skip_3   # jump if not this cacheline
307
308         mov     d2,(L1_CACHE_WAYDISP*3,a0)      # kill the tag
309
310 mn10300_local_dcache_inv_range_skip_3:
311
312         # approx every N steps we re-enable the cache and see if there are any
313         # interrupts to be processed
314         # we also break out if we've reached the end of the loop
315         # (the bottom nibble of the count is zero in both cases)
316         add     L1_CACHE_BYTES,a0
317         add     L1_CACHE_BYTES,a1
318         and     ~L1_CACHE_WAYDISP,a0
319         add     -1,d1
320         btst    mn10300_local_dcache_inv_range_intr_interval,d1
321         bne     mn10300_local_dcache_inv_range_loop
322
323         # wait for the cache to finish what it's doing
324         setlb
325         movhu   (a2),d0
326         btst    CHCTR_DCBUSY,d0
327         lne
328
329         # and reenable it
330         or      CHCTR_DCEN,d0
331         movhu   d0,(a2)
332         movhu   (a2),d0
333
334         # re-enable interrupts
335         # - we don't bother with delay NOPs as we'll have enough instructions
336         #   before we disable interrupts again to give the interrupts a chance
337         #   to happen
338         LOCAL_IRQ_RESTORE(d3)
339
340         # go around again if the counter hasn't yet reached zero
341         add     0,d1
342         bne     mn10300_local_dcache_inv_range_outer_loop
343
344 mn10300_local_dcache_inv_range_end:
345         ret     [d2,d3,a2],12
346         .size   mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
347         .size   mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
348         .size   mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2