c96fa1b3f49f5d78b670289a1d8fc8ccf3b38b30
[linux-3.10.git] / arch / arm / mm / cache-v6.S
1 /*
2  *  linux/arch/arm/mm/cache-v6.S
3  *
4  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  *  This is the "shell" of the ARMv6 processor support.
11  */
12 #include <linux/linkage.h>
13 #include <linux/init.h>
14 #include <asm/assembler.h>
15 #include <asm/unwind.h>
16
17 #include "proc-macros.S"
18
19 #define HARVARD_CACHE
20 #define CACHE_LINE_SIZE         32
21 #define D_CACHE_LINE_SIZE       32
22 #define BTB_FLUSH_SIZE          8
23
24 /*
25  *      v6_flush_icache_all()
26  *
27  *      Flush the whole I-cache.
28  *
29  *      ARM1136 erratum 411920 - Invalidate Instruction Cache operation can fail.
30  *      This erratum is present in 1136, 1156 and 1176. It does not affect the
31  *      MPCore.
32  *
33  *      Registers:
34  *      r0 - set to 0
35  *      r1 - corrupted
36  */
37 ENTRY(v6_flush_icache_all)
38         mov     r0, #0
39 #ifdef CONFIG_ARM_ERRATA_411920
40         mrs     r1, cpsr
41         cpsid   ifa                             @ disable interrupts
42         mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
43         mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
44         mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
45         mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
46         msr     cpsr_cx, r1                     @ restore interrupts
47         .rept   11                              @ ARM Ltd recommends at least
48         nop                                     @ 11 NOPs
49         .endr
50 #else
51         mcr     p15, 0, r0, c7, c5, 0           @ invalidate I-cache
52 #endif
53         mov     pc, lr
54 ENDPROC(v6_flush_icache_all)
55
56 /*
57  *      v6_flush_cache_all()
58  *
59  *      Flush the entire cache.
60  *
61  *      It is assumed that:
62  */
63 ENTRY(v6_flush_kern_cache_all)
64         mov     r0, #0
65 #ifdef HARVARD_CACHE
66         mcr     p15, 0, r0, c7, c14, 0          @ D cache clean+invalidate
67 #ifndef CONFIG_ARM_ERRATA_411920
68         mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
69 #else
70         b       v6_flush_icache_all
71 #endif
72 #else
73         mcr     p15, 0, r0, c7, c15, 0          @ Cache clean+invalidate
74 #endif
75         mov     pc, lr
76
77 /*
78  *      v6_flush_cache_all()
79  *
80  *      Flush all TLB entries in a particular address space
81  *
82  *      - mm    - mm_struct describing address space
83  */
84 ENTRY(v6_flush_user_cache_all)
85         /*FALLTHROUGH*/
86
87 /*
88  *      v6_flush_cache_range(start, end, flags)
89  *
90  *      Flush a range of TLB entries in the specified address space.
91  *
92  *      - start - start address (may not be aligned)
93  *      - end   - end address (exclusive, may not be aligned)
94  *      - flags - vm_area_struct flags describing address space
95  *
96  *      It is assumed that:
97  *      - we have a VIPT cache.
98  */
99 ENTRY(v6_flush_user_cache_range)
100         mov     pc, lr
101
102 /*
103  *      v6_coherent_kern_range(start,end)
104  *
105  *      Ensure that the I and D caches are coherent within specified
106  *      region.  This is typically used when code has been written to
107  *      a memory region, and will be executed.
108  *
109  *      - start   - virtual start address of region
110  *      - end     - virtual end address of region
111  *
112  *      It is assumed that:
113  *      - the Icache does not read data from the write buffer
114  */
115 ENTRY(v6_coherent_kern_range)
116         /* FALLTHROUGH */
117
118 /*
119  *      v6_coherent_user_range(start,end)
120  *
121  *      Ensure that the I and D caches are coherent within specified
122  *      region.  This is typically used when code has been written to
123  *      a memory region, and will be executed.
124  *
125  *      - start   - virtual start address of region
126  *      - end     - virtual end address of region
127  *
128  *      It is assumed that:
129  *      - the Icache does not read data from the write buffer
130  */
131 ENTRY(v6_coherent_user_range)
132  UNWIND(.fnstart                )
133 #ifdef HARVARD_CACHE
134         bic     r0, r0, #CACHE_LINE_SIZE - 1
135 1:
136  USER(  mcr     p15, 0, r0, c7, c10, 1  )       @ clean D line
137         add     r0, r0, #CACHE_LINE_SIZE
138 2:
139         cmp     r0, r1
140         blo     1b
141 #endif
142         mov     r0, #0
143 #ifdef HARVARD_CACHE
144         mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
145 #ifndef CONFIG_ARM_ERRATA_411920
146         mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
147 #else
148         b       v6_flush_icache_all
149 #endif
150 #else
151         mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
152 #endif
153         mov     pc, lr
154
155 /*
156  * Fault handling for the cache operation above. If the virtual address in r0
157  * isn't mapped, just try the next page.
158  */
159 9001:
160         mov     r0, r0, lsr #12
161         mov     r0, r0, lsl #12
162         add     r0, r0, #4096
163         b       2b
164  UNWIND(.fnend          )
165 ENDPROC(v6_coherent_user_range)
166 ENDPROC(v6_coherent_kern_range)
167
168 /*
169  *      v6_flush_kern_dcache_area(void *addr, size_t size)
170  *
171  *      Ensure that the data held in the page kaddr is written back
172  *      to the page in question.
173  *
174  *      - addr  - kernel address
175  *      - size  - region size
176  */
177 ENTRY(v6_flush_kern_dcache_area)
178         add     r1, r0, r1
179 1:
180 #ifdef HARVARD_CACHE
181         mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
182 #else
183         mcr     p15, 0, r0, c7, c15, 1          @ clean & invalidate unified line
184 #endif  
185         add     r0, r0, #D_CACHE_LINE_SIZE
186         cmp     r0, r1
187         blo     1b
188 #ifdef HARVARD_CACHE
189         mov     r0, #0
190         mcr     p15, 0, r0, c7, c10, 4
191 #endif
192         mov     pc, lr
193
194
195 /*
196  *      v6_dma_inv_range(start,end)
197  *
198  *      Invalidate the data cache within the specified region; we will
199  *      be performing a DMA operation in this region and we want to
200  *      purge old data in the cache.
201  *
202  *      - start   - virtual start address of region
203  *      - end     - virtual end address of region
204  */
205 v6_dma_inv_range:
206 #ifdef CONFIG_DMA_CACHE_RWFO
207         ldrb    r2, [r0]                        @ read for ownership
208         strb    r2, [r0]                        @ write for ownership
209 #endif
210         tst     r0, #D_CACHE_LINE_SIZE - 1
211         bic     r0, r0, #D_CACHE_LINE_SIZE - 1
212 #ifdef HARVARD_CACHE
213         mcrne   p15, 0, r0, c7, c10, 1          @ clean D line
214 #else
215         mcrne   p15, 0, r0, c7, c11, 1          @ clean unified line
216 #endif
217         tst     r1, #D_CACHE_LINE_SIZE - 1
218 #ifdef CONFIG_DMA_CACHE_RWFO
219         ldrneb  r2, [r1, #-1]                   @ read for ownership
220         strneb  r2, [r1, #-1]                   @ write for ownership
221 #endif
222         bic     r1, r1, #D_CACHE_LINE_SIZE - 1
223 #ifdef HARVARD_CACHE
224         mcrne   p15, 0, r1, c7, c14, 1          @ clean & invalidate D line
225 #else
226         mcrne   p15, 0, r1, c7, c15, 1          @ clean & invalidate unified line
227 #endif
228 1:
229 #ifdef HARVARD_CACHE
230         mcr     p15, 0, r0, c7, c6, 1           @ invalidate D line
231 #else
232         mcr     p15, 0, r0, c7, c7, 1           @ invalidate unified line
233 #endif
234         add     r0, r0, #D_CACHE_LINE_SIZE
235         cmp     r0, r1
236 #ifdef CONFIG_DMA_CACHE_RWFO
237         ldrlo   r2, [r0]                        @ read for ownership
238         strlo   r2, [r0]                        @ write for ownership
239 #endif
240         blo     1b
241         mov     r0, #0
242         mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
243         mov     pc, lr
244
245 /*
246  *      v6_dma_clean_range(start,end)
247  *      - start   - virtual start address of region
248  *      - end     - virtual end address of region
249  */
250 v6_dma_clean_range:
251         bic     r0, r0, #D_CACHE_LINE_SIZE - 1
252 1:
253 #ifdef CONFIG_DMA_CACHE_RWFO
254         ldr     r2, [r0]                        @ read for ownership
255 #endif
256 #ifdef HARVARD_CACHE
257         mcr     p15, 0, r0, c7, c10, 1          @ clean D line
258 #else
259         mcr     p15, 0, r0, c7, c11, 1          @ clean unified line
260 #endif
261         add     r0, r0, #D_CACHE_LINE_SIZE
262         cmp     r0, r1
263         blo     1b
264         mov     r0, #0
265         mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
266         mov     pc, lr
267
268 /*
269  *      v6_dma_flush_range(start,end)
270  *      - start   - virtual start address of region
271  *      - end     - virtual end address of region
272  */
273 ENTRY(v6_dma_flush_range)
274 #ifdef CONFIG_DMA_CACHE_RWFO
275         ldrb    r2, [r0]                @ read for ownership
276         strb    r2, [r0]                @ write for ownership
277 #endif
278         bic     r0, r0, #D_CACHE_LINE_SIZE - 1
279 1:
280 #ifdef HARVARD_CACHE
281         mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
282 #else
283         mcr     p15, 0, r0, c7, c15, 1          @ clean & invalidate line
284 #endif
285         add     r0, r0, #D_CACHE_LINE_SIZE
286         cmp     r0, r1
287 #ifdef CONFIG_DMA_CACHE_RWFO
288         ldrlob  r2, [r0]                        @ read for ownership
289         strlob  r2, [r0]                        @ write for ownership
290 #endif
291         blo     1b
292         mov     r0, #0
293         mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
294         mov     pc, lr
295
296 /*
297  *      dma_map_area(start, size, dir)
298  *      - start - kernel virtual start address
299  *      - size  - size of region
300  *      - dir   - DMA direction
301  */
302 ENTRY(v6_dma_map_area)
303         add     r1, r1, r0
304         teq     r2, #DMA_FROM_DEVICE
305         beq     v6_dma_inv_range
306 #ifndef CONFIG_DMA_CACHE_RWFO
307         b       v6_dma_clean_range
308 #else
309         teq     r2, #DMA_TO_DEVICE
310         beq     v6_dma_clean_range
311         b       v6_dma_flush_range
312 #endif
313 ENDPROC(v6_dma_map_area)
314
315 /*
316  *      dma_unmap_area(start, size, dir)
317  *      - start - kernel virtual start address
318  *      - size  - size of region
319  *      - dir   - DMA direction
320  */
321 ENTRY(v6_dma_unmap_area)
322 #ifndef CONFIG_DMA_CACHE_RWFO
323         add     r1, r1, r0
324         teq     r2, #DMA_TO_DEVICE
325         bne     v6_dma_inv_range
326 #endif
327         mov     pc, lr
328 ENDPROC(v6_dma_unmap_area)
329
330         __INITDATA
331
332         .type   v6_cache_fns, #object
333 ENTRY(v6_cache_fns)
334         .long   v6_flush_icache_all
335         .long   v6_flush_kern_cache_all
336         .long   v6_flush_user_cache_all
337         .long   v6_flush_user_cache_range
338         .long   v6_coherent_kern_range
339         .long   v6_coherent_user_range
340         .long   v6_flush_kern_dcache_area
341         .long   v6_dma_map_area
342         .long   v6_dma_unmap_area
343         .long   v6_dma_flush_range
344         .size   v6_cache_fns, . - v6_cache_fns