Subject: bug in iommu_dvmamap_load_raw()
To: None <port-sparc64@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: port-sparc64
Date: 08/06/2001 21:31:27
--6TrnltStXW4iwmi0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
I think I've found a bug in iommu_dvmamap_load_raw(), in the part that
count the size we need to extent_alloc(): when we need a new page because the
previous segment(s) and the current one are not in the same page, if we
round_page the size after adding the current's segment len we loose the current
segement len. In the case of a mapping with 2 small segments, each in its own
page, we end up allocating one page instead of 2. iommu_dvmamap_unload()
will properly compute the size of 2 pages, and we'll panic in
extent_free().

The attached patch solve this (at last it allows if_tl to work on sparc64),
but maybe I've missed another corner case where we should round_page the
size after adding the len ...

BTW, I discovered this while working on if_tl, and it looks only
iommu_dvmamap_load_raw() (so bus_dmamap_load_raw(), bus_dmamap_load_mbuf(),
bus_dmamap_load_uio()) is affected. However, the hme driver doesn't use
bus_dmamap_load_mbuf() :)

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

--6TrnltStXW4iwmi0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

Index: iommu.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sparc64/dev/iommu.c,v
retrieving revision 1.36
diff -u -r1.36 iommu.c
--- iommu.c	2001/07/20 00:07:13	1.36
+++ iommu.c	2001/08/06 19:21:16
@@ -650,9 +650,9 @@
 	pa = segs[0].ds_addr;
 	sgsize = 0;
 	for (i=0; i<nsegs; i++) {
-		sgsize += segs[i].ds_len;
 		if (round_page(pa) != round_page(segs[i].ds_addr))
 			sgsize = round_page(sgsize);
+		sgsize += segs[i].ds_len;
 		pa = segs[i].ds_addr + segs[i].ds_len;
 	}
 	sgsize = round_page(sgsize);

--6TrnltStXW4iwmi0--