diff options
Diffstat (limited to 'arch/arc/mm/cache_arc700.c')
| -rw-r--r-- | arch/arc/mm/cache_arc700.c | 168 |
1 files changed, 96 insertions, 72 deletions
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 353b202c37c9..4670afc3b971 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c | |||
| @@ -77,21 +77,19 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) | |||
| 77 | { | 77 | { |
| 78 | int n = 0; | 78 | int n = 0; |
| 79 | 79 | ||
| 80 | #define PR_CACHE(p, enb, str) \ | 80 | #define PR_CACHE(p, cfg, str) \ |
| 81 | { \ | ||
| 82 | if (!(p)->ver) \ | 81 | if (!(p)->ver) \ |
| 83 | n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \ | 82 | n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \ |
| 84 | else \ | 83 | else \ |
| 85 | n += scnprintf(buf + n, len - n, \ | 84 | n += scnprintf(buf + n, len - n, \ |
| 86 | str"\t\t: (%uK) VIPT, %dway set-asc, %ub Line %s\n", \ | 85 | str"\t\t: %uK, %dway/set, %uB Line, %s%s%s\n", \ |
| 87 | TO_KB((p)->sz), (p)->assoc, (p)->line_len, \ | 86 | (p)->sz_k, (p)->assoc, (p)->line_len, \ |
| 88 | enb ? "" : "DISABLED (kernel-build)"); \ | 87 | (p)->vipt ? "VIPT" : "PIPT", \ |
| 89 | } | 88 | (p)->alias ? " aliasing" : "", \ |
| 89 | IS_ENABLED(cfg) ? "" : " (not used)"); | ||
| 90 | 90 | ||
| 91 | PR_CACHE(&cpuinfo_arc700[c].icache, IS_ENABLED(CONFIG_ARC_HAS_ICACHE), | 91 | PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache"); |
| 92 | "I-Cache"); | 92 | PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache"); |
| 93 | PR_CACHE(&cpuinfo_arc700[c].dcache, IS_ENABLED(CONFIG_ARC_HAS_DCACHE), | ||
| 94 | "D-Cache"); | ||
| 95 | 93 | ||
| 96 | return buf; | 94 | return buf; |
| 97 | } | 95 | } |
| @@ -116,20 +114,31 @@ void read_decode_cache_bcr(void) | |||
| 116 | p_ic = &cpuinfo_arc700[cpu].icache; | 114 | p_ic = &cpuinfo_arc700[cpu].icache; |
| 117 | READ_BCR(ARC_REG_IC_BCR, ibcr); | 115 | READ_BCR(ARC_REG_IC_BCR, ibcr); |
| 118 | 116 | ||
| 117 | if (!ibcr.ver) | ||
| 118 | goto dc_chk; | ||
| 119 | |||
| 119 | BUG_ON(ibcr.config != 3); | 120 | BUG_ON(ibcr.config != 3); |
| 120 | p_ic->assoc = 2; /* Fixed to 2w set assoc */ | 121 | p_ic->assoc = 2; /* Fixed to 2w set assoc */ |
| 121 | p_ic->line_len = 8 << ibcr.line_len; | 122 | p_ic->line_len = 8 << ibcr.line_len; |
| 122 | p_ic->sz = 0x200 << ibcr.sz; | 123 | p_ic->sz_k = 1 << (ibcr.sz - 1); |
| 123 | p_ic->ver = ibcr.ver; | 124 | p_ic->ver = ibcr.ver; |
| 125 | p_ic->vipt = 1; | ||
| 126 | p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1; | ||
| 124 | 127 | ||
| 128 | dc_chk: | ||
| 125 | p_dc = &cpuinfo_arc700[cpu].dcache; | 129 | p_dc = &cpuinfo_arc700[cpu].dcache; |
| 126 | READ_BCR(ARC_REG_DC_BCR, dbcr); | 130 | READ_BCR(ARC_REG_DC_BCR, dbcr); |
| 127 | 131 | ||
| 132 | if (!dbcr.ver) | ||
| 133 | return; | ||
| 134 | |||
| 128 | BUG_ON(dbcr.config != 2); | 135 | BUG_ON(dbcr.config != 2); |
| 129 | p_dc->assoc = 4; /* Fixed to 4w set assoc */ | 136 | p_dc->assoc = 4; /* Fixed to 4w set assoc */ |
| 130 | p_dc->line_len = 16 << dbcr.line_len; | 137 | p_dc->line_len = 16 << dbcr.line_len; |
| 131 | p_dc->sz = 0x200 << dbcr.sz; | 138 | p_dc->sz_k = 1 << (dbcr.sz - 1); |
| 132 | p_dc->ver = dbcr.ver; | 139 | p_dc->ver = dbcr.ver; |
| 140 | p_dc->vipt = 1; | ||
| 141 | p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1; | ||
| 133 | } | 142 | } |
| 134 | 143 | ||
| 135 | /* | 144 | /* |
| @@ -142,14 +151,16 @@ void read_decode_cache_bcr(void) | |||
| 142 | void arc_cache_init(void) | 151 | void arc_cache_init(void) |
| 143 | { | 152 | { |
| 144 | unsigned int __maybe_unused cpu = smp_processor_id(); | 153 | unsigned int __maybe_unused cpu = smp_processor_id(); |
| 145 | struct cpuinfo_arc_cache __maybe_unused *ic, __maybe_unused *dc; | ||
| 146 | char str[256]; | 154 | char str[256]; |
| 147 | 155 | ||
| 148 | printk(arc_cache_mumbojumbo(0, str, sizeof(str))); | 156 | printk(arc_cache_mumbojumbo(0, str, sizeof(str))); |
| 149 | 157 | ||
| 150 | #ifdef CONFIG_ARC_HAS_ICACHE | 158 | if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) { |
| 151 | ic = &cpuinfo_arc700[cpu].icache; | 159 | struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache; |
| 152 | if (ic->ver) { | 160 | |
| 161 | if (!ic->ver) | ||
| 162 | panic("cache support enabled but non-existent cache\n"); | ||
| 163 | |||
| 153 | if (ic->line_len != L1_CACHE_BYTES) | 164 | if (ic->line_len != L1_CACHE_BYTES) |
| 154 | panic("ICache line [%d] != kernel Config [%d]", | 165 | panic("ICache line [%d] != kernel Config [%d]", |
| 155 | ic->line_len, L1_CACHE_BYTES); | 166 | ic->line_len, L1_CACHE_BYTES); |
| @@ -158,26 +169,26 @@ void arc_cache_init(void) | |||
| 158 | panic("Cache ver [%d] doesn't match MMU ver [%d]\n", | 169 | panic("Cache ver [%d] doesn't match MMU ver [%d]\n", |
| 159 | ic->ver, CONFIG_ARC_MMU_VER); | 170 | ic->ver, CONFIG_ARC_MMU_VER); |
| 160 | } | 171 | } |
| 161 | #endif | ||
| 162 | 172 | ||
| 163 | #ifdef CONFIG_ARC_HAS_DCACHE | 173 | if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) { |
| 164 | dc = &cpuinfo_arc700[cpu].dcache; | 174 | struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache; |
| 165 | if (dc->ver) { | 175 | int handled; |
| 166 | unsigned int dcache_does_alias; | 176 | |
| 177 | if (!dc->ver) | ||
| 178 | panic("cache support enabled but non-existent cache\n"); | ||
| 167 | 179 | ||
| 168 | if (dc->line_len != L1_CACHE_BYTES) | 180 | if (dc->line_len != L1_CACHE_BYTES) |
| 169 | panic("DCache line [%d] != kernel Config [%d]", | 181 | panic("DCache line [%d] != kernel Config [%d]", |
| 170 | dc->line_len, L1_CACHE_BYTES); | 182 | dc->line_len, L1_CACHE_BYTES); |
| 171 | 183 | ||
| 172 | /* check for D-Cache aliasing */ | 184 | /* check for D-Cache aliasing */ |
| 173 | dcache_does_alias = (dc->sz / dc->assoc) > PAGE_SIZE; | 185 | handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING); |
| 174 | 186 | ||
| 175 | if (dcache_does_alias && !cache_is_vipt_aliasing()) | 187 | if (dc->alias && !handled) |
| 176 | panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); | 188 | panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); |
| 177 | else if (!dcache_does_alias && cache_is_vipt_aliasing()) | 189 | else if (!dc->alias && handled) |
| 178 | panic("Don't need CONFIG_ARC_CACHE_VIPT_ALIASING\n"); | 190 | panic("Don't need CONFIG_ARC_CACHE_VIPT_ALIASING\n"); |
| 179 | } | 191 | } |
| 180 | #endif | ||
| 181 | } | 192 | } |
| 182 | 193 | ||
| 183 | #define OP_INV 0x1 | 194 | #define OP_INV 0x1 |
| @@ -255,10 +266,32 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr, | |||
| 255 | * Machine specific helpers for Entire D-Cache or Per Line ops | 266 | * Machine specific helpers for Entire D-Cache or Per Line ops |
| 256 | */ | 267 | */ |
| 257 | 268 | ||
| 258 | static inline void wait_for_flush(void) | 269 | static unsigned int __before_dc_op(const int op) |
| 270 | { | ||
| 271 | unsigned int reg = reg; | ||
| 272 | |||
| 273 | if (op == OP_FLUSH_N_INV) { | ||
| 274 | /* Dcache provides 2 cmd: FLUSH or INV | ||
| 275 | * INV inturn has sub-modes: DISCARD or FLUSH-BEFORE | ||
| 276 | * flush-n-inv is achieved by INV cmd but with IM=1 | ||
| 277 | * So toggle INV sub-mode depending on op request and default | ||
| 278 | */ | ||
| 279 | reg = read_aux_reg(ARC_REG_DC_CTRL); | ||
| 280 | write_aux_reg(ARC_REG_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH) | ||
| 281 | ; | ||
| 282 | } | ||
| 283 | |||
| 284 | return reg; | ||
| 285 | } | ||
| 286 | |||
| 287 | static void __after_dc_op(const int op, unsigned int reg) | ||
| 259 | { | 288 | { |
| 260 | while (read_aux_reg(ARC_REG_DC_CTRL) & DC_CTRL_FLUSH_STATUS) | 289 | if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ |
| 261 | ; | 290 | while (read_aux_reg(ARC_REG_DC_CTRL) & DC_CTRL_FLUSH_STATUS); |
| 291 | |||
| 292 | /* Switch back to default Invalidate mode */ | ||
| 293 | if (op == OP_FLUSH_N_INV) | ||
| 294 | write_aux_reg(ARC_REG_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); | ||
| 262 | } | 295 | } |
| 263 | 296 | ||
| 264 | /* | 297 | /* |
| @@ -269,18 +302,10 @@ static inline void wait_for_flush(void) | |||
| 269 | */ | 302 | */ |
| 270 | static inline void __dc_entire_op(const int cacheop) | 303 | static inline void __dc_entire_op(const int cacheop) |
| 271 | { | 304 | { |
| 272 | unsigned int tmp = tmp; | 305 | unsigned int ctrl_reg; |
| 273 | int aux; | 306 | int aux; |
| 274 | 307 | ||
| 275 | if (cacheop == OP_FLUSH_N_INV) { | 308 | ctrl_reg = __before_dc_op(cacheop); |
| 276 | /* Dcache provides 2 cmd: FLUSH or INV | ||
| 277 | * INV inturn has sub-modes: DISCARD or FLUSH-BEFORE | ||
| 278 | * flush-n-inv is achieved by INV cmd but with IM=1 | ||
| 279 | * Default INV sub-mode is DISCARD, which needs to be toggled | ||
| 280 | */ | ||
| 281 | tmp = read_aux_reg(ARC_REG_DC_CTRL); | ||
| 282 | write_aux_reg(ARC_REG_DC_CTRL, tmp | DC_CTRL_INV_MODE_FLUSH); | ||
| 283 | } | ||
| 284 | 309 | ||
| 285 | if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ | 310 | if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ |
| 286 | aux = ARC_REG_DC_IVDC; | 311 | aux = ARC_REG_DC_IVDC; |
| @@ -289,12 +314,7 @@ static inline void __dc_entire_op(const int cacheop) | |||
| 289 | 314 | ||
| 290 | write_aux_reg(aux, 0x1); | 315 | write_aux_reg(aux, 0x1); |
| 291 | 316 | ||
| 292 | if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */ | 317 | __after_dc_op(cacheop, ctrl_reg); |
| 293 | wait_for_flush(); | ||
| 294 | |||
| 295 | /* Switch back the DISCARD ONLY Invalidate mode */ | ||
| 296 | if (cacheop == OP_FLUSH_N_INV) | ||
| 297 | write_aux_reg(ARC_REG_DC_CTRL, tmp & ~DC_CTRL_INV_MODE_FLUSH); | ||
| 298 | } | 318 | } |
| 299 | 319 | ||
| 300 | /* For kernel mappings cache operation: index is same as paddr */ | 320 | /* For kernel mappings cache operation: index is same as paddr */ |
| @@ -306,29 +326,16 @@ static inline void __dc_entire_op(const int cacheop) | |||
| 306 | static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, | 326 | static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, |
| 307 | unsigned long sz, const int cacheop) | 327 | unsigned long sz, const int cacheop) |
| 308 | { | 328 | { |
| 309 | unsigned long flags, tmp = tmp; | 329 | unsigned long flags; |
| 330 | unsigned int ctrl_reg; | ||
| 310 | 331 | ||
| 311 | local_irq_save(flags); | 332 | local_irq_save(flags); |
| 312 | 333 | ||
| 313 | if (cacheop == OP_FLUSH_N_INV) { | 334 | ctrl_reg = __before_dc_op(cacheop); |
| 314 | /* | ||
| 315 | * Dcache provides 2 cmd: FLUSH or INV | ||
| 316 | * INV inturn has sub-modes: DISCARD or FLUSH-BEFORE | ||
| 317 | * flush-n-inv is achieved by INV cmd but with IM=1 | ||
| 318 | * Default INV sub-mode is DISCARD, which needs to be toggled | ||
| 319 | */ | ||
| 320 | tmp = read_aux_reg(ARC_REG_DC_CTRL); | ||
| 321 | write_aux_reg(ARC_REG_DC_CTRL, tmp | DC_CTRL_INV_MODE_FLUSH); | ||
| 322 | } | ||
| 323 | 335 | ||
| 324 | __cache_line_loop(paddr, vaddr, sz, cacheop); | 336 | __cache_line_loop(paddr, vaddr, sz, cacheop); |
| 325 | 337 | ||
| 326 | if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */ | 338 | __after_dc_op(cacheop, ctrl_reg); |
| 327 | wait_for_flush(); | ||
| 328 | |||
| 329 | /* Switch back the DISCARD ONLY Invalidate mode */ | ||
| 330 | if (cacheop == OP_FLUSH_N_INV) | ||
| 331 | write_aux_reg(ARC_REG_DC_CTRL, tmp & ~DC_CTRL_INV_MODE_FLUSH); | ||
| 332 | 339 | ||
| 333 | local_irq_restore(flags); | 340 | local_irq_restore(flags); |
| 334 | } | 341 | } |
| @@ -389,8 +396,16 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, | |||
| 389 | /*********************************************************** | 396 | /*********************************************************** |
| 390 | * Machine specific helper for per line I-Cache invalidate. | 397 | * Machine specific helper for per line I-Cache invalidate. |
| 391 | */ | 398 | */ |
| 392 | static void __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, | 399 | |
| 393 | unsigned long sz) | 400 | static inline void __ic_entire_inv(void) |
| 401 | { | ||
| 402 | write_aux_reg(ARC_REG_IC_IVIC, 1); | ||
| 403 | read_aux_reg(ARC_REG_IC_CTRL); /* blocks */ | ||
| 404 | } | ||
| 405 | |||
| 406 | static inline void | ||
| 407 | __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, | ||
| 408 | unsigned long sz) | ||
| 394 | { | 409 | { |
| 395 | unsigned long flags; | 410 | unsigned long flags; |
| 396 | 411 | ||
| @@ -399,30 +414,39 @@ static void __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, | |||
| 399 | local_irq_restore(flags); | 414 | local_irq_restore(flags); |
| 400 | } | 415 | } |
| 401 | 416 | ||
| 402 | static inline void __ic_entire_inv(void) | 417 | #ifndef CONFIG_SMP |
| 403 | { | 418 | |
| 404 | write_aux_reg(ARC_REG_IC_IVIC, 1); | 419 | #define __ic_line_inv_vaddr(p, v, s) __ic_line_inv_vaddr_local(p, v, s) |
| 405 | read_aux_reg(ARC_REG_IC_CTRL); /* blocks */ | ||
| 406 | } | ||
| 407 | 420 | ||
| 408 | struct ic_line_inv_vaddr_ipi { | 421 | #else |
| 422 | |||
| 423 | struct ic_inv_args { | ||
| 409 | unsigned long paddr, vaddr; | 424 | unsigned long paddr, vaddr; |
| 410 | int sz; | 425 | int sz; |
| 411 | }; | 426 | }; |
| 412 | 427 | ||
| 413 | static void __ic_line_inv_vaddr_helper(void *info) | 428 | static void __ic_line_inv_vaddr_helper(void *info) |
| 414 | { | 429 | { |
| 415 | struct ic_line_inv_vaddr_ipi *ic_inv = (struct ic_line_inv_vaddr_ipi*) info; | 430 | struct ic_inv *ic_inv_args = (struct ic_inv_args *) info; |
| 431 | |||
| 416 | __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz); | 432 | __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz); |
| 417 | } | 433 | } |
| 418 | 434 | ||
| 419 | static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, | 435 | static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, |
| 420 | unsigned long sz) | 436 | unsigned long sz) |
| 421 | { | 437 | { |
| 422 | struct ic_line_inv_vaddr_ipi ic_inv = { paddr, vaddr , sz}; | 438 | struct ic_inv_args ic_inv = { |
| 439 | .paddr = paddr, | ||
| 440 | .vaddr = vaddr, | ||
| 441 | .sz = sz | ||
| 442 | }; | ||
| 443 | |||
| 423 | on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1); | 444 | on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1); |
| 424 | } | 445 | } |
| 425 | #else | 446 | |
| 447 | #endif /* CONFIG_SMP */ | ||
| 448 | |||
| 449 | #else /* !CONFIG_ARC_HAS_ICACHE */ | ||
| 426 | 450 | ||
| 427 | #define __ic_entire_inv() | 451 | #define __ic_entire_inv() |
| 428 | #define __ic_line_inv_vaddr(pstart, vstart, sz) | 452 | #define __ic_line_inv_vaddr(pstart, vstart, sz) |
