diff options
author | Vineet Gupta <vgupta@synopsys.com> | 2013-05-09 05:40:18 -0400 |
---|---|---|
committer | Vineet Gupta <vgupta@synopsys.com> | 2013-05-09 12:23:16 -0400 |
commit | 6ec18a81b22ab2b40df8424f2b5fc6be20ccad87 (patch) | |
tree | 974447f69a0a4b10dc0f1f7ff81440539761b4dc /arch/arc | |
parent | a690984d60abcb627ce1bcc0300a14043b5e224a (diff) |
ARC: [mm] Aliasing VIPT dcache support 1/4
This preps the low level dcache flush helpers to take vaddr argument in
addition to the existing paddr to properly flush the VIPT dcache
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'arch/arc')
-rw-r--r-- | arch/arc/include/asm/cacheflush.h | 2 | ||||
-rw-r--r-- | arch/arc/mm/cache_arc700.c | 48 | ||||
-rw-r--r-- | arch/arc/mm/tlb.c | 2 |
3 files changed, 34 insertions, 18 deletions
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h index ee1f6eae82d2..ed820bcb745e 100644 --- a/arch/arc/include/asm/cacheflush.h +++ b/arch/arc/include/asm/cacheflush.h | |||
@@ -33,7 +33,7 @@ void flush_cache_all(void); | |||
33 | void flush_icache_range(unsigned long start, unsigned long end); | 33 | void flush_icache_range(unsigned long start, unsigned long end); |
34 | void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len); | 34 | void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len); |
35 | void __inv_icache_page(unsigned long paddr, unsigned long vaddr); | 35 | void __inv_icache_page(unsigned long paddr, unsigned long vaddr); |
36 | void __flush_dcache_page(unsigned long paddr); | 36 | void __flush_dcache_page(unsigned long paddr, unsigned long vaddr); |
37 | 37 | ||
38 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 | 38 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 |
39 | 39 | ||
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 8a760e2c0341..a9a37089257a 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c | |||
@@ -269,9 +269,10 @@ static inline void __dc_entire_op(const int cacheop) | |||
269 | * Per Line Operation on D-Cache | 269 | * Per Line Operation on D-Cache |
270 | * Doesn't deal with type-of-op/IRQ-disabling/waiting-for-flush-to-complete | 270 | * Doesn't deal with type-of-op/IRQ-disabling/waiting-for-flush-to-complete |
271 | * It's sole purpose is to help gcc generate ZOL | 271 | * It's sole purpose is to help gcc generate ZOL |
272 | * (aliasing VIPT dcache flushing needs both vaddr and paddr) | ||
272 | */ | 273 | */ |
273 | static inline void __dc_line_loop(unsigned long paddr, unsigned long sz, | 274 | static inline void __dc_line_loop(unsigned long paddr, unsigned long vaddr, |
274 | int aux_reg) | 275 | unsigned long sz, const int aux_reg) |
275 | { | 276 | { |
276 | int num_lines; | 277 | int num_lines; |
277 | 278 | ||
@@ -284,31 +285,41 @@ static inline void __dc_line_loop(unsigned long paddr, unsigned long sz, | |||
284 | if (!(__builtin_constant_p(sz) && sz == PAGE_SIZE)) { | 285 | if (!(__builtin_constant_p(sz) && sz == PAGE_SIZE)) { |
285 | sz += paddr & ~DCACHE_LINE_MASK; | 286 | sz += paddr & ~DCACHE_LINE_MASK; |
286 | paddr &= DCACHE_LINE_MASK; | 287 | paddr &= DCACHE_LINE_MASK; |
288 | vaddr &= DCACHE_LINE_MASK; | ||
287 | } | 289 | } |
288 | 290 | ||
289 | num_lines = DIV_ROUND_UP(sz, ARC_DCACHE_LINE_LEN); | 291 | num_lines = DIV_ROUND_UP(sz, ARC_DCACHE_LINE_LEN); |
290 | 292 | ||
293 | #if (CONFIG_ARC_MMU_VER <= 2) | ||
294 | paddr |= (vaddr >> PAGE_SHIFT) & 0x1F; | ||
295 | #endif | ||
296 | |||
291 | while (num_lines-- > 0) { | 297 | while (num_lines-- > 0) { |
292 | #if (CONFIG_ARC_MMU_VER > 2) | 298 | #if (CONFIG_ARC_MMU_VER > 2) |
293 | /* | 299 | /* |
294 | * Just as for I$, in MMU v3, D$ ops also require | 300 | * Just as for I$, in MMU v3, D$ ops also require |
295 | * "tag" bits in DC_PTAG, "index" bits in FLDL,IVDL ops | 301 | * "tag" bits in DC_PTAG, "index" bits in FLDL,IVDL ops |
296 | * But we pass phy addr for both. This works since Linux | ||
297 | * doesn't support aliasing configs for D$, yet. | ||
298 | * Thus paddr is enough to provide both tag and index. | ||
299 | */ | 302 | */ |
300 | write_aux_reg(ARC_REG_DC_PTAG, paddr); | 303 | write_aux_reg(ARC_REG_DC_PTAG, paddr); |
301 | #endif | 304 | |
305 | write_aux_reg(aux_reg, vaddr); | ||
306 | vaddr += ARC_DCACHE_LINE_LEN; | ||
307 | #else | ||
308 | /* paddr contains stuffed vaddrs bits */ | ||
302 | write_aux_reg(aux_reg, paddr); | 309 | write_aux_reg(aux_reg, paddr); |
310 | #endif | ||
303 | paddr += ARC_DCACHE_LINE_LEN; | 311 | paddr += ARC_DCACHE_LINE_LEN; |
304 | } | 312 | } |
305 | } | 313 | } |
306 | 314 | ||
315 | /* For kernel mappings cache op index is same as paddr */ | ||
316 | #define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op) | ||
317 | |||
307 | /* | 318 | /* |
308 | * D-Cache : Per Line INV (discard or wback+discard) or FLUSH (wback) | 319 | * D-Cache : Per Line INV (discard or wback+discard) or FLUSH (wback) |
309 | */ | 320 | */ |
310 | static inline void __dc_line_op(unsigned long paddr, unsigned long sz, | 321 | static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, |
311 | const int cacheop) | 322 | unsigned long sz, const int cacheop) |
312 | { | 323 | { |
313 | unsigned long flags, tmp = tmp; | 324 | unsigned long flags, tmp = tmp; |
314 | int aux; | 325 | int aux; |
@@ -331,7 +342,7 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz, | |||
331 | else | 342 | else |
332 | aux = ARC_REG_DC_FLDL; | 343 | aux = ARC_REG_DC_FLDL; |
333 | 344 | ||
334 | __dc_line_loop(paddr, sz, aux); | 345 | __dc_line_loop(paddr, vaddr, sz, aux); |
335 | 346 | ||
336 | if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */ | 347 | if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */ |
337 | wait_for_flush(); | 348 | wait_for_flush(); |
@@ -346,7 +357,8 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz, | |||
346 | #else | 357 | #else |
347 | 358 | ||
348 | #define __dc_entire_op(cacheop) | 359 | #define __dc_entire_op(cacheop) |
349 | #define __dc_line_op(paddr, sz, cacheop) | 360 | #define __dc_line_op(paddr, vaddr, sz, cacheop) |
361 | #define __dc_line_op_k(paddr, sz, cacheop) | ||
350 | 362 | ||
351 | #endif /* CONFIG_ARC_HAS_DCACHE */ | 363 | #endif /* CONFIG_ARC_HAS_DCACHE */ |
352 | 364 | ||
@@ -462,19 +474,19 @@ EXPORT_SYMBOL(flush_dcache_page); | |||
462 | 474 | ||
463 | void dma_cache_wback_inv(unsigned long start, unsigned long sz) | 475 | void dma_cache_wback_inv(unsigned long start, unsigned long sz) |
464 | { | 476 | { |
465 | __dc_line_op(start, sz, OP_FLUSH_N_INV); | 477 | __dc_line_op_k(start, sz, OP_FLUSH_N_INV); |
466 | } | 478 | } |
467 | EXPORT_SYMBOL(dma_cache_wback_inv); | 479 | EXPORT_SYMBOL(dma_cache_wback_inv); |
468 | 480 | ||
469 | void dma_cache_inv(unsigned long start, unsigned long sz) | 481 | void dma_cache_inv(unsigned long start, unsigned long sz) |
470 | { | 482 | { |
471 | __dc_line_op(start, sz, OP_INV); | 483 | __dc_line_op_k(start, sz, OP_INV); |
472 | } | 484 | } |
473 | EXPORT_SYMBOL(dma_cache_inv); | 485 | EXPORT_SYMBOL(dma_cache_inv); |
474 | 486 | ||
475 | void dma_cache_wback(unsigned long start, unsigned long sz) | 487 | void dma_cache_wback(unsigned long start, unsigned long sz) |
476 | { | 488 | { |
477 | __dc_line_op(start, sz, OP_FLUSH); | 489 | __dc_line_op_k(start, sz, OP_FLUSH); |
478 | } | 490 | } |
479 | EXPORT_SYMBOL(dma_cache_wback); | 491 | EXPORT_SYMBOL(dma_cache_wback); |
480 | 492 | ||
@@ -555,7 +567,7 @@ void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len) | |||
555 | 567 | ||
556 | local_irq_save(flags); | 568 | local_irq_save(flags); |
557 | __ic_line_inv_vaddr(paddr, vaddr, len); | 569 | __ic_line_inv_vaddr(paddr, vaddr, len); |
558 | __dc_line_op(paddr, len, OP_FLUSH); | 570 | __dc_line_op(paddr, vaddr, len, OP_FLUSH); |
559 | local_irq_restore(flags); | 571 | local_irq_restore(flags); |
560 | } | 572 | } |
561 | 573 | ||
@@ -565,9 +577,13 @@ void __inv_icache_page(unsigned long paddr, unsigned long vaddr) | |||
565 | __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE); | 577 | __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE); |
566 | } | 578 | } |
567 | 579 | ||
568 | void __flush_dcache_page(unsigned long paddr) | 580 | /* |
581 | * wrapper to clearout kernel or userspace mappings of a page | ||
582 | * For kernel mappings @vaddr == @paddr | ||
583 | */ | ||
584 | void __flush_dcache_page(unsigned long paddr, unsigned long vaddr) | ||
569 | { | 585 | { |
570 | __dc_line_op(paddr, PAGE_SIZE, OP_FLUSH_N_INV); | 586 | __dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV); |
571 | } | 587 | } |
572 | 588 | ||
573 | void flush_icache_all(void) | 589 | void flush_icache_all(void) |
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 003d69ac6ffa..5810c7a92b77 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c | |||
@@ -438,7 +438,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned, | |||
438 | int dirty = test_and_clear_bit(PG_arch_1, &page->flags); | 438 | int dirty = test_and_clear_bit(PG_arch_1, &page->flags); |
439 | if (dirty) { | 439 | if (dirty) { |
440 | unsigned long paddr = pte_val(*ptep) & PAGE_MASK; | 440 | unsigned long paddr = pte_val(*ptep) & PAGE_MASK; |
441 | __flush_dcache_page(paddr); | 441 | __flush_dcache_page(paddr, paddr); |
442 | __inv_icache_page(paddr, vaddr); | 442 | __inv_icache_page(paddr, vaddr); |
443 | } | 443 | } |
444 | } | 444 | } |