Subject: Re: net troubles
To: None <eeh@netbsd.org>
From: Takeshi Nakayama <tn@catvmics.ne.jp>
List: port-sparc64
Date: 06/12/2002 19:35:47
----Next_Part(Wed_Jun_12_19:23:22_2002_229)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

>>> eeh@netbsd.org wrote

> After looking at what you did to _bus_dmamap_load_mbuf() I 
> cannot see anything that would change it's behavior.  Other
> than limiting the numver of segments used to map->_dm_segcnt
> it should result in the exact same data layout as the old
> version.

Thanks for reviewing my patch.

I saw that it is not suitable to check the segments limit by
map->_dm_segcnt in _bus_dmamap_load_mbuf().

In this case, only when segments fragmentation occurs, it passes
the limitation check in dev/iommu.c. So, we need to check like the
attached patch I revised. The important part is the 2nd chunk of
dev/iommu.c.

I also revised _bus_dmamap_load() more properly.

Please review my patch again.

-- Takeshi Nakayama

----Next_Part(Wed_Jun_12_19:23:22_2002_229)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="netra-x1.fix2.diff"

Index: sys/arch/sparc64/dev/iommu.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sparc64/dev/iommu.c,v
retrieving revision 1.51
diff -u -d -u -r1.51 iommu.c
--- iommu.c	2002/05/13 21:01:15	1.51
+++ iommu.c	2002/06/11 21:36:07
@@ -537,7 +553,7 @@
 			map->dm_segs[seg].ds_len));
 		map->dm_segs[seg].ds_len =
 		    boundary - (sgstart & (boundary - 1));
-		if (++seg > map->_dm_segcnt) {
+		if (++seg >= map->_dm_segcnt) {
 			/* Too many segments.  Fail the operation. */
 			DPRINTF(IDB_INFO, ("iommu_dvmamap_load: "
 				"too many segments %d\n", seg));
@@ -789,6 +805,10 @@
 					(long)map->dm_segs[j].ds_addr, 
 					map->dm_segs[j].ds_len));
 			} else {
+				if (j >= map->_dm_segcnt) {
+					iommu_dvmamap_unload(t, is, map);
+					return (E2BIG);
+				}
 				map->dm_segs[j].ds_addr = sgstart;
 				map->dm_segs[j].ds_len = left;
 				DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: "
@@ -803,12 +823,12 @@
 				(sgend & ~(boundary - 1))) {
 				/* Need a new segment. */
 				map->dm_segs[j].ds_len =
-					sgstart & (boundary - 1);
+					boundary - (sgstart & (boundary - 1));
 				DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: "
 					"seg %d start %lx size %lx\n", j,
 					(long)map->dm_segs[j].ds_addr, 
 					map->dm_segs[j].ds_len));
-				if (++j > map->_dm_segcnt) {
+				if (++j >= map->_dm_segcnt) {
 					iommu_dvmamap_unload(t, is, map);
 					return (E2BIG);
 				}
@@ -874,12 +894,12 @@
 	map->dm_segs[i].ds_addr = sgstart;
 	while ((sgstart & ~(boundary - 1)) != (sgend & ~(boundary - 1))) {
 		/* Oops.  We crossed a boundary.  Split the xfer. */
-		map->dm_segs[i].ds_len = sgstart & (boundary - 1);
+		map->dm_segs[i].ds_len = boundary - (sgstart & (boundary - 1));
 		DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: "
 			"seg %d start %lx size %lx\n", i,
 			(long)map->dm_segs[i].ds_addr,
 			map->dm_segs[i].ds_len));
