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

ARCv2: MMUv4: cache programming model changes

Caveats about cache flush on ARCv2 based cores

- dcache is PIPT so paddr is sufficient for cache maintenance ops (no
need to setup PTAG reg

- icache is still VIPT but only aliasing configs need PTAG setup

So basically this is departure from MMU-v3 which always need vaddr in
line ops registers (DC_IVDL, DC_FLDL, IC_IVIL) but paddr in DC_PTAG,
IC_PTAG respectively.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

+104 -18
+1 -1
arch/arc/Kconfig
··· 223 223 224 224 config ARC_CACHE_VIPT_ALIASING 225 225 bool "Support VIPT Aliasing D$" 226 - depends on ARC_HAS_DCACHE 226 + depends on ARC_HAS_DCACHE && ISA_ARCOMPACT 227 227 default n 228 228 229 229 endif #ARC_CACHE
+3 -2
arch/arc/include/asm/arcregs.h
··· 17 17 #define ARC_REG_FP_BCR 0x6B /* ARCompact: Single-Precision FPU */ 18 18 #define ARC_REG_DPFP_BCR 0x6C /* ARCompact: Dbl Precision FPU */ 19 19 #define ARC_REG_FP_V2_BCR 0xc8 /* ARCv2 FPU */ 20 + #define ARC_REG_SLC_BCR 0xce 20 21 #define ARC_REG_DCCM_BCR 0x74 /* DCCM Present + SZ */ 21 22 #define ARC_REG_TIMERS_BCR 0x75 22 23 #define ARC_REG_AP_BCR 0x76 ··· 332 331 }; 333 332 334 333 struct cpuinfo_arc_cache { 335 - unsigned int sz_k:8, line_len:8, assoc:4, ver:4, alias:1, vipt:1, pad:6; 334 + unsigned int sz_k:14, line_len:8, assoc:4, ver:4, alias:1, vipt:1; 336 335 }; 337 336 338 337 struct cpuinfo_arc_bpu { ··· 344 343 }; 345 344 346 345 struct cpuinfo_arc { 347 - struct cpuinfo_arc_cache icache, dcache; 346 + struct cpuinfo_arc_cache icache, dcache, slc; 348 347 struct cpuinfo_arc_mmu mmu; 349 348 struct cpuinfo_arc_bpu bpu; 350 349 struct bcr_identity core;
+3
arch/arc/include/asm/cache.h
··· 82 82 #define DC_CTRL_INV_MODE_FLUSH 0x40 83 83 #define DC_CTRL_FLUSH_STATUS 0x100 84 84 85 + /*System-level cache (L2 cache) related Auxiliary registers */ 86 + #define ARC_REG_SLC_CFG 0x901 87 + 85 88 #endif /* _ASM_CACHE_H */
+97 -15
arch/arc/mm/cache.c
··· 24 24 char *arc_cache_mumbojumbo(int c, char *buf, int len) 25 25 { 26 26 int n = 0; 27 + struct cpuinfo_arc_cache *p; 27 28 28 29 #define PR_CACHE(p, cfg, str) \ 29 30 if (!(p)->ver) \ ··· 40 39 PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache"); 41 40 PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache"); 42 41 42 + p = &cpuinfo_arc700[c].slc; 43 + if (p->ver) 44 + n += scnprintf(buf + n, len - n, 45 + "SLC\t\t: %uK, %uB Line\n", p->sz_k, p->line_len); 46 + 43 47 return buf; 44 48 } 45 49 ··· 55 49 */ 56 50 void read_decode_cache_bcr(void) 57 51 { 58 - struct cpuinfo_arc_cache *p_ic, *p_dc; 52 + struct cpuinfo_arc_cache *p_ic, *p_dc, *p_slc; 59 53 unsigned int cpu = smp_processor_id(); 60 54 struct bcr_cache { 61 55 #ifdef CONFIG_CPU_BIG_ENDIAN ··· 65 59 #endif 66 60 } ibcr, dbcr; 67 61 62 + struct bcr_generic sbcr; 63 + 64 + struct bcr_slc_cfg { 65 + #ifdef CONFIG_CPU_BIG_ENDIAN 66 + unsigned int pad:24, way:2, lsz:2, sz:4; 67 + #else 68 + unsigned int sz:4, lsz:2, way:2, pad:24; 69 + #endif 70 + } slc_cfg; 71 + 68 72 p_ic = &cpuinfo_arc700[cpu].icache; 69 73 READ_BCR(ARC_REG_IC_BCR, ibcr); 70 74 71 75 if (!ibcr.ver) 72 76 goto dc_chk; 73 77 74 - BUG_ON(ibcr.config != 3); 75 - p_ic->assoc = 2; /* Fixed to 2w set assoc */ 78 + if (ibcr.ver <= 3) { 79 + BUG_ON(ibcr.config != 3); 80 + p_ic->assoc = 2; /* Fixed to 2w set assoc */ 81 + } else if (ibcr.ver >= 4) { 82 + p_ic->assoc = 1 << ibcr.config; /* 1,2,4,8 */ 83 + } 84 + 76 85 p_ic->line_len = 8 << ibcr.line_len; 77 86 p_ic->sz_k = 1 << (ibcr.sz - 1); 78 87 p_ic->ver = ibcr.ver; ··· 99 78 READ_BCR(ARC_REG_DC_BCR, dbcr); 100 79 101 80 if (!dbcr.ver) 102 - return; 81 + goto slc_chk; 103 82 104 - BUG_ON(dbcr.config != 2); 105 - p_dc->assoc = 4; /* Fixed to 4w set assoc */ 83 + if (dbcr.ver <= 3) { 84 + BUG_ON(dbcr.config != 2); 85 + p_dc->assoc = 4; /* Fixed to 4w set assoc */ 86 + p_dc->vipt = 1; 87 + p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1; 88 + } else if (dbcr.ver >= 4) { 89 + p_dc->assoc = 1 << dbcr.config; /* 1,2,4,8 */ 90 + p_dc->vipt = 0; 91 + p_dc->alias = 0; /* PIPT so can't VIPT alias */ 92 + } 93 + 106 94 p_dc->line_len = 16 << dbcr.line_len; 107 95 p_dc->sz_k = 1 << (dbcr.sz - 1); 108 96 p_dc->ver = dbcr.ver; 109 - p_dc->vipt = 1; 110 - p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1; 97 + 98 + slc_chk: 99 + p_slc = &cpuinfo_arc700[cpu].slc; 100 + READ_BCR(ARC_REG_SLC_BCR, sbcr); 101 + if (sbcr.ver) { 102 + READ_BCR(ARC_REG_SLC_CFG, slc_cfg); 103 + p_slc->ver = sbcr.ver; 104 + p_slc->sz_k = 128 << slc_cfg.sz; 105 + p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64; 106 + } 111 107 } 112 108 113 109 /* ··· 263 225 } 264 226 } 265 227 228 + /* 229 + * In HS38x (MMU v4), although icache is VIPT, only paddr is needed for cache 230 + * maintenance ops (in IVIL reg), as long as icache doesn't alias. 231 + * 232 + * For Aliasing icache, vaddr is also needed (in IVIL), while paddr is 233 + * specified in PTAG (similar to MMU v3) 234 + */ 235 + static inline 236 + void __cache_line_loop_v4(unsigned long paddr, unsigned long vaddr, 237 + unsigned long sz, const int cacheop) 238 + { 239 + unsigned int aux_cmd; 240 + int num_lines; 241 + const int full_page_op = __builtin_constant_p(sz) && sz == PAGE_SIZE; 242 + 243 + if (cacheop == OP_INV_IC) { 244 + aux_cmd = ARC_REG_IC_IVIL; 245 + } else { 246 + /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ 247 + aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL; 248 + } 249 + 250 + /* Ensure we properly floor/ceil the non-line aligned/sized requests 251 + * and have @paddr - aligned to cache line and integral @num_lines. 252 + * This however can be avoided for page sized since: 253 + * -@paddr will be cache-line aligned already (being page aligned) 254 + * -@sz will be integral multiple of line size (being page sized). 255 + */ 256 + if (!full_page_op) { 257 + sz += paddr & ~CACHE_LINE_MASK; 258 + paddr &= CACHE_LINE_MASK; 259 + } 260 + 261 + num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES); 262 + 263 + while (num_lines-- > 0) { 264 + write_aux_reg(aux_cmd, paddr); 265 + paddr += L1_CACHE_BYTES; 266 + } 267 + } 268 + 266 269 #if (CONFIG_ARC_MMU_VER < 3) 267 270 #define __cache_line_loop __cache_line_loop_v2 268 271 #elif (CONFIG_ARC_MMU_VER == 3) 269 272 #define __cache_line_loop __cache_line_loop_v3 273 + #elif (CONFIG_ARC_MMU_VER > 3) 274 + #define __cache_line_loop __cache_line_loop_v4 270 275 #endif 271 276 272 277 #ifdef CONFIG_ARC_HAS_DCACHE ··· 750 669 751 670 if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) { 752 671 struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache; 753 - int handled; 754 672 755 673 if (!dc->ver) 756 674 panic("cache support enabled but non-existent cache\n"); ··· 758 678 panic("DCache line [%d] != kernel Config [%d]", 759 679 dc->line_len, L1_CACHE_BYTES); 760 680 761 - /* check for D-Cache aliasing */ 762 - handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING); 681 + /* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */ 682 + if (is_isa_arcompact()) { 683 + int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING); 763 684 764 - if (dc->alias && !handled) 765 - panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); 766 - else if (!dc->alias && handled) 767 - panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); 685 + if (dc->alias && !handled) 686 + panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); 687 + else if (!dc->alias && handled) 688 + panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); 689 + } 768 690 } 769 691 }