diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-09-01 00:54:14 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-09-01 00:54:14 -0400 |
commit | ac6a0cf6716bb46813d0161024c66c2af66e53d1 (patch) | |
tree | c7f53b1a04c590032c022549f3186fb9b04f8358 /arch/sh/mm/cache-sh4.c | |
parent | e76a0136a3cf1859fbc07f122e42293d22229558 (diff) | |
parent | ce3f7cb96e67d6518c7fc7b361a76409c3817d64 (diff) |
Merge branch 'master' into sh/smp
Conflicts:
arch/sh/mm/cache-sh4.c
Diffstat (limited to 'arch/sh/mm/cache-sh4.c')
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 2775f84d9aa3..70fb906419dd 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -455,7 +455,49 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, | |||
455 | * Break the 1, 2 and 4 way variants of this out into separate functions to | 455 | * Break the 1, 2 and 4 way variants of this out into separate functions to |
456 | * avoid nearly all the overhead of having the conditional stuff in the function | 456 | * avoid nearly all the overhead of having the conditional stuff in the function |
457 | * bodies (+ the 1 and 2 way cases avoid saving any registers too). | 457 | * bodies (+ the 1 and 2 way cases avoid saving any registers too). |
458 | * | ||
459 | * We want to eliminate unnecessary bus transactions, so this code uses | ||
460 | * a non-obvious technique. | ||
461 | * | ||
462 | * Loop over a cache way sized block of, one cache line at a time. For each | ||
463 | * line, use movca.a to cause the current cache line contents to be written | ||
464 | * back, but without reading anything from main memory. However this has the | ||
465 | * side effect that the cache is now caching that memory location. So follow | ||
466 | * this with a cache invalidate to mark the cache line invalid. And do all | ||
467 | * this with interrupts disabled, to avoid the cache line being accidently | ||
468 | * evicted while it is holding garbage. | ||
469 | * | ||
470 | * This also breaks in a number of circumstances: | ||
471 | * - if there are modifications to the region of memory just above | ||
472 | * empty_zero_page (for example because a breakpoint has been placed | ||
473 | * there), then these can be lost. | ||
474 | * | ||
475 | * This is because the the memory address which the cache temporarily | ||
476 | * caches in the above description is empty_zero_page. So the | ||
477 | * movca.l hits the cache (it is assumed that it misses, or at least | ||
478 | * isn't dirty), modifies the line and then invalidates it, losing the | ||
479 | * required change. | ||
480 | * | ||
481 | * - If caches are disabled or configured in write-through mode, then | ||
482 | * the movca.l writes garbage directly into memory. | ||
458 | */ | 483 | */ |
484 | static void __flush_dcache_segment_writethrough(unsigned long start, | ||
485 | unsigned long extent_per_way) | ||
486 | { | ||
487 | unsigned long addr; | ||
488 | int i; | ||
489 | |||
490 | addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask); | ||
491 | |||
492 | while (extent_per_way) { | ||
493 | for (i = 0; i < cpu_data->dcache.ways; i++) | ||
494 | __raw_writel(0, addr + cpu_data->dcache.way_incr * i); | ||
495 | |||
496 | addr += cpu_data->dcache.linesz; | ||
497 | extent_per_way -= cpu_data->dcache.linesz; | ||
498 | } | ||
499 | } | ||
500 | |||
459 | static void __flush_dcache_segment_1way(unsigned long start, | 501 | static void __flush_dcache_segment_1way(unsigned long start, |
460 | unsigned long extent_per_way) | 502 | unsigned long extent_per_way) |
461 | { | 503 | { |
@@ -655,24 +697,30 @@ extern void __weak sh4__flush_region_init(void); | |||
655 | */ | 697 | */ |
656 | void __init sh4_cache_init(void) | 698 | void __init sh4_cache_init(void) |
657 | { | 699 | { |
700 | unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT); | ||
701 | |||
658 | printk("PVR=%08x CVR=%08x PRR=%08x\n", | 702 | printk("PVR=%08x CVR=%08x PRR=%08x\n", |
659 | ctrl_inl(CCN_PVR), | 703 | ctrl_inl(CCN_PVR), |
660 | ctrl_inl(CCN_CVR), | 704 | ctrl_inl(CCN_CVR), |
661 | ctrl_inl(CCN_PRR)); | 705 | ctrl_inl(CCN_PRR)); |
662 | 706 | ||
663 | switch (boot_cpu_data.dcache.ways) { | 707 | if (wt_enabled) |
664 | case 1: | 708 | __flush_dcache_segment_fn = __flush_dcache_segment_writethrough; |
665 | __flush_dcache_segment_fn = __flush_dcache_segment_1way; | 709 | else { |
666 | break; | 710 | switch (boot_cpu_data.dcache.ways) { |
667 | case 2: | 711 | case 1: |
668 | __flush_dcache_segment_fn = __flush_dcache_segment_2way; | 712 | __flush_dcache_segment_fn = __flush_dcache_segment_1way; |
669 | break; | 713 | break; |
670 | case 4: | 714 | case 2: |
671 | __flush_dcache_segment_fn = __flush_dcache_segment_4way; | 715 | __flush_dcache_segment_fn = __flush_dcache_segment_2way; |
672 | break; | 716 | break; |
673 | default: | 717 | case 4: |
674 | panic("unknown number of cache ways\n"); | 718 | __flush_dcache_segment_fn = __flush_dcache_segment_4way; |
675 | break; | 719 | break; |
720 | default: | ||
721 | panic("unknown number of cache ways\n"); | ||
722 | break; | ||
723 | } | ||
676 | } | 724 | } |
677 | 725 | ||
678 | local_flush_icache_range = sh4_flush_icache_range; | 726 | local_flush_icache_range = sh4_flush_icache_range; |