Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Jan 2003 15:34:37 +0100 (CET)
From:      Harti Brandt <brandt@fokus.gmd.de>
To:        tmm@freebsd.org
Cc:        sparc@freebsd.org
Subject:   Problem with iommu_dvmamap_create
Message-ID:  <20030117151958.U715@beagle.fokus.gmd.de>

next in thread | raw e-mail | index | archive | help

Hi,

it seems, there is a problem in this function. I have a case, where my
driver creates a dma_tag with a maxsize of 64k-1, a maximum segment size
of 64k-1 and a large maximum number of segments (say 30...40). As soon, as
I create a DMA map with this tag, the io gets botched (up to the point,
that the boot prom reports a nvram checksum error). When I comment out the
code in iommu.c as follows I can at least create and destroy the maps
without any bad effect (I did not try to load them yet):

int
iommu_dvmamap_create(bus_dma_tag_t pt, bus_dma_tag_t dt, struct iommu_state *is,
    int flags, bus_dmamap_t *mapp)
{
	bus_size_t totsz, presz, currsz;
	int error, i, maxpre;

	if ((error = sparc64_dmamap_create(pt->dt_parent, dt, flags, mapp)) != 0)
		return (error);
	KASSERT(SLIST_EMPTY(&(*mapp)->dm_reslist),
	    ("iommu_dvmamap_create: hierarchy botched"));
	iommu_map_insq(*mapp);
	/*
	 * Preallocate DVMA space; if this fails now, it is retried at load
	 * time. Through bus_dmamap_load_mbuf() and bus_dmamap_load_uio(), it
	 * is possible to have multiple discontiguous segments in a single map,
	 * which is handled by allocating additional resources, instead of
	 * increasing the size, to avoid fragmentation.
	 * Clamp preallocation to BUS_SPACE_MAXSIZE. In some situations we can
	 * handle more; that case is handled by reallocating at map load time.
	 */
	totsz = ulmin(IOMMU_SIZE_ROUNDUP(dt->dt_maxsize), IOMMU_MAX_PRE);
	error = iommu_dvma_valloc(dt, is, *mapp, totsz);
	if (error != 0)
		return (0);
#if 0
	/*
	 * Try to be smart about preallocating some additional segments if
	 * needed.
	 */
	maxpre = imin(dt->dt_nsegments, IOMMU_MAX_PRE_SEG);
	presz = dt->dt_maxsize / maxpre;
	for (i = 0; i < maxpre && totsz < IOMMU_MAX_PRE; i++) {
		currsz = round_io_page(ulmin(presz, IOMMU_MAX_PRE - totsz));
		error = iommu_dvma_valloc(dt, is, *mapp, currsz);
		if (error != 0)
			break;
		totsz += currsz;
	}
#endif
	return (0);
}

The problem seems to be the dt_maxsize / maxpre. In my case this evaluates
to 0 and the call to valloc will use a currsz of 0. This seems to have bad
effects on the resource manager.

Also the loop will allocate one segment more than it needs (it does not
count the first allocation). This is, however, not critical.

I suggest also changing the comment above - it mentions BUS_SPACE_MAXSIZE,
but BUS_SPACE_MAXSIZE does not figure in the code (should be
IOMMU_MAX_PRE probably, which happens to be BUS_SPACE_MAXSIZE).

Regards,
harti
-- 
harti brandt, http://www.fokus.gmd.de/research/cc/cats/employees/hartmut.brandt/private
              brandt@fokus.gmd.de, brandt@fokus.fhg.de

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-sparc" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030117151958.U715>