Module Name:    src
Committed By:   matt
Date:           Wed Oct 17 20:17:19 UTC 2012

Modified Files:
        src/sys/arch/arm/arm32: bus_dma.c
        src/sys/arch/arm/include: bus_defs.h

Log Message:
Add per-segment and per-ragne flag (to store _BUS_DMAMAP_COHERENT).
Use the per-range flag to set the per-segment flag.
This allows bus_dma to skip flushing for known coherent memory regions.


To generate a diff of this commit:
cvs rdiff -u -r1.60 -r1.61 src/sys/arch/arm/arm32/bus_dma.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/include/bus_defs.h

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/arm/arm32/bus_dma.c
diff -u src/sys/arch/arm/arm32/bus_dma.c:1.60 src/sys/arch/arm/arm32/bus_dma.c:1.61
--- src/sys/arch/arm/arm32/bus_dma.c:1.60	Sat Oct  6 02:58:39 2012
+++ src/sys/arch/arm/arm32/bus_dma.c	Wed Oct 17 20:17:18 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_dma.c,v 1.60 2012/10/06 02:58:39 matt Exp $	*/
+/*	$NetBSD: bus_dma.c,v 1.61 2012/10/17 20:17:18 matt Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #define _ARM32_BUS_DMA_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.60 2012/10/06 02:58:39 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.61 2012/10/17 20:17:18 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -139,7 +139,7 @@ _bus_dma_busaddr_to_paddr(bus_dma_tag_t 
  */
 static int
 _bus_dmamap_load_paddr(bus_dma_tag_t t, bus_dmamap_t map,
-    bus_addr_t paddr, bus_size_t size)
+    bus_addr_t paddr, bus_size_t size, bool coherent)
 {
 	bus_dma_segment_t * const segs = map->dm_segs;
 	int nseg = map->dm_nsegs;
@@ -147,6 +147,7 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, 
 	bus_addr_t bmask = ~(map->_dm_boundary - 1);
 	bus_addr_t curaddr;
 	bus_size_t sgsize;
+	uint32_t _ds_flags = coherent ? _BUS_DMAMAP_COHERENT : 0;
 
 	if (nseg > 0)
 		lastaddr = segs[nseg-1].ds_addr + segs[nseg-1].ds_len;
@@ -163,7 +164,16 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, 
 		    _bus_dma_paddr_inrange(t->_ranges, t->_nranges, paddr);
 		if (dr == NULL)
 			return (EINVAL);
-		
+
+		/*
+		 * If this region is coherent, mark the segment as coherent.
+		 */
+		_ds_flags |= dr->dr_flags & _BUS_DMAMAP_COHERENT;
+#if 0
+		printf("%p: %#lx: range %#lx/%#lx/%#lx/%#x: %#x\n",
+		    t, paddr, dr->dr_sysbase, dr->dr_busbase,
+		    dr->dr_len, dr->dr_flags, _ds_flags);
+#endif
 		/*
 		 * In a valid DMA range.  Translate the physical
 		 * memory address to an address in the DMA window.
@@ -189,6 +199,7 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, 
 	 */
 	if (nseg > 0 && curaddr == lastaddr &&
 	    segs[nseg-1].ds_len + sgsize <= map->dm_maxsegsz &&
+	    ((segs[nseg-1]._ds_flags ^ _ds_flags) & _BUS_DMAMAP_COHERENT) == 0 &&
 	    (map->_dm_boundary == 0 ||
 	     (segs[nseg-1].ds_addr & bmask) == (curaddr & bmask))) {
 	     	/* coalesce */
@@ -199,6 +210,7 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, 
 		/* new segment */
 		segs[nseg].ds_addr = curaddr;
 		segs[nseg].ds_len = sgsize;
+		segs[nseg]._ds_flags = _ds_flags;
 		nseg++;
 	}
 
@@ -208,7 +220,8 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, 
 	size -= sgsize;
 	if (size > 0)
 		goto again;
-	
+
+	map->_dm_flags &= (_ds_flags & _BUS_DMAMAP_COHERENT);
 	map->dm_nsegs = nseg;
 	return (0);
 }
