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>