diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-06-18 08:08:18 -0400 |
---|---|---|
committer | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-06-23 08:52:52 -0400 |
commit | ab61f7d21ab7f564fce322c498e4a7d6171140db (patch) | |
tree | d7fbdeea3ea85fd65ce20a5132e4264cb866c9c9 | |
parent | 75154f402ef18e459ff97ddece25656b6c2b329c (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>
-rw-r--r-- | arch/avr32/mm/cache.c | 14 |
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 @@ | |||
23 | void invalidate_dcache_region(void *start, size_t size) | 23 | void 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 | ||
55 | void clean_dcache_region(void *start, size_t size) | 51 | void clean_dcache_region(void *start, size_t size) |