From: David Brownell <dbrownell@users.sourceforge.net>
Date: Sun, 28 Jan 2007 20:56:42 +0000 (-0800)
Subject: [AVR32] Fix incorrect invalidation of shared cachelines
X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=212868d387d0033b7e0029326a900126fe5e3d52;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git

[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>
---

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 @@
 
 void invalidate_dcache_region(void *start, size_t size)
 {
-	unsigned long v, begin, end, linesz;
+	unsigned long v, begin, end, linesz, mask;
+	int flush = 0;
 
 	linesz = boot_cpu_data.dcache.linesz;
+	mask = linesz - 1;
+
+	/* when first and/or last cachelines are shared, flush them
+	 * instead of invalidating ... never discard valid data!
+	 */
+	begin = (unsigned long)start;
+	end = begin + size - 1;
+
+	if (begin & mask) {
+		flush_dcache_line(start);
+		begin += linesz;
+		flush = 1;
+	}
+	if ((end & mask) != mask) {
+		flush_dcache_line((void *)end);
+		end -= linesz;
+		flush = 1;
+	}
 
-	//printk("invalidate dcache: %p + %u\n", start, size);
-
-	/* You asked for it, you got it */
-	begin = (unsigned long)start & ~(linesz - 1);
-	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
-
-	for (v = begin; v < end; v += linesz)
+	/* remaining cachelines only need invalidation */
+	for (v = begin; v <= end; v += linesz)
 		invalidate_dcache_line((void *)v);
+	if (flush)
+		flush_write_buffer();
 }
 
 void clean_dcache_region(void *start, size_t size)