diff options
| author | David Brownell <dbrownell@users.sourceforge.net> | 2007-01-28 15:56:42 -0500 |
|---|---|---|
| committer | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-02-09 09:01:57 -0500 |
| commit | 212868d387d0033b7e0029326a900126fe5e3d52 (patch) | |
| tree | dc4209d294def354963f22051caa7832f8de98c1 | |
| parent | 58febc0b1374de7506277d3aa9e9cddaea62ba65 (diff) | |
[AVR32] Fix incorrect invalidation of shared cachelines
Fix bug in dma_map_single(..., DMA_FROM_DEVICE) caused by incorrect
invalidation of shared cachelines at the beginning and/or end of
the specified buffer. Those shared cachelines need to be flushed,
since they may hold valid data (which must not be discarded).
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
| -rw-r--r-- | arch/avr32/mm/cache.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c index 450515b245a0..fb13f72e9a02 100644 --- a/arch/avr32/mm/cache.c +++ b/arch/avr32/mm/cache.c | |||
| @@ -22,18 +22,34 @@ | |||
| 22 | 22 | ||
| 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; | 25 | unsigned long v, begin, end, linesz, mask; |
| 26 | int flush = 0; | ||
| 26 | 27 | ||
| 27 | linesz = boot_cpu_data.dcache.linesz; | 28 | linesz = boot_cpu_data.dcache.linesz; |
| 29 | mask = linesz - 1; | ||
| 30 | |||
| 31 | /* when first and/or last cachelines are shared, flush them | ||
| 32 | * instead of invalidating ... never discard valid data! | ||
| 33 | */ | ||
| 34 | begin = (unsigned long)start; | ||
| 35 | end = begin + size - 1; | ||
| 36 | |||
| 37 | if (begin & mask) { | ||
| 38 | flush_dcache_line(start); | ||
| 39 | begin += linesz; | ||
| 40 | flush = 1; | ||
| 41 | } | ||
| 42 | if ((end & mask) != mask) { | ||
| 43 | flush_dcache_line((void *)end); | ||
| 44 | end -= linesz; | ||
| 45 | flush = 1; | ||
| 46 | } | ||
| 28 | 47 | ||
| 29 | //printk("invalidate dcache: %p + %u\n", start, size); | 48 | /* remaining cachelines only need invalidation */ |
| 30 | 49 | for (v = begin; v <= end; v += linesz) | |
| 31 | /* You asked for it, you got it */ | ||
| 32 | begin = (unsigned long)start & ~(linesz - 1); | ||
| 33 | end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); | ||
| 34 | |||
| 35 | for (v = begin; v < end; v += linesz) | ||
| 36 | invalidate_dcache_line((void *)v); | 50 | invalidate_dcache_line((void *)v); |
| 51 | if (flush) | ||
| 52 | flush_write_buffer(); | ||
| 37 | } | 53 | } |
| 38 | 54 | ||
| 39 | void clean_dcache_region(void *start, size_t size) | 55 | void clean_dcache_region(void *start, size_t size) |
