svn commit: r198534 - projects/mips/sys/mips/mips

Oleksandr Tymoshenko gonzo at FreeBSD.org
Wed Oct 28 03:34:06 UTC 2009


Author: gonzo
Date: Wed Oct 28 03:34:05 2009
New Revision: 198534
URL: http://svn.freebsd.org/changeset/base/198534

Log:
  - Fix busdma sync: dcache invalidation operates on cache line aligned
    addresses and could modify areas of memory that share the same cache
    line at the beginning and at the ending of the buffer. In order to
    prevent a data loss we save these chunks in temporary buffer before
    invalidation and restore them afer it.
  
  Idea suggested by: cognet

Modified:
  projects/mips/sys/mips/mips/busdma_machdep.c

Modified: projects/mips/sys/mips/mips/busdma_machdep.c
==============================================================================
--- projects/mips/sys/mips/mips/busdma_machdep.c	Wed Oct 28 02:20:29 2009	(r198533)
+++ projects/mips/sys/mips/mips/busdma_machdep.c	Wed Oct 28 03:34:05 2009	(r198534)
@@ -1029,10 +1029,43 @@ _bus_dmamap_unload(bus_dma_tag_t dmat, b
 static void
 bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op)
 {
+	char tmp_cl[mips_pdcache_linesize], tmp_clend[mips_pdcache_linesize];
+	vm_offset_t buf_cl, buf_clend;
+	vm_size_t size_cl, size_clend;
+	int cache_linesize_mask = mips_pdcache_linesize - 1;
+
+	/*
+	 * dcache invalidation operates on cache line aligned addresses
+	 * and could modify areas of memory that share the same cache line
+	 * at the beginning and the ending of the buffer. In order to 
+	 * prevent a data loss we save these chunks in temporary buffer
+	 * before invalidation and restore them afer it
+	 */
+	buf_cl = (vm_offset_t)buf  & ~cache_linesize_mask;
+	size_cl = (vm_offset_t)buf  & cache_linesize_mask;
+	buf_clend = (vm_offset_t)buf + len;
+	size_clend = (mips_pdcache_linesize - 
+	    (buf_clend & cache_linesize_mask)) & cache_linesize_mask;
+
 	switch (op) {
 	case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE:
 	case BUS_DMASYNC_POSTREAD:
+
+		/* 
+		 * Save buffers that might be modified by invalidation
+		 */
+		if (size_cl)
+			memcpy (tmp_cl, (void*)buf_cl, size_cl);
+		if (size_clend)
+			memcpy (tmp_clend, (void*)buf_clend, size_clend);
 		mips_dcache_inv_range((vm_offset_t)buf, len);
+		/* 
+		 * Restore them
+		 */
+		if (size_cl)
+			memcpy ((void*)buf_cl, tmp_cl, size_cl);
+		if (size_clend)
+			memcpy ((void*)buf_clend, tmp_clend, size_clend);
 		break;
 
 	case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
@@ -1040,11 +1073,21 @@ bus_dmamap_sync_buf(void *buf, int len, 
 		break;
 
 	case BUS_DMASYNC_PREREAD:
-#if 0
-		mips_dcache_wbinv_range((vm_offset_t)buf, len);
-#else
+		/* 
+		 * Save buffers that might be modified by invalidation
+		 */
+		if (size_cl)
+			memcpy (tmp_cl, (void *)buf_cl, size_cl);
+		if (size_clend)
+			memcpy (tmp_clend, (void *)buf_clend, size_clend);
 		mips_dcache_inv_range((vm_offset_t)buf, len);
-#endif
+		/*
+		 * Restore them
+		 */
+		if (size_cl)
+			memcpy ((void *)buf_cl, tmp_cl, size_cl);
+		if (size_clend)
+			memcpy ((void *)buf_clend, tmp_clend, size_clend);
 		break;
 
 	case BUS_DMASYNC_PREWRITE:


More information about the svn-src-projects mailing list