diff options
author | Stuart Menefy <stuart.menefy@st.com> | 2009-08-24 05:39:39 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-24 05:39:39 -0400 |
commit | ffad9d7a54a5e809007135595c778715aa0fb07a (patch) | |
tree | b421ae948125190493186c52269d517e3688d094 /arch/sh/mm/cache-sh4.c | |
parent | a1fce732359b80ead84efba23059a5f1b572b85a (diff) |
sh: Fix problems with cache flushing when cache is in write-through mode
Change the method used to flush the cache in write-through mode to
avoid corrupted data being written back to memory.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm/cache-sh4.c')
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 7ce816188313..397c1030c7a6 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -592,6 +592,20 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, | |||
592 | * this with a cache invalidate to mark the cache line invalid. And do all | 592 | * this with a cache invalidate to mark the cache line invalid. And do all |
593 | * this with interrupts disabled, to avoid the cache line being accidently | 593 | * this with interrupts disabled, to avoid the cache line being accidently |
594 | * evicted while it is holding garbage. | 594 | * evicted while it is holding garbage. |
595 | * | ||
596 | * This also breaks in a number of circumstances: | ||
597 | * - if there are modifications to the region of memory just above | ||
598 | * empty_zero_page (for example because a breakpoint has been placed | ||
599 | * there), then these can be lost. | ||
600 | * | ||
601 | * This is because the the memory address which the cache temporarily | ||
602 | * caches in the above description is empty_zero_page. So the | ||
603 | * movca.l hits the cache (it is assumed that it misses, or at least | ||
604 | * isn't dirty), modifies the line and then invalidates it, losing the | ||
605 | * required change. | ||
606 | * | ||
607 | * - If caches are disabled or configured in write-through mode, then | ||
608 | * the movca.l writes garbage directly into memory. | ||
595 | */ | 609 | */ |
596 | static void __flush_dcache_segment_1way(unsigned long start, | 610 | static void __flush_dcache_segment_1way(unsigned long start, |
597 | unsigned long extent_per_way) | 611 | unsigned long extent_per_way) |
@@ -641,6 +655,25 @@ static void __flush_dcache_segment_1way(unsigned long start, | |||
641 | } while (a0 < a0e); | 655 | } while (a0 < a0e); |
642 | } | 656 | } |
643 | 657 | ||
658 | #ifdef CONFIG_CACHE_WRITETHROUGH | ||
659 | /* This method of cache flushing avoids the problems discussed | ||
660 | * in the comment above if writethrough caches are enabled. */ | ||
661 | static void __flush_dcache_segment_2way(unsigned long start, | ||
662 | unsigned long extent_per_way) | ||
663 | { | ||
664 | unsigned long array_addr; | ||
665 | |||
666 | array_addr = CACHE_OC_ADDRESS_ARRAY | | ||
667 | (start & cpu_data->dcache.entry_mask); | ||
668 | |||
669 | while (extent_per_way) { | ||
670 | ctrl_outl(0, array_addr); | ||
671 | ctrl_outl(0, array_addr + cpu_data->dcache.way_incr); | ||
672 | array_addr += cpu_data->dcache.linesz; | ||
673 | extent_per_way -= cpu_data->dcache.linesz; | ||
674 | } | ||
675 | } | ||
676 | #else | ||
644 | static void __flush_dcache_segment_2way(unsigned long start, | 677 | static void __flush_dcache_segment_2way(unsigned long start, |
645 | unsigned long extent_per_way) | 678 | unsigned long extent_per_way) |
646 | { | 679 | { |
@@ -699,6 +732,7 @@ static void __flush_dcache_segment_2way(unsigned long start, | |||
699 | a1 += linesz; | 732 | a1 += linesz; |
700 | } while (a0 < a0e); | 733 | } while (a0 < a0e); |
701 | } | 734 | } |
735 | #endif | ||
702 | 736 | ||
703 | static void __flush_dcache_segment_4way(unsigned long start, | 737 | static void __flush_dcache_segment_4way(unsigned long start, |
704 | unsigned long extent_per_way) | 738 | unsigned long extent_per_way) |