From owner-svn-src-projects@FreeBSD.ORG Wed Oct 28 03:34:06 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1ED021065670; Wed, 28 Oct 2009 03:34:06 +0000 (UTC) (envelope-from gonzo@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id E84058FC13; Wed, 28 Oct 2009 03:34:05 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n9S3Y5jn049538; Wed, 28 Oct 2009 03:34:05 GMT (envelope-from gonzo@svn.freebsd.org) Received: (from gonzo@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n9S3Y5NQ049536; Wed, 28 Oct 2009 03:34:05 GMT (envelope-from gonzo@svn.freebsd.org) Message-Id: <200910280334.n9S3Y5NQ049536@svn.freebsd.org> From: Oleksandr Tymoshenko Date: Wed, 28 Oct 2009 03:34:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r198534 - projects/mips/sys/mips/mips X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Oct 2009 03:34:06 -0000 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: