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) |