-		if (++i > map->_dm_segcnt) {
+		if (++i >= map->_dm_segcnt) {
 			/* Too many segments.  Fail the operation. */
 			s = splhigh();
 			/* How can this fail?  And if it does what can we do? */
Index: sys/arch/sparc64/sparc64/machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sparc64/sparc64/machdep.c,v
retrieving revision 1.119.6.1
diff -u -d -u -r1.119.6.1 machdep.c
--- machdep.c	2002/06/05 04:09:19	1.119.6.1
+++ machdep.c	2002/06/11 21:36:08
@@ -1112,7 +1112,8 @@
 	bus_dma_tag_t t;
 	bus_dmamap_t map;
 {
-
+	if (map->dm_nsegs)
+		bus_dmamap_unload(t, map);
 	free(map, M_DMAMAP);
 }
 
@@ -1165,24 +1166,30 @@
 	i = 0;
 	map->dm_segs[i].ds_addr = NULL;
 	map->dm_segs[i].ds_len = 0;
-	while (sgsize > 0 && i < map->_dm_segcnt) {
+	while (sgsize > 0) {
 		paddr_t pa;
+		long incr;
 
+		incr = NBPG - (vaddr & PGOFSET);
+		incr = min(sgsize, incr);
+
 		(void) pmap_extract(pmap_kernel(), vaddr, &pa);
-		sgsize -= NBPG;
-		vaddr += NBPG;
+		sgsize -= incr;
+		vaddr += incr;
 		if (map->dm_segs[i].ds_len == 0)
 			map->dm_segs[i].ds_addr = pa;
 		if (pa == (map->dm_segs[i].ds_addr + map->dm_segs[i].ds_len)
-		    && ((map->dm_segs[i].ds_len + NBPG) < map->_dm_maxsegsz)) {
+		    && ((map->dm_segs[i].ds_len + incr) <= map->_dm_maxsegsz)) {
 			/* Hey, waddyaknow, they're contiguous */
-			map->dm_segs[i].ds_len += NBPG;
+			map->dm_segs[i].ds_len += incr;
 			continue;
 		}
-		map->dm_segs[++i].ds_addr = pa;
+		if (++i >= map->_dm_segcnt)
+			return (E2BIG);
+		map->dm_segs[i].ds_addr = pa;
 		map->dm_segs[i].ds_len = NBPG;
 	}
-	map->dm_nsegs = i;
+	map->dm_nsegs = i + 1;
 	/* Mapping is bus dependent */
 	return (0);
 }
@@ -1197,7 +1204,6 @@
 	struct mbuf *m;
 	int flags;
 {
-#if 1
 	bus_dma_segment_t segs[MAX_DMA_SEGS];
 	int i;
 	size_t len;
@@ -1217,15 +1223,17 @@
 			paddr_t pa;
 			long incr;
 
-			incr = NBPG - (vaddr&PGOFSET);
+			incr = NBPG - (vaddr & PGOFSET);
 			incr = min(buflen, incr);
 
 			(void) pmap_extract(pmap_kernel(), vaddr, &pa);
 			buflen -= incr;
 			vaddr += incr;
 
-			if (i > 0 && pa == (segs[i-1].ds_addr + segs[i-1].ds_len)
-			    && ((segs[i-1].ds_len + incr) < map->_dm_maxsegsz)) {
+			if (i > 0 && 
+				pa == (segs[i-1].ds_addr + segs[i-1].ds_len) &&
+				((segs[i-1].ds_len + incr) <= 
+					map->_dm_maxsegsz)) {
 				/* Hey, waddyaknow, they're contiguous */
 				segs[i-1].ds_len += incr;
 				continue;
@@ -1285,13 +1293,8 @@
 		}
 		return (retval);
 	}
-#endif
-	return (bus_dmamap_load_raw(t, map, segs, i,
-			    (bus_size_t)len, flags));
-#else
-	panic("_bus_dmamap_load_mbuf: not implemented");
-	return 0;
 #endif
+	return (bus_dmamap_load_raw(t, map, segs, i, (bus_size_t)len, flags));
 }
 
 /*
@@ -1365,7 +1368,7 @@
 
 
 			if (i > 0 && pa == (segs[i-1].ds_addr + segs[i-1].ds_len)
-			    && ((segs[i-1].ds_len + incr) < map->_dm_maxsegsz)) {
+			    && ((segs[i-1].ds_len + incr) <= map->_dm_maxsegsz)) {
 				/* Hey, waddyaknow, they're contiguous */
 				segs[i-1].ds_len += incr;
 				continue;

----Next_Part(Wed_Jun_12_19:23:22_2002_229)----