Module Name:    src
Committed By:   matt
Date:           Tue Jan 12 05:52:09 UTC 2010

Modified Files:
        src/sys/arch/mips/include [matt-nb5-mips64]: bus_dma.h
        src/sys/arch/mips/mips [matt-nb5-mips64]: bus_dma.c

Log Message:
Rework bounce buffers so that it can also deal with non-coherent buffers.


To generate a diff of this commit:
cvs rdiff -u -r1.9.18.1 -r1.9.18.2 src/sys/arch/mips/include/bus_dma.h
cvs rdiff -u -r1.22.16.9 -r1.22.16.10 src/sys/arch/mips/mips/bus_dma.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/mips/include/bus_dma.h
diff -u src/sys/arch/mips/include/bus_dma.h:1.9.18.1 src/sys/arch/mips/include/bus_dma.h:1.9.18.2
--- src/sys/arch/mips/include/bus_dma.h:1.9.18.1	Sun Jan 10 02:48:46 2010
+++ src/sys/arch/mips/include/bus_dma.h	Tue Jan 12 05:52:09 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.h,v 1.9.18.1 2010/01/10 02:48:46 matt Exp $ */
+/* $NetBSD: bus_dma.h,v 1.9.18.2 2010/01/12 05:52:09 matt Exp $ */
 
 /*-
  * Copyright (c) 1997, 1998, 2000, 2001 The NetBSD Foundation, Inc.
@@ -259,8 +259,17 @@
 	 * DMA map syncs.  Note that origibuflen is only used
 	 * for ID_BUFTYPE_LINEAR.
 	 */
-	void	*id_origbuf;		/* pointer to orig buffer if
-					   bouncing */
+	union {
+		void	*un_origbuf;		/* pointer to orig buffer if
+						   bouncing */
+		char	*un_linearbuf;
+		struct mbuf	*un_mbuf;
+		struct uio	*un_uio;
+	} id_origbuf_un;
+#define	id_origbuf		id_origbuf_un.un_origbuf
+#define	id_origlinearbuf	id_origbuf_un.un_linearbuf
+#define	id_origmbuf		id_origbuf_un.un_mbuf
+#define	id_origuio		id_origbuf_un.un_uio
 	bus_size_t id_origbuflen;	/* ...and size */
 	int	id_buftype;		/* type of buffer */
 

Index: src/sys/arch/mips/mips/bus_dma.c
diff -u src/sys/arch/mips/mips/bus_dma.c:1.22.16.9 src/sys/arch/mips/mips/bus_dma.c:1.22.16.10
--- src/sys/arch/mips/mips/bus_dma.c:1.22.16.9	Mon Jan 11 19:52:30 2010
+++ src/sys/arch/mips/mips/bus_dma.c	Tue Jan 12 05:52:09 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_dma.c,v 1.22.16.9 2010/01/11 19:52:30 matt Exp $	*/
+/*	$NetBSD: bus_dma.c,v 1.22.16.10 2010/01/12 05:52:09 matt Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.22.16.9 2010/01/11 19:52:30 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.22.16.10 2010/01/12 05:52:09 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -579,9 +579,8 @@
     bus_size_t len, int ops)
 {
 	bus_size_t minlen;
-	bus_addr_t addr;  
-	int i, useindex;
 
+#ifdef DIAGNOSTIC
 	/*
 	 * Mixing PRE and POST operations is not allowed.
 	 */