@@ -511,11 +524,8 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b
 	if (m0->m_pkthdr.len > map->_dm_size)
 		return (EINVAL);
 
-	/*
-	 * Mbuf chains should almost never have coherent (i.e.
-	 * un-cached) mappings, so clear that flag now.
-	 */
-	map->_dm_flags &= ~_BUS_DMAMAP_COHERENT;
+	/* _bus_dmamap_load_paddr() clears this if we're not... */
+	map->_dm_flags |= _BUS_DMAMAP_COHERENT;
 
 	error = 0;
 	for (m = m0; m != NULL && error == 0; m = m->m_next) {
@@ -541,7 +551,8 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b
 			paddr = m->m_ext.ext_paddr +
 			    (m->m_data - m->m_ext.ext_buf);
 			size = m->m_len;
-			error = _bus_dmamap_load_paddr(t, map, paddr, size);
+			error = _bus_dmamap_load_paddr(t, map, paddr, size,
+			    false);
 			break;
 		
 		case M_EXT|M_EXT_PAGES:
@@ -570,7 +581,7 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b
 				paddr = VM_PAGE_TO_PHYS(pg) + offset;
 
 				error = _bus_dmamap_load_paddr(t, map,
-				    paddr, size);
+				    paddr, size, false);
 				if (error)
 					break;
 				offset = 0;
@@ -582,7 +593,8 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, b
 			paddr = m->m_paddr + M_BUFOFFSET(m) +
 			    (m->m_data - M_BUFADDR(m));
 			size = m->m_len;
-			error = _bus_dmamap_load_paddr(t, map, paddr, size);
+			error = _bus_dmamap_load_paddr(t, map, paddr, size,
+			    false);
 			break;
 
 		default:
