diff options
| -rw-r--r-- | arch/arm/Kconfig | 2 | ||||
| -rw-r--r-- | arch/arm/include/asm/cacheflush.h | 56 | ||||
| -rw-r--r-- | arch/arm/mm/cache-v6.S | 30 | ||||
| -rw-r--r-- | arch/arm/mm/cache-v7.S | 16 |
4 files changed, 77 insertions, 27 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f6cdc21b562c..7562f884f2c5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -1002,7 +1002,7 @@ endif | |||
| 1002 | 1002 | ||
| 1003 | config ARM_ERRATA_411920 | 1003 | config ARM_ERRATA_411920 |
| 1004 | bool "ARM errata: Invalidation of the Instruction Cache operation can fail" | 1004 | bool "ARM errata: Invalidation of the Instruction Cache operation can fail" |
| 1005 | depends on CPU_V6 && !SMP | 1005 | depends on CPU_V6 |
| 1006 | help | 1006 | help |
| 1007 | Invalidation of the Instruction Cache operation can | 1007 | Invalidation of the Instruction Cache operation can |
| 1008 | fail. This erratum is present in 1136 (before r1p4), 1156 and 1176. | 1008 | fail. This erratum is present in 1136 (before r1p4), 1156 and 1176. |
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 4656a24058d2..a3db768ee5cc 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h | |||
| @@ -156,6 +156,12 @@ | |||
| 156 | * Please note that the implementation of these, and the required | 156 | * Please note that the implementation of these, and the required |
| 157 | * effects are cache-type (VIVT/VIPT/PIPT) specific. | 157 | * effects are cache-type (VIVT/VIPT/PIPT) specific. |
| 158 | * | 158 | * |
| 159 | * flush_icache_all() | ||
| 160 | * | ||
| 161 | * Unconditionally clean and invalidate the entire icache. | ||
| 162 | * Currently only needed for cache-v6.S and cache-v7.S, see | ||
| 163 | * __flush_icache_all for the generic implementation. | ||
| 164 | * | ||
| 159 | * flush_kern_all() | 165 | * flush_kern_all() |
| 160 | * | 166 | * |
| 161 | * Unconditionally clean and invalidate the entire cache. | 167 | * Unconditionally clean and invalidate the entire cache. |
| @@ -206,6 +212,7 @@ | |||
| 206 | */ | 212 | */ |
| 207 | 213 | ||
| 208 | struct cpu_cache_fns { | 214 | struct cpu_cache_fns { |
| 215 | void (*flush_icache_all)(void); | ||
| 209 | void (*flush_kern_all)(void); | 216 | void (*flush_kern_all)(void); |
| 210 | void (*flush_user_all)(void); | 217 | void (*flush_user_all)(void); |
| 211 | void (*flush_user_range)(unsigned long, unsigned long, unsigned int); | 218 | void (*flush_user_range)(unsigned long, unsigned long, unsigned int); |
| @@ -227,6 +234,7 @@ struct cpu_cache_fns { | |||
| 227 | 234 | ||
| 228 | extern struct cpu_cache_fns cpu_cache; | 235 | extern struct cpu_cache_fns cpu_cache; |
| 229 | 236 | ||
| 237 | #define __cpuc_flush_icache_all cpu_cache.flush_icache_all | ||
| 230 | #define __cpuc_flush_kern_all cpu_cache.flush_kern_all | 238 | #define __cpuc_flush_kern_all cpu_cache.flush_kern_all |
| 231 | #define __cpuc_flush_user_all cpu_cache.flush_user_all | 239 | #define __cpuc_flush_user_all cpu_cache.flush_user_all |
| 232 | #define __cpuc_flush_user_range cpu_cache.flush_user_range | 240 | #define __cpuc_flush_user_range cpu_cache.flush_user_range |
| @@ -246,6 +254,7 @@ extern struct cpu_cache_fns cpu_cache; | |||
| 246 | 254 | ||
| 247 | #else | 255 | #else |
| 248 | 256 | ||
| 257 | #define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all) | ||
| 249 | #define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all) | 258 | #define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all) |
| 250 | #define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all) | 259 | #define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all) |
| 251 | #define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range) | 260 | #define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range) |
| @@ -253,6 +262,7 @@ extern struct cpu_cache_fns cpu_cache; | |||
| 253 | #define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range) | 262 | #define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range) |
| 254 | #define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area) | 263 | #define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area) |
| 255 | 264 | ||
| 265 | extern void __cpuc_flush_icache_all(void); | ||
| 256 | extern void __cpuc_flush_kern_all(void); | 266 | extern void __cpuc_flush_kern_all(void); |
| 257 | extern void __cpuc_flush_user_all(void); | 267 | extern void __cpuc_flush_user_all(void); |
| 258 | extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); | 268 | extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); |
| @@ -291,6 +301,37 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *, | |||
| 291 | /* | 301 | /* |
| 292 | * Convert calls to our calling convention. | 302 | * Convert calls to our calling convention. |
| 293 | */ | 303 | */ |
| 304 | |||
| 305 | /* Invalidate I-cache */ | ||
| 306 | #define __flush_icache_all_generic() \ | ||
| 307 | asm("mcr p15, 0, %0, c7, c5, 0" \ | ||
| 308 | : : "r" (0)); | ||
| 309 | |||
| 310 | /* Invalidate I-cache inner shareable */ | ||
| 311 | #define __flush_icache_all_v7_smp() \ | ||
| 312 | asm("mcr p15, 0, %0, c7, c1, 0" \ | ||
| 313 | : : "r" (0)); | ||
| 314 | |||
| 315 | /* | ||
| 316 | * Optimized __flush_icache_all for the common cases. Note that UP ARMv7 | ||
| 317 | * will fall through to use __flush_icache_all_generic. | ||
| 318 | */ | ||
| 319 | #if (defined(CONFIG_CPU_V7) && defined(CONFIG_CPU_V6)) || \ | ||
| 320 | defined(CONFIG_SMP_ON_UP) | ||
| 321 | #define __flush_icache_preferred __cpuc_flush_icache_all | ||
| 322 | #elif __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP) | ||
| 323 | #define __flush_icache_preferred __flush_icache_all_v7_smp | ||
| 324 | #elif __LINUX_ARM_ARCH__ == 6 && defined(CONFIG_ARM_ERRATA_411920) | ||
| 325 | #define __flush_icache_preferred __cpuc_flush_icache_all | ||
| 326 | #else | ||
| 327 | #define __flush_icache_preferred __flush_icache_all_generic | ||
| 328 | #endif | ||
| 329 | |||
| 330 | static inline void __flush_icache_all(void) | ||
| 331 | { | ||
| 332 | __flush_icache_preferred(); | ||
| 333 | } | ||
| 334 | |||
| 294 | #define flush_cache_all() __cpuc_flush_kern_all() | 335 | #define flush_cache_all() __cpuc_flush_kern_all() |
| 295 | 336 | ||
| 296 | static inline void vivt_flush_cache_mm(struct mm_struct *mm) | 337 | static inline void vivt_flush_cache_mm(struct mm_struct *mm) |
| @@ -366,21 +407,6 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr | |||
| 366 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 | 407 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 |
| 367 | extern void flush_dcache_page(struct page *); | 408 | extern void flush_dcache_page(struct page *); |
| 368 | 409 | ||
| 369 | static inline void __flush_icache_all(void) | ||
| 370 | { | ||
| 371 | #ifdef CONFIG_ARM_ERRATA_411920 | ||
| 372 | extern void v6_icache_inval_all(void); | ||
| 373 | v6_icache_inval_all(); | ||
| 374 | #elif defined(CONFIG_SMP) && __LINUX_ARM_ARCH__ >= 7 | ||
| 375 | asm("mcr p15, 0, %0, c7, c1, 0 @ invalidate I-cache inner shareable\n" | ||
| 376 | : | ||
| 377 | : "r" (0)); | ||
| 378 | #else | ||
| 379 | asm("mcr p15, 0, %0, c7, c5, 0 @ invalidate I-cache\n" | ||
| 380 | : | ||
| 381 | : "r" (0)); | ||
| 382 | #endif | ||
| 383 | } | ||
| 384 | static inline void flush_kernel_vmap_range(void *addr, int size) | 410 | static inline void flush_kernel_vmap_range(void *addr, int size) |
| 385 | { | 411 | { |
| 386 | if ((cache_is_vivt() || cache_is_vipt_aliasing())) | 412 | if ((cache_is_vivt() || cache_is_vipt_aliasing())) |
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 86aa689ef1aa..99fa688dfadd 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S | |||
| @@ -21,18 +21,22 @@ | |||
| 21 | #define D_CACHE_LINE_SIZE 32 | 21 | #define D_CACHE_LINE_SIZE 32 |
| 22 | #define BTB_FLUSH_SIZE 8 | 22 | #define BTB_FLUSH_SIZE 8 |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_ARM_ERRATA_411920 | ||
| 25 | /* | 24 | /* |
| 26 | * Invalidate the entire I cache (this code is a workaround for the ARM1136 | 25 | * v6_flush_icache_all() |
| 27 | * erratum 411920 - Invalidate Instruction Cache operation can fail. This | 26 | * |
| 28 | * erratum is present in 1136, 1156 and 1176. It does not affect the MPCore. | 27 | * Flush the whole I-cache. |
| 29 | * | 28 | * |
| 30 | * Registers: | 29 | * ARM1136 erratum 411920 - Invalidate Instruction Cache operation can fail. |
| 31 | * r0 - set to 0 | 30 | * This erratum is present in 1136, 1156 and 1176. It does not affect the |
| 32 | * r1 - corrupted | 31 | * MPCore. |
| 32 | * | ||
| 33 | * Registers: | ||
| 34 | * r0 - set to 0 | ||
| 35 | * r1 - corrupted | ||
| 33 | */ | 36 | */ |
| 34 | ENTRY(v6_icache_inval_all) | 37 | ENTRY(v6_flush_icache_all) |
| 35 | mov r0, #0 | 38 | mov r0, #0 |
| 39 | #ifdef CONFIG_ARM_ERRATA_411920 | ||
| 36 | mrs r1, cpsr | 40 | mrs r1, cpsr |
| 37 | cpsid ifa @ disable interrupts | 41 | cpsid ifa @ disable interrupts |
| 38 | mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache | 42 | mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache |
| @@ -43,8 +47,11 @@ ENTRY(v6_icache_inval_all) | |||
| 43 | .rept 11 @ ARM Ltd recommends at least | 47 | .rept 11 @ ARM Ltd recommends at least |
| 44 | nop @ 11 NOPs | 48 | nop @ 11 NOPs |
| 45 | .endr | 49 | .endr |
| 46 | mov pc, lr | 50 | #else |
| 51 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I-cache | ||
| 47 | #endif | 52 | #endif |
| 53 | mov pc, lr | ||
| 54 | ENDPROC(v6_flush_icache_all) | ||
| 48 | 55 | ||
| 49 | /* | 56 | /* |
| 50 | * v6_flush_cache_all() | 57 | * v6_flush_cache_all() |
| @@ -60,7 +67,7 @@ ENTRY(v6_flush_kern_cache_all) | |||
| 60 | #ifndef CONFIG_ARM_ERRATA_411920 | 67 | #ifndef CONFIG_ARM_ERRATA_411920 |
| 61 | mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate | 68 | mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate |
| 62 | #else | 69 | #else |
| 63 | b v6_icache_inval_all | 70 | b v6_flush_icache_all |
| 64 | #endif | 71 | #endif |
| 65 | #else | 72 | #else |
| 66 | mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate | 73 | mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate |
| @@ -138,7 +145,7 @@ ENTRY(v6_coherent_user_range) | |||
| 138 | #ifndef CONFIG_ARM_ERRATA_411920 | 145 | #ifndef CONFIG_ARM_ERRATA_411920 |
| 139 | mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate | 146 | mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate |
| 140 | #else | 147 | #else |
| 141 | b v6_icache_inval_all | 148 | b v6_flush_icache_all |
| 142 | #endif | 149 | #endif |
| 143 | #else | 150 | #else |
| 144 | mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB | 151 | mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB |
| @@ -312,6 +319,7 @@ ENDPROC(v6_dma_unmap_area) | |||
| 312 | 319 | ||
| 313 | .type v6_cache_fns, #object | 320 | .type v6_cache_fns, #object |
| 314 | ENTRY(v6_cache_fns) | 321 | ENTRY(v6_cache_fns) |
| 322 | .long v6_flush_icache_all | ||
| 315 | .long v6_flush_kern_cache_all | 323 | .long v6_flush_kern_cache_all |
| 316 | .long v6_flush_user_cache_all | 324 | .long v6_flush_user_cache_all |
| 317 | .long v6_flush_user_cache_range | 325 | .long v6_flush_user_cache_range |
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index e8ea1a071f43..a3ebf7a4f49b 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S | |||
| @@ -18,6 +18,21 @@ | |||
| 18 | #include "proc-macros.S" | 18 | #include "proc-macros.S" |
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| 21 | * v7_flush_icache_all() | ||
| 22 | * | ||
| 23 | * Flush the whole I-cache. | ||
| 24 | * | ||
| 25 | * Registers: | ||
| 26 | * r0 - set to 0 | ||
| 27 | */ | ||
| 28 | ENTRY(v7_flush_icache_all) | ||
| 29 | mov r0, #0 | ||
| 30 | ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable | ||
| 31 | ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate | ||
| 32 | mov pc, lr | ||
| 33 | ENDPROC(v7_flush_icache_all) | ||
| 34 | |||
| 35 | /* | ||
| 21 | * v7_flush_dcache_all() | 36 | * v7_flush_dcache_all() |
| 22 | * | 37 | * |
| 23 | * Flush the whole D-cache. | 38 | * Flush the whole D-cache. |
| @@ -303,6 +318,7 @@ ENDPROC(v7_dma_unmap_area) | |||
| 303 | 318 | ||
| 304 | .type v7_cache_fns, #object | 319 | .type v7_cache_fns, #object |
| 305 | ENTRY(v7_cache_fns) | 320 | ENTRY(v7_cache_fns) |
| 321 | .long v7_flush_icache_all | ||
| 306 | .long v7_flush_kern_cache_all | 322 | .long v7_flush_kern_cache_all |
| 307 | .long v7_flush_user_cache_all | 323 | .long v7_flush_user_cache_all |
| 308 | .long v7_flush_user_cache_range | 324 | .long v7_flush_user_cache_range |