@@ -589,7 +588,6 @@
 	    (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
 		panic("_bus_dmamap_sync: mix PRE and POST");
 
-#ifdef DIAGNOSTIC
 	if (offset >= map->dm_mapsize)
 		panic("_bus_dmamap_sync: bad offset %"PRIxPADDR 
 			" (map size is %"PRIxPSIZE")",
@@ -615,117 +613,27 @@
 	 *
 	 *	POSTWRITE -- Nothing.
 	 */
-
 #ifdef _MIPS_NEED_BUS_DMA_BOUNCE
-	struct mips_bus_dma_cookie * cookie = map->_dm_cookie;
-	if (cookie != NULL && (cookie->id_flags & _BUS_DMA_IS_BOUNCING)) {
+	struct mips_bus_dma_cookie * const cookie = map->_dm_cookie;
+	if (cookie != NULL && (cookie->id_flags & _BUS_DMA_IS_BOUNCING)
+	    && (ops & BUS_DMASYNC_PREWRITE)) {
+		/*
+		 * Copy the caller's buffer to the bounce buffer.
+		 */
 		switch (cookie->id_buftype) {
 		case _BUS_DMA_BUFTYPE_LINEAR:
-			/*
-			 * Nothing to do for pre-read or post-write.
-			 */
-			if (ops & BUS_DMASYNC_PREWRITE) {
-				/* 
-				 * Copy the caller's buffer to the bounce
-				 * buffer.
-				 */ 
-				memcpy((char *)cookie->id_bouncebuf + offset,
-				    (char *)cookie->id_origbuf + offset, len);
-			}
-			if (ops & BUS_DMASYNC_POSTREAD) {
-				/*
-				 * Copy the bounce buffer to the caller's
-				 * buffer.
-				 */
-				memcpy((char *)cookie->id_origbuf + offset,
-				    (char *)cookie->id_bouncebuf + offset, len);
-			}
-
+			memcpy((char *)cookie->id_bouncebuf + offset,
+			    cookie->id_origlinearbuf + offset, len);
 			break;
-
 		case _BUS_DMA_BUFTYPE_MBUF:
-		    {
-			struct mbuf *m, *m0 = cookie->id_origbuf;
-			bus_size_t moff;
-
-			/*
-			 * Nothing to do for pre-read.
-			 */
-
-			if (ops & BUS_DMASYNC_PREWRITE) {
-				/*
-				 * Copy the caller's buffer to the bounce
-				 * buffer.
-				 */
-				m_copydata(m0, offset, len,
-				    (char *)cookie->id_bouncebuf + offset);
-			}
-
-			if (ops & BUS_DMASYNC_POSTREAD) {
-				/*
-				 * Copy the bounce buffer to the caller's
-				 * buffer.
-				 */
-				for (moff = offset, m = m0;
-				     m != NULL && len != 0;
-				     m = m->m_next) {
-					/* Find the beginning mbuf. */
-					if (moff >= m->m_len) {
-						moff -= m->m_len;
-						continue;
-					}
-
-					/*
-					 * Now at the first mbuf to sync; nail
-					 * each one until we have exhausted the
-					 * length.
-					 */
-					minlen = len < m->m_len - moff ?
-					    len : m->m_len - moff;
-
-					memcpy(mtod(m, char *) + moff,
-					    (char *)cookie->id_bouncebuf+offset,
-					    minlen);
-
-					moff = 0;
-					len -= minlen;
-					offset += minlen;
-				}
-			}
-
-			/*
-			 * Nothing to do for post-write.
-			 */
+			m_copydata(cookie->id_origmbuf, offset, len,
+			    (char *)cookie->id_bouncebuf + offset);
 			break;
-		    }
-		case _BUS_DMA_BUFTYPE_UIO: {
-			struct uio *uio;
-
-			uio = (struct uio *)cookie->id_origbuf;
-
-			/*
-			 * Nothing to do for pre-read.
-			 */
-
-			if (ops & BUS_DMASYNC_PREWRITE) {
-				/*
-				 * Copy the caller's buffer to the bounce buffer.
-				 */
-				_bus_dma_uiomove((char *)cookie->id_bouncebuf + offset,
-				    uio, len, UIO_WRITE);
-			}
-
-			if (ops & BUS_DMASYNC_POSTREAD) {
-				_bus_dma_uiomove((char *)cookie->id_bouncebuf + offset,
-				    uio, len, UIO_READ);
-			}
-
-			/*
-			 * Nothing to do for post-write.
-			 */
+		case _BUS_DMA_BUFTYPE_UIO:
+			_bus_dma_uiomove((char *)cookie->id_bouncebuf + offset,
+			    cookie->id_origuio, len, UIO_WRITE);
 			break;
-		    }
-
+#ifdef DIAGNOSTIC
 		case _BUS_DMA_BUFTYPE_RAW:
 			panic("_bus_dmamap_sync: _BUS_DMA_BUFTYPE_RAW");
 			break;
@@ -735,10 +643,12 @@
 			break;
 
 		default:
-			printf("unknown buffer type %d\n", cookie->id_buftype);
-			panic("_bus_dmamap_sync");
+			panic("_bus_dmamap_sync: unknown buffer type %d\n",
+			    cookie->id_buftype);
+			break;
+#endif /* DIAGNOSTIC */
 		}
-	} 
+	}
 #endif /* _MIPS_NEED_BUS_DMA_BOUNCE */
 
 	/*
@@ -747,16 +657,14 @@
 	 */
 	wbflush();
 
-	ops &= (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-	if (ops == 0)
-		return;
-
 	/*
-	 * If the mapping is of COHERENT DMA-safe memory, no cache
-	 * flush is necessary.
-	 */
-	if (map->_dm_flags & _BUS_DMAMAP_COHERENT)
-		return;
+	 * If the mapping is of COHERENT DMA-safe memory or this isn't a
+	 * PREREAD or PREWRITE, no cache flush is necessary.  Check to see
+	 * if we need to bounce it.
+	 */
+	if ((map->_dm_flags & _BUS_DMAMAP_COHERENT)
+	    || (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) == 0)
+		goto bounce_it;
 
 	/*
 	 * If the mapping belongs to the kernel, or it belongs
@@ -765,33 +673,33 @@
 	 *
 	 * This should be true the vast majority of the time.
 	 */
-	if (__predict_true(VMSPACE_IS_KERNEL_P(map->_dm_vmspace) ||
-	    map->_dm_vmspace == curproc->p_vmspace))
-		useindex = 0;
-	else
-		useindex = 1;
-
-	for (i = 0; i < map->dm_nsegs && len != 0; i++) {
-		/* Find the beginning segment. */
-		if (offset >= map->dm_segs[i].ds_len) {
-			offset -= map->dm_segs[i].ds_len;
-			continue;
-		}
+	const bool useindex = (!VMSPACE_IS_KERNEL_P(map->_dm_vmspace)
+	    && map->_dm_vmspace != curproc->p_vmspace);
 
+	bus_dma_segment_t *seg = map->dm_segs;
+	bus_dma_segment_t * const lastseg = seg + map->dm_nsegs;
+	/*
+	 * Skip segments until offset are withing a segment.
+	 */
+	for (; offset >= seg->ds_len; seg++) {
+		offset -= seg->ds_len;
+	}
+		
+	for (; seg < lastseg && len != 0; seg++, offset = 0, len -= minlen) {
 		/*
-		 * Now at the first segment to sync; nail
-		 * each segment until we have exhausted the
-		 * length.
+		 * Now at the first segment to sync; nail each segment until we
+		 * have exhausted the length.
 		 */
-		minlen = len < map->dm_segs[i].ds_len - offset ?
-		    len : map->dm_segs[i].ds_len - offset;
-
-		addr = map->dm_segs[i]._ds_vaddr;
+		vaddr_t vaddr = seg->_ds_vaddr + offset;
+		minlen = ulmin(len, seg->ds_len - offset);
 
 #ifdef BUS_DMA_DEBUG
 		printf("bus_dmamap_sync: flushing segment %d "
-		    "(0x%lx+%lx, 0x%lx+0x%lx) (olen = %ld)...", i,
-		    addr, offset, addr, offset + minlen - 1, len);
+		    "(0x%"PRIxVADDR"+%"PRIxBUSADDR
+		    ", 0x%"PRIxVADDR"+0x%"PRIxBUSADDR
+		    ") (olen = %"PRIxBUSADDR")...", i,
+		    vaddr - offset, offset,
+		    vaddr - offset, offset + minlen - 1, len);
 #endif
 
 		/*
@@ -799,38 +707,98 @@
 		 * Write-back,Invalidate, so just do one test.
 		 */
 		if (__predict_false(useindex)) {
-			mips_dcache_wbinv_range_index(addr + offset, minlen);
+			mips_dcache_wbinv_range_index(vaddr, minlen);
 #ifdef BUS_DMA_DEBUG
 			printf("\n");
 #endif
-			offset = 0;
-			len -= minlen;
 			continue;
 		}
 
 		switch (ops) {
 		case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
-			mips_dcache_wbinv_range(addr + offset, minlen);
+			mips_dcache_wbinv_range(vaddr, minlen);
 			break;
 
 		case BUS_DMASYNC_PREREAD:
 #if 1
-			mips_dcache_wbinv_range(addr + offset, minlen);
+			mips_dcache_wbinv_range(vaddr, minlen);
 #else
-			mips_dcache_inv_range(addr + offset, minlen);
+			mips_dcache_inv_range(vaddr, minlen);
 #endif
 			break;
 
 		case BUS_DMASYNC_PREWRITE:
-			mips_dcache_wb_range(addr + offset, minlen);
+			mips_dcache_wb_range(vaddr, minlen);
 			break;
 		}
 #ifdef BUS_DMA_DEBUG
 		printf("\n");
 #endif
-		offset = 0;
-		len -= minlen;
 	}
+
+  bounce_it:
+#ifdef _MIPS_NEED_BUS_DMA_BOUNCE
+	if ((ops & BUS_DMASYNC_POSTREAD) == 0
+	    || cookie == NULL
+	    || (cookie->id_flags & _BUS_DMA_IS_BOUNCING) == 0)
+		return;
+
+	/*
+	 * Copy the bounce buffer to the caller's buffer.
+	 */
+	switch (cookie->id_buftype) {
+	case _BUS_DMA_BUFTYPE_LINEAR:
+		memcpy(cookie->id_origlinearbuf + offset,
+		    (char *)cookie->id_bouncebuf + offset, len);
+		break;
+
+	case _BUS_DMA_BUFTYPE_MBUF: {
+		struct mbuf *m = cookie->id_origmbuf;
+		char *dp = cookie->id_bouncebuf;
+		char * const ep = dp + offset + len;
+
+		for (; offset >= m->m_len; m = m->m_next) {
+			offset -= m->m_len;
+			dp += m->m_len;
+		}
+		/*
+		 * Copy the bounce buffer to the caller's buffer.
+		 */
+		for (; dp < ep; m = m->m_next) {
+			/*
+			 * Now at the first mbuf to sync; nail
+			 * each one until we have exhausted the
+			 * length.
+			 */
+			minlen = ulmin(len, m->m_len - offset);
+			memcpy(mtod(m, char *) + offset, dp + offset, minlen);
+
+			offset = 0;
+			len -= minlen;
+			dp += minlen;
+		}
+		break;
+	}
+	case _BUS_DMA_BUFTYPE_UIO:
+		_bus_dma_uiomove((char *)cookie->id_bouncebuf + offset,
+		    cookie->id_origuio, len, UIO_READ);
+		break;
+#ifdef DIAGNOSTIC
+	case _BUS_DMA_BUFTYPE_RAW:
+		panic("_bus_dmamap_sync: _BUS_DMA_BUFTYPE_RAW");
+		break;
+
+	case _BUS_DMA_BUFTYPE_INVALID:
+		panic("_bus_dmamap_sync: _BUS_DMA_BUFTYPE_INVALID");
+		break;
+
+	default:
+		panic("_bus_dmamap_sync: unknown buffer type %d\n",
+		    cookie->id_buftype);
+		break;
+#endif
+	}
+#endif /* _MIPS_NEED_BUS_DMA_BOUNCE */
 }
 
 /*

Reply via email to