@@ -766,7 +778,9 @@ _bus_dmamap_sync_linear(bus_dma_tag_t t,
 		paddr_t pa = _bus_dma_busaddr_to_paddr(t, ds->ds_addr + offset);
 		size_t seglen = min(len, ds->ds_len - offset);
 
-		_bus_dmamap_sync_segment(va + offset, pa, seglen, ops, false);
+		if ((ds->_ds_flags & _BUS_DMAMAP_COHERENT) == 0)
+			_bus_dmamap_sync_segment(va + offset, pa, seglen, ops,
+			     false);
 
 		offset += seglen;
 		len -= seglen;
@@ -819,7 +833,9 @@ _bus_dmamap_sync_mbuf(bus_dma_tag_t t, b
 		 * cache), this will have to be revisited.
 		 */
 
-		_bus_dmamap_sync_segment(va, pa, seglen, ops, M_ROMAP(m));
+		if ((ds->_ds_flags & _BUS_DMAMAP_COHERENT) == 0)
+			_bus_dmamap_sync_segment(va, pa, seglen, ops,
+			    M_ROMAP(m));
 		voff += seglen;
 		ds_off += seglen;
 		len -= seglen;
@@ -857,7 +873,8 @@ _bus_dmamap_sync_uio(bus_dma_tag_t t, bu
 		vaddr_t va = (vaddr_t) iov->iov_base + voff;
 		paddr_t pa = _bus_dma_busaddr_to_paddr(t, ds->ds_addr + ds_off);
 
-		_bus_dmamap_sync_segment(va, pa, seglen, ops, false);
+		if ((ds->_ds_flags & _BUS_DMAMAP_COHERENT) == 0)
+			_bus_dmamap_sync_segment(va, pa, seglen, ops, false);
 
 		voff += seglen;
 		ds_off += seglen;
@@ -924,8 +941,9 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dm
 #endif
 
 	const int pre_ops = ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-	if (!bouncing && pre_ops == 0)
+	if (!bouncing && pre_ops == 0) {
 		return;
+	}
 
 #ifdef _ARM32_NEED_BUS_DMA_BOUNCE
 	if (bouncing && (ops & BUS_DMASYNC_PREWRITE)) {
@@ -1283,11 +1301,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
 	bus_size_t sgsize;
 	bus_addr_t curaddr;
 	vaddr_t vaddr = (vaddr_t)buf;
-	pd_entry_t *pde;
-	pt_entry_t pte;
 	int error;
 	pmap_t pmap;
-	pt_entry_t *ptep;
 
 #ifdef DEBUG_DMA
 	printf("_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d)\n",
@@ -1303,7 +1318,10 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
 		 * XXX Doesn't support checking for coherent mappings
 		 * XXX in user address space.
 		 */
+		bool coherent;
 		if (__predict_true(pmap == pmap_kernel())) {
+			pd_entry_t *pde;
+			pt_entry_t *ptep;
 			(void) pmap_get_pde_pte(pmap, vaddr, &pde, &ptep);
 			if (__predict_false(pmap_pde_section(pde))) {
 				paddr_t s_frame = L1_S_FRAME;
@@ -1315,32 +1333,24 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
 				}
 #endif
 				curaddr = (*pde & s_frame) | (vaddr & s_offset);
-				if (*pde & L1_S_CACHE_MASK) {
-					map->_dm_flags &= ~_BUS_DMAMAP_COHERENT;
-				}
+				coherent = (*pde & L1_S_CACHE_MASK) != 0;
 			} else {
-				pte = *ptep;
+				pt_entry_t pte = *ptep;
 				KDASSERT((pte & L2_TYPE_MASK) != L2_TYPE_INV);
 				if (__predict_false((pte & L2_TYPE_MASK)
 						    == L2_TYPE_L)) {
 					curaddr = (pte & L2_L_FRAME) |
 					    (vaddr & L2_L_OFFSET);
-					if (pte & L2_L_CACHE_MASK) {
-						map->_dm_flags &=
-						    ~_BUS_DMAMAP_COHERENT;
-					}
+					coherent = (pte & L2_L_CACHE_MASK) != 0;
 				} else {
 					curaddr = (pte & L2_S_FRAME) |
 					    (vaddr & L2_S_OFFSET);
-					if (pte & L2_S_CACHE_MASK) {
-						map->_dm_flags &=
-						    ~_BUS_DMAMAP_COHERENT;
-					}
+					coherent = (pte & L2_S_CACHE_MASK) != 0;
 				}
 			}
 		} else {
 			(void) pmap_extract(pmap, vaddr, &curaddr);
-			map->_dm_flags &= ~_BUS_DMAMAP_COHERENT;
+			coherent = false;
 		}
 
 		/*
@@ -1350,7 +1360,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
 		if (buflen < sgsize)
 			sgsize = buflen;
 
-		error = _bus_dmamap_load_paddr(t, map, curaddr, sgsize);
+		error = _bus_dmamap_load_paddr(t, map, curaddr, sgsize,
+		    coherent);
 		if (error)
 			return (error);
 

Index: src/sys/arch/arm/include/bus_defs.h
diff -u src/sys/arch/arm/include/bus_defs.h:1.2 src/sys/arch/arm/include/bus_defs.h:1.3
--- src/sys/arch/arm/include/bus_defs.h:1.2	Tue Sep 18 05:47:27 2012
+++ src/sys/arch/arm/include/bus_defs.h	Wed Oct 17 20:17:18 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_defs.h,v 1.2 2012/09/18 05:47:27 matt Exp $	*/
+/*	$NetBSD: bus_defs.h,v 1.3 2012/10/17 20:17:18 matt Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
@@ -330,6 +330,7 @@ struct arm32_bus_dma_segment {
 	 */
 	bus_addr_t	ds_addr;	/* DMA address */
 	bus_size_t	ds_len;		/* length of transfer */
+	uint32_t	_ds_flags;	/* _BUS_DMAMAP_COHERENT */
 };
 typedef struct arm32_bus_dma_segment	bus_dma_segment_t;
 
@@ -342,6 +343,7 @@ struct arm32_dma_range {
 	bus_addr_t	dr_sysbase;	/* system base address */
 	bus_addr_t	dr_busbase;	/* appears here on bus */
 	bus_size_t	dr_len;		/* length of range */
+	uint32_t	dr_flags;	/* flags for range */
 };
 
 /*

Reply via email to