aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-06-18 08:08:18 -0400
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-06-23 08:52:52 -0400
commitab61f7d21ab7f564fce322c498e4a7d6171140db (patch)
treed7fbdeea3ea85fd65ce20a5132e4264cb866c9c9 /arch/avr32
parent75154f402ef18e459ff97ddece25656b6c2b329c (diff)
[AVR32] Fix bug in invalidate_dcache_region()
If (start + size) is not cacheline aligned and (start & mask) > (end & mask), the last but one cacheline won't be invalidated as it should. Fix this by rounding `end' down to the nearest cacheline boundary if it gets adjusted due to misalignment. Also flush the write buffer unconditionally -- if the dcache wrote back a line just before we invalidated it, the dirty data may be sitting in the write buffer waiting to corrupt our buffer later. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32')
-rw-r--r--arch/avr32/mm/cache.c14
1 files changed, 5 insertions, 9 deletions
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 8f7b1c3cd0f9..c1233c615e67 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -23,7 +23,6 @@
23void invalidate_dcache_region(void *start, size_t size) 23void invalidate_dcache_region(void *start, size_t size)
24{ 24{
25 unsigned long v, begin, end, linesz, mask; 25 unsigned long v, begin, end, linesz, mask;
26 int flush = 0;
27 26
28 linesz = boot_cpu_data.dcache.linesz; 27 linesz = boot_cpu_data.dcache.linesz;
29 mask = linesz - 1; 28 mask = linesz - 1;
@@ -32,24 +31,21 @@ void invalidate_dcache_region(void *start, size_t size)
32 * instead of invalidating ... never discard valid data! 31 * instead of invalidating ... never discard valid data!
33 */ 32 */
34 begin = (unsigned long)start; 33 begin = (unsigned long)start;
35 end = begin + size - 1; 34 end = begin + size;
36 35
37 if (begin & mask) { 36 if (begin & mask) {
38 flush_dcache_line(start); 37 flush_dcache_line(start);
39 begin += linesz; 38 begin += linesz;
40 flush = 1;
41 } 39 }
42 if ((end & mask) != mask) { 40 if (end & mask) {
43 flush_dcache_line((void *)end); 41 flush_dcache_line((void *)end);
44 end -= linesz; 42 end &= ~mask;
45 flush = 1;
46 } 43 }
47 44
48 /* remaining cachelines only need invalidation */ 45 /* remaining cachelines only need invalidation */
49 for (v = begin; v <= end; v += linesz) 46 for (v = begin; v < end; v += linesz)
50 invalidate_dcache_line((void *)v); 47 invalidate_dcache_line((void *)v);
51 if (flush) 48 flush_write_buffer();
52 flush_write_buffer();
53} 49}
54 50
55void clean_dcache_region(void *start, size_t size) 51void clean_dcache_region(void *start, size_t size)