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 */ 37ENTRY(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 54ENDPROC(v6_flush_icache_all) 55 56/* 57 * v6_flush_cache_all() 58 * 59 * Flush the entire cache. 60 * 61 * It is assumed that: 62 */ 63ENTRY(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 */ 84ENTRY(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 */ 99ENTRY(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 */ 115ENTRY(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 */ 131ENTRY(v6_coherent_user_range) 132 UNWIND(.fnstart ) 133#ifdef HARVARD_CACHE 134 bic r0, r0, #CACHE_LINE_SIZE - 1 1351: 136 USER( mcr p15, 0, r0, c7, c10, 1 ) @ clean D line 137 add r0, r0, #CACHE_LINE_SIZE 1382: 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 */ 1599001: 160 mov r0, r0, lsr #12 161 mov r0, r0, lsl #12 162 add r0, r0, #4096 163 b 2b 164 UNWIND(.fnend ) 165ENDPROC(v6_coherent_user_range) 166ENDPROC(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 */ 177ENTRY(v6_flush_kern_dcache_area) 178 add r1, r0, r1 1791: 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 */ 205v6_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 2281: 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 */ 250v6_dma_clean_range: 251 bic r0, r0, #D_CACHE_LINE_SIZE - 1 2521: 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 */ 273ENTRY(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 2791: 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 */ 302ENTRY(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 313ENDPROC(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 */ 321ENTRY(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 328ENDPROC(v6_dma_unmap_area) 329 330 __INITDATA 331 332 .type v6_cache_fns, #object 333ENTRY(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 345