Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

csky: Support icache flush without specific instructions

Some CPUs don't support icache specific instructions to flush icache
lines in broadcast way. We use cpu control registers to flush local
icache and use IPI to notify other cores.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>

Guo Ren 761b4f69 a736fa1e

+32 -9
+4
arch/csky/Kconfig
··· 231 231 bool "CPU has FPU coprocessor" 232 232 depends on CPU_CK807 || CPU_CK810 || CPU_CK860 233 233 234 + config CPU_HAS_ICACHE_INS 235 + bool "CPU has Icache invalidate instructions" 236 + depends on CPU_HAS_CACHEV2 237 + 234 238 config CPU_HAS_TEE 235 239 bool "CPU has Trusted Execution Environment" 236 240 depends on CPU_CK810
+1
arch/csky/include/asm/cache.h
··· 16 16 17 17 void icache_inv_range(unsigned long start, unsigned long end); 18 18 void icache_inv_all(void); 19 + void local_icache_inv_all(void *priv); 19 20 20 21 void dcache_wb_range(unsigned long start, unsigned long end); 21 22 void dcache_wbinv_all(void);
+5
arch/csky/mm/cachev1.c
··· 94 94 cache_op_all(INS_CACHE|CACHE_INV, 0); 95 95 } 96 96 97 + void local_icache_inv_all(void *priv) 98 + { 99 + cache_op_all(INS_CACHE|CACHE_INV, 0); 100 + } 101 + 97 102 void dcache_wb_range(unsigned long start, unsigned long end) 98 103 { 99 104 cache_op_range(start, end, DATA_CACHE|CACHE_CLR, 0);
+22 -9
arch/csky/mm/cachev2.c
··· 3 3 4 4 #include <linux/spinlock.h> 5 5 #include <linux/smp.h> 6 + #include <linux/mm.h> 6 7 #include <asm/cache.h> 7 8 #include <asm/barrier.h> 8 9 9 - inline void dcache_wb_line(unsigned long start) 10 + #define INS_CACHE (1 << 0) 11 + #define CACHE_INV (1 << 4) 12 + 13 + void local_icache_inv_all(void *priv) 10 14 { 11 - asm volatile("dcache.cval1 %0\n"::"r"(start):"memory"); 15 + mtcr("cr17", INS_CACHE|CACHE_INV); 12 16 sync_is(); 13 17 } 14 18 19 + void icache_inv_all(void) 20 + { 21 + on_each_cpu(local_icache_inv_all, NULL, 1); 22 + } 23 + 24 + #ifdef CONFIG_CPU_HAS_ICACHE_INS 15 25 void icache_inv_range(unsigned long start, unsigned long end) 16 26 { 17 27 unsigned long i = start & ~(L1_CACHE_BYTES - 1); ··· 30 20 asm volatile("icache.iva %0\n"::"r"(i):"memory"); 31 21 sync_is(); 32 22 } 33 - 34 - void icache_inv_all(void) 23 + #else 24 + void icache_inv_range(unsigned long start, unsigned long end) 35 25 { 36 - asm volatile("icache.ialls\n":::"memory"); 26 + icache_inv_all(); 27 + } 28 + #endif 29 + 30 + inline void dcache_wb_line(unsigned long start) 31 + { 32 + asm volatile("dcache.cval1 %0\n"::"r"(start):"memory"); 37 33 sync_is(); 38 34 } 39 35 ··· 69 53 asm volatile("dcache.cval1 %0\n"::"r"(i):"memory"); 70 54 sync_is(); 71 55 72 - i = start & ~(L1_CACHE_BYTES - 1); 73 - for (; i < end; i += L1_CACHE_BYTES) 74 - asm volatile("icache.iva %0\n"::"r"(i):"memory"); 75 - sync_is(); 56 + icache_inv_range(start, end); 76 57 } 77 58 EXPORT_SYMBOL(cache_wbinv_range); 78 59