1/* 2 * linux/arch/arm/mm/cache-v7.S 3 * 4 * Copyright (C) 2001 Deep Blue Solutions Ltd. 5 * Copyright (C) 2005 ARM Ltd. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This is the "shell" of the ARMv7 processor support. 12 */ 13#include <linux/linkage.h> 14#include <linux/init.h> 15#include <asm/assembler.h> 16#include <asm/errno.h> 17#include <asm/unwind.h> 18#include <asm/hardware/cache-b15-rac.h> 19 20#include "proc-macros.S" 21 22/* 23 * The secondary kernel init calls v7_flush_dcache_all before it enables 24 * the L1; however, the L1 comes out of reset in an undefined state, so 25 * the clean + invalidate performed by v7_flush_dcache_all causes a bunch 26 * of cache lines with uninitialized data and uninitialized tags to get 27 * written out to memory, which does really unpleasant things to the main 28 * processor. We fix this by performing an invalidate, rather than a 29 * clean + invalidate, before jumping into the kernel. 30 * 31 * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs 32 * to be called for both secondary cores startup and primary core resume 33 * procedures. 34 */ 35ENTRY(v7_invalidate_l1) 36 mov r0, #0 37 mcr p15, 2, r0, c0, c0, 0 38 mrc p15, 1, r0, c0, c0, 0 39 40 movw r1, #0x7fff 41 and r2, r1, r0, lsr #13 42 43 movw r1, #0x3ff 44 45 and r3, r1, r0, lsr #3 @ NumWays - 1 46 add r2, r2, #1 @ NumSets 47 48 and r0, r0, #0x7 49 add r0, r0, #4 @ SetShift 50 51 clz r1, r3 @ WayShift 52 add r4, r3, #1 @ NumWays 531: sub r2, r2, #1 @ NumSets-- 54 mov r3, r4 @ Temp = NumWays 552: subs r3, r3, #1 @ Temp-- 56 mov r5, r3, lsl r1 57 mov r6, r2, lsl r0 58 orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift) 59 mcr p15, 0, r5, c7, c6, 2 60 bgt 2b 61 cmp r2, #0 62 bgt 1b 63 dsb st 64 isb 65 ret lr 66ENDPROC(v7_invalidate_l1) 67 68/* 69 * v7_flush_icache_all() 70 * 71 * Flush the whole I-cache. 72 * 73 * Registers: 74 * r0 - set to 0 75 */ 76ENTRY(v7_flush_icache_all) 77 mov r0, #0 78 ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable 79 ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate 80 ret lr 81ENDPROC(v7_flush_icache_all) 82 83 /* 84 * v7_flush_dcache_louis() 85 * 86 * Flush the D-cache up to the Level of Unification Inner Shareable 87 * 88 * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 89 */ 90 91ENTRY(v7_flush_dcache_louis) 92 dmb @ ensure ordering with previous memory accesses 93 mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr 94ALT_SMP(mov r3, r0, lsr #20) @ move LoUIS into position 95ALT_UP( mov r3, r0, lsr #26) @ move LoUU into position 96 ands r3, r3, #7 << 1 @ extract LoU*2 field from clidr 97 bne start_flush_levels @ LoU != 0, start flushing 98#ifdef CONFIG_ARM_ERRATA_643719 99ALT_SMP(mrc p15, 0, r2, c0, c0, 0) @ read main ID register 100ALT_UP( ret lr) @ LoUU is zero, so nothing to do 101 movw r1, #:lower16:(0x410fc090 >> 4) @ ID of ARM Cortex A9 r0p? 102 movt r1, #:upper16:(0x410fc090 >> 4) 103 teq r1, r2, lsr #4 @ test for errata affected core and if so... 104 moveq r3, #1 << 1 @ fix LoUIS value 105 beq start_flush_levels @ start flushing cache levels 106#endif 107 ret lr 108ENDPROC(v7_flush_dcache_louis) 109 110/* 111 * v7_flush_dcache_all() 112 * 113 * Flush the whole D-cache. 114 * 115 * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 116 * 117 * - mm - mm_struct describing address space 118 */ 119ENTRY(v7_flush_dcache_all) 120 dmb @ ensure ordering with previous memory accesses 121 mrc p15, 1, r0, c0, c0, 1 @ read clidr 122 mov r3, r0, lsr #23 @ move LoC into position 123 ands r3, r3, #7 << 1 @ extract LoC*2 from clidr 124 beq finished @ if loc is 0, then no need to clean 125start_flush_levels: 126 mov r10, #0 @ start clean at cache level 0 127flush_levels: 128 add r2, r10, r10, lsr #1 @ work out 3x current cache level 129 mov r1, r0, lsr r2 @ extract cache type bits from clidr 130 and r1, r1, #7 @ mask of the bits for current cache only 131 cmp r1, #2 @ see what cache we have at this level 132 blt skip @ skip if no cache, or just i-cache 133#ifdef CONFIG_PREEMPT 134 save_and_disable_irqs_notrace r9 @ make cssr&csidr read atomic 135#endif 136 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 137 isb @ isb to sych the new cssr&csidr 138 mrc p15, 1, r1, c0, c0, 0 @ read the new csidr 139#ifdef CONFIG_PREEMPT 140 restore_irqs_notrace r9 141#endif 142 and r2, r1, #7 @ extract the length of the cache lines 143 add r2, r2, #4 @ add 4 (line length offset) 144 movw r4, #0x3ff 145 ands r4, r4, r1, lsr #3 @ find maximum number on the way size 146 clz r5, r4 @ find bit position of way size increment 147 movw r7, #0x7fff 148 ands r7, r7, r1, lsr #13 @ extract max number of the index size 149loop1: 150 mov r9, r7 @ create working copy of max index 151loop2: 152 ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 153 THUMB( lsl r6, r4, r5 ) 154 THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 155 ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 156 THUMB( lsl r6, r9, r2 ) 157 THUMB( orr r11, r11, r6 ) @ factor index number into r11 158 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way 159 subs r9, r9, #1 @ decrement the index 160 bge loop2 161 subs r4, r4, #1 @ decrement the way 162 bge loop1 163skip: 164 add r10, r10, #2 @ increment cache number 165 cmp r3, r10 166 bgt flush_levels 167finished: 168 mov r10, #0 @ switch back to cache level 0 169 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 170 dsb st 171 isb 172 ret lr 173ENDPROC(v7_flush_dcache_all) 174 175/* 176 * v7_flush_cache_all() 177 * 178 * Flush the entire cache system. 179 * The data cache flush is now achieved using atomic clean / invalidates 180 * working outwards from L1 cache. This is done using Set/Way based cache 181 * maintenance instructions. 182 * The instruction cache can still be invalidated back to the point of 183 * unification in a single instruction. 184 * 185 */ 186ENTRY(v7_flush_kern_cache_all) 187 ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 188 THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 189 bl v7_flush_dcache_all 190 mov r0, #0 191 ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable 192 ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate 193 ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 194 THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 195 ret lr 196ENDPROC(v7_flush_kern_cache_all) 197 198 /* 199 * v7_flush_kern_cache_louis(void) 200 * 201 * Flush the data cache up to Level of Unification Inner Shareable. 202 * Invalidate the I-cache to the point of unification. 203 */ 204ENTRY(v7_flush_kern_cache_louis) 205 ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 206 THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 207 bl v7_flush_dcache_louis 208 mov r0, #0 209 ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable 210 ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate 211 ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 212 THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 213 ret lr 214ENDPROC(v7_flush_kern_cache_louis) 215 216/* 217 * v7_flush_cache_all() 218 * 219 * Flush all TLB entries in a particular address space 220 * 221 * - mm - mm_struct describing address space 222 */ 223ENTRY(v7_flush_user_cache_all) 224 /*FALLTHROUGH*/ 225 226/* 227 * v7_flush_cache_range(start, end, flags) 228 * 229 * Flush a range of TLB entries in the specified address space. 230 * 231 * - start - start address (may not be aligned) 232 * - end - end address (exclusive, may not be aligned) 233 * - flags - vm_area_struct flags describing address space 234 * 235 * It is assumed that: 236 * - we have a VIPT cache. 237 */ 238ENTRY(v7_flush_user_cache_range) 239 ret lr 240ENDPROC(v7_flush_user_cache_all) 241ENDPROC(v7_flush_user_cache_range) 242 243/* 244 * v7_coherent_kern_range(start,end) 245 * 246 * Ensure that the I and D caches are coherent within specified 247 * region. This is typically used when code has been written to 248 * a memory region, and will be executed. 249 * 250 * - start - virtual start address of region 251 * - end - virtual end address of region 252 * 253 * It is assumed that: 254 * - the Icache does not read data from the write buffer 255 */ 256ENTRY(v7_coherent_kern_range) 257 /* FALLTHROUGH */ 258 259/* 260 * v7_coherent_user_range(start,end) 261 * 262 * Ensure that the I and D caches are coherent within specified 263 * region. This is typically used when code has been written to 264 * a memory region, and will be executed. 265 * 266 * - start - virtual start address of region 267 * - end - virtual end address of region 268 * 269 * It is assumed that: 270 * - the Icache does not read data from the write buffer 271 */ 272ENTRY(v7_coherent_user_range) 273 UNWIND(.fnstart ) 274 dcache_line_size r2, r3 275 sub r3, r2, #1 276 bic r12, r0, r3 277#ifdef CONFIG_ARM_ERRATA_764369 278 ALT_SMP(W(dsb)) 279 ALT_UP(W(nop)) 280#endif 2811: 282 USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification 283 add r12, r12, r2 284 cmp r12, r1 285 blo 1b 286 dsb ishst 287 icache_line_size r2, r3 288 sub r3, r2, #1 289 bic r12, r0, r3 2902: 291 USER( mcr p15, 0, r12, c7, c5, 1 ) @ invalidate I line 292 add r12, r12, r2 293 cmp r12, r1 294 blo 2b 295 mov r0, #0 296 ALT_SMP(mcr p15, 0, r0, c7, c1, 6) @ invalidate BTB Inner Shareable 297 ALT_UP(mcr p15, 0, r0, c7, c5, 6) @ invalidate BTB 298 dsb ishst 299 isb 300 ret lr 301 302/* 303 * Fault handling for the cache operation above. If the virtual address in r0 304 * isn't mapped, fail with -EFAULT. 305 */ 3069001: 307#ifdef CONFIG_ARM_ERRATA_775420 308 dsb 309#endif 310 mov r0, #-EFAULT 311 ret lr 312 UNWIND(.fnend ) 313ENDPROC(v7_coherent_kern_range) 314ENDPROC(v7_coherent_user_range) 315 316/* 317 * v7_flush_kern_dcache_area(void *addr, size_t size) 318 * 319 * Ensure that the data held in the page kaddr is written back 320 * to the page in question. 321 * 322 * - addr - kernel address 323 * - size - region size 324 */ 325ENTRY(v7_flush_kern_dcache_area) 326 dcache_line_size r2, r3 327 add r1, r0, r1 328 sub r3, r2, #1 329 bic r0, r0, r3 330#ifdef CONFIG_ARM_ERRATA_764369 331 ALT_SMP(W(dsb)) 332 ALT_UP(W(nop)) 333#endif 3341: 335 mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line / unified line 336 add r0, r0, r2 337 cmp r0, r1 338 blo 1b 339 dsb st 340 ret lr 341ENDPROC(v7_flush_kern_dcache_area) 342 343/* 344 * v7_dma_inv_range(start,end) 345 * 346 * Invalidate the data cache within the specified region; we will 347 * be performing a DMA operation in this region and we want to 348 * purge old data in the cache. 349 * 350 * - start - virtual start address of region 351 * - end - virtual end address of region 352 */ 353v7_dma_inv_range: 354 dcache_line_size r2, r3 355 sub r3, r2, #1 356 tst r0, r3 357 bic r0, r0, r3 358#ifdef CONFIG_ARM_ERRATA_764369 359 ALT_SMP(W(dsb)) 360 ALT_UP(W(nop)) 361#endif 362 mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line 363 addne r0, r0, r2 364 365 tst r1, r3 366 bic r1, r1, r3 367 mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D / U line 368 cmp r0, r1 3691: 370 mcrlo p15, 0, r0, c7, c6, 1 @ invalidate D / U line 371 addlo r0, r0, r2 372 cmplo r0, r1 373 blo 1b 374 dsb st 375 ret lr 376ENDPROC(v7_dma_inv_range) 377 378/* 379 * v7_dma_clean_range(start,end) 380 * - start - virtual start address of region 381 * - end - virtual end address of region 382 */ 383v7_dma_clean_range: 384 dcache_line_size r2, r3 385 sub r3, r2, #1 386 bic r0, r0, r3 387#ifdef CONFIG_ARM_ERRATA_764369 388 ALT_SMP(W(dsb)) 389 ALT_UP(W(nop)) 390#endif 3911: 392 mcr p15, 0, r0, c7, c10, 1 @ clean D / U line 393 add r0, r0, r2 394 cmp r0, r1 395 blo 1b 396 dsb st 397 ret lr 398ENDPROC(v7_dma_clean_range) 399 400/* 401 * v7_dma_flush_range(start,end) 402 * - start - virtual start address of region 403 * - end - virtual end address of region 404 */ 405ENTRY(v7_dma_flush_range) 406 dcache_line_size r2, r3 407 sub r3, r2, #1 408 bic r0, r0, r3 409#ifdef CONFIG_ARM_ERRATA_764369 410 ALT_SMP(W(dsb)) 411 ALT_UP(W(nop)) 412#endif 4131: 414 mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line 415 add r0, r0, r2 416 cmp r0, r1 417 blo 1b 418 dsb st 419 ret lr 420ENDPROC(v7_dma_flush_range) 421 422/* 423 * dma_map_area(start, size, dir) 424 * - start - kernel virtual start address 425 * - size - size of region 426 * - dir - DMA direction 427 */ 428ENTRY(v7_dma_map_area) 429 add r1, r1, r0 430 teq r2, #DMA_FROM_DEVICE 431 beq v7_dma_inv_range 432 b v7_dma_clean_range 433ENDPROC(v7_dma_map_area) 434 435/* 436 * dma_unmap_area(start, size, dir) 437 * - start - kernel virtual start address 438 * - size - size of region 439 * - dir - DMA direction 440 */ 441ENTRY(v7_dma_unmap_area) 442 add r1, r1, r0 443 teq r2, #DMA_TO_DEVICE 444 bne v7_dma_inv_range 445 ret lr 446ENDPROC(v7_dma_unmap_area) 447 448 __INITDATA 449 450 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 451 define_cache_functions v7 452 453 /* The Broadcom Brahma-B15 read-ahead cache requires some modifications 454 * to the v7_cache_fns, we only override the ones we need 455 */ 456#ifndef CONFIG_CACHE_B15_RAC 457 globl_equ b15_flush_kern_cache_all, v7_flush_kern_cache_all 458#endif 459 globl_equ b15_flush_icache_all, v7_flush_icache_all 460 globl_equ b15_flush_kern_cache_louis, v7_flush_kern_cache_louis 461 globl_equ b15_flush_user_cache_all, v7_flush_user_cache_all 462 globl_equ b15_flush_user_cache_range, v7_flush_user_cache_range 463 globl_equ b15_coherent_kern_range, v7_coherent_kern_range 464 globl_equ b15_coherent_user_range, v7_coherent_user_range 465 globl_equ b15_flush_kern_dcache_area, v7_flush_kern_dcache_area 466 467 globl_equ b15_dma_map_area, v7_dma_map_area 468 globl_equ b15_dma_unmap_area, v7_dma_unmap_area 469 globl_equ b15_dma_flush_range, v7_dma_flush_range 470 471 define_cache_functions b15 472