summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2012-09-06 20:16:59 +0000
committerjhb <jhb@FreeBSD.org>2012-09-06 20:16:59 +0000
commit0bc0a2586ce9caa8fbee0c1f134bff3f6dec4f15 (patch)
tree01bf8e21104992b8d6a4b8388ad9b756dfcfa433
parentb483b4ba3d82feaef71fa09be9ad987686bd4204 (diff)
downloadFreeBSD-src-0bc0a2586ce9caa8fbee0c1f134bff3f6dec4f15.zip
FreeBSD-src-0bc0a2586ce9caa8fbee0c1f134bff3f6dec4f15.tar.gz
Dynamically allocate the S/G lists passed to callback routines rather than
allocating them on the stack of various bus_dmamap_load*() functions. The S/G lists are stored in the DMA tags. This matches the implementation on all other platforms. Discussed with: scottl, gibbs Tested by: stas (arm@)
-rw-r--r--sys/arm/arm/busdma_machdep.c60
-rw-r--r--sys/mips/mips/busdma_machdep.c61
2 files changed, 71 insertions, 50 deletions
diff --git a/sys/arm/arm/busdma_machdep.c b/sys/arm/arm/busdma_machdep.c
index 7deffed..ecda7f9 100644
--- a/sys/arm/arm/busdma_machdep.c
+++ b/sys/arm/arm/busdma_machdep.c
@@ -81,6 +81,7 @@ struct bus_dma_tag {
int map_count;
bus_dma_lock_t *lockfunc;
void *lockfuncarg;
+ bus_dma_segment_t *segments;
/*
* DMA range for this tag. If the page doesn't fall within
* one of these ranges, an error is returned. The caller
@@ -374,6 +375,8 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
newtag->lockfunc = dflt_lock;
newtag->lockfuncarg = NULL;
}
+ newtag->segments = NULL;
+
/*
* Take into account any restrictions imposed by our parent tag
*/
@@ -447,7 +450,6 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat)
#endif
if (dmat != NULL) {
-
if (dmat->map_count != 0)
return (EBUSY);
@@ -457,6 +459,8 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat)
parent = dmat->parent;
atomic_subtract_int(&dmat->ref_count, 1);
if (dmat->ref_count == 0) {
+ if (dmat->segments != NULL)
+ free(dmat->segments, M_DEVBUF);
free(dmat, M_DEVBUF);
/*
* Last reference count, so
@@ -484,6 +488,17 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
bus_dmamap_t newmap;
int error = 0;
+ if (dmat->segments == NULL) {
+ dmat->segments = (bus_dma_segment_t *)malloc(
+ sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+ M_NOWAIT);
+ if (dmat->segments == NULL) {
+ CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+ __func__, dmat, ENOMEM);
+ return (ENOMEM);
+ }
+ }
+
newmap = _busdma_alloc_dmamap();
if (newmap == NULL) {
CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
@@ -585,6 +600,16 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
mflags = M_NOWAIT;
else
mflags = M_WAITOK;
+ if (dmat->segments == NULL) {
+ dmat->segments = (bus_dma_segment_t *)malloc(
+ sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+ mflags);
+ if (dmat->segments == NULL) {
+ CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+ __func__, dmat, dmat->flags, ENOMEM);
+ return (ENOMEM);
+ }
+ }
if (flags & BUS_DMA_ZERO)
mflags |= M_ZERO;
@@ -883,11 +908,6 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
{
vm_offset_t lastaddr = 0;
int error, nsegs = -1;
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
KASSERT(dmat != NULL, ("dmatag is NULL"));
KASSERT(map != NULL, ("dmamap is NULL"));
@@ -898,14 +918,14 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
map->buffer = buf;
map->len = buflen;
error = bus_dmamap_load_buffer(dmat,
- dm_segments, map, buf, buflen, kernel_pmap,
+ dmat->segments, map, buf, buflen, kernel_pmap,
flags, &lastaddr, &nsegs);
if (error == EINPROGRESS)
return (error);
if (error)
(*callback)(callback_arg, NULL, 0, error);
else
- (*callback)(callback_arg, dm_segments, nsegs + 1, error);
+ (*callback)(callback_arg, dmat->segments, nsegs + 1, error);
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
__func__, dmat, dmat->flags, nsegs + 1, error);
@@ -921,11 +941,6 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
bus_dmamap_callback2_t *callback, void *callback_arg,
int flags)
{
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
int nsegs = -1, error = 0;
M_ASSERTPKTHDR(m0);
@@ -941,7 +956,7 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
for (m = m0; m != NULL && error == 0; m = m->m_next) {
if (m->m_len > 0) {
error = bus_dmamap_load_buffer(dmat,
- dm_segments, map, m->m_data, m->m_len,
+ dmat->segments, map, m->m_data, m->m_len,
pmap_kernel(), flags, &lastaddr, &nsegs);
map->len += m->m_len;
}
@@ -954,9 +969,9 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
/*
* force "no valid mappings" on error in callback.
*/
- (*callback)(callback_arg, dm_segments, 0, 0, error);
+ (*callback)(callback_arg, dmat->segments, 0, 0, error);
} else {
- (*callback)(callback_arg, dm_segments, nsegs + 1,
+ (*callback)(callback_arg, dmat->segments, nsegs + 1,
m0->m_pkthdr.len, error);
}
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
@@ -1012,11 +1027,6 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
int flags)
{
vm_offset_t lastaddr = 0;
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
int nsegs, i, error;
bus_size_t resid;
struct iovec *iov;
@@ -1048,8 +1058,8 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
caddr_t addr = (caddr_t) iov[i].iov_base;
if (minlen > 0) {
- error = bus_dmamap_load_buffer(dmat, dm_segments, map,
- addr, minlen, pmap, flags, &lastaddr, &nsegs);
+ error = bus_dmamap_load_buffer(dmat, dmat->segments,
+ map, addr, minlen, pmap, flags, &lastaddr, &nsegs);
map->len += minlen;
resid -= minlen;
@@ -1060,9 +1070,9 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
/*
* force "no valid mappings" on error in callback.
*/
- (*callback)(callback_arg, dm_segments, 0, 0, error);
+ (*callback)(callback_arg, dmat->segments, 0, 0, error);
} else {
- (*callback)(callback_arg, dm_segments, nsegs+1,
+ (*callback)(callback_arg, dmat->segments, nsegs+1,
uio->uio_resid, error);
}
diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c
index 8e0317d..62e5efd 100644
--- a/sys/mips/mips/busdma_machdep.c
+++ b/sys/mips/mips/busdma_machdep.c
@@ -80,6 +80,7 @@ struct bus_dma_tag {
int map_count;
bus_dma_lock_t *lockfunc;
void *lockfuncarg;
+ bus_dma_segment_t *segments;
struct bounce_zone *bounce_zone;
};
@@ -352,6 +353,8 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
newtag->lockfunc = dflt_lock;
newtag->lockfuncarg = NULL;
}
+ newtag->segments = NULL;
+
/*
* Take into account any restrictions imposed by our parent tag
*/
@@ -434,6 +437,8 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat)
parent = dmat->parent;
atomic_subtract_int(&dmat->ref_count, 1);
if (dmat->ref_count == 0) {
+ if (dmat->segments != NULL)
+ free(dmat->segments, M_DEVBUF);
free(dmat, M_DEVBUF);
/*
* Last reference count, so
@@ -442,7 +447,7 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat)
*/
dmat = parent;
} else
- dmat = NULL;
+ dmat = NULL;
}
}
CTR2(KTR_BUSDMA, "%s tag %p", __func__, dmat_copy);
@@ -461,6 +466,17 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
bus_dmamap_t newmap;
int error = 0;
+ if (dmat->segments == NULL) {
+ dmat->segments = (bus_dma_segment_t *)malloc(
+ sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+ M_NOWAIT);
+ if (dmat->segments == NULL) {
+ CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+ __func__, dmat, ENOMEM);
+ return (ENOMEM);
+ }
+ }
+
newmap = _busdma_alloc_dmamap();
if (newmap == NULL) {
CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
@@ -563,6 +579,16 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
mflags = M_NOWAIT;
else
mflags = M_WAITOK;
+ if (dmat->segments == NULL) {
+ dmat->segments = (bus_dma_segment_t *)malloc(
+ sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+ mflags);
+ if (dmat->segments == NULL) {
+ CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+ __func__, dmat, dmat->flags, ENOMEM);
+ return (ENOMEM);
+ }
+ }
if (flags & BUS_DMA_ZERO)
mflags |= M_ZERO;
@@ -824,11 +850,6 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
{
vm_offset_t lastaddr = 0;
int error, nsegs = -1;
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
KASSERT(dmat != NULL, ("dmatag is NULL"));
KASSERT(map != NULL, ("dmamap is NULL"));
@@ -839,14 +860,14 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
map->buffer = buf;
map->len = buflen;
error = bus_dmamap_load_buffer(dmat,
- dm_segments, map, buf, buflen, kernel_pmap,
+ dmat->segments, map, buf, buflen, kernel_pmap,
flags, &lastaddr, &nsegs);
if (error == EINPROGRESS)
return (error);
if (error)
(*callback)(callback_arg, NULL, 0, error);
else
- (*callback)(callback_arg, dm_segments, nsegs + 1, error);
+ (*callback)(callback_arg, dmat->segments, nsegs + 1, error);
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
__func__, dmat, dmat->flags, nsegs + 1, error);
@@ -862,11 +883,6 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
bus_dmamap_callback2_t *callback, void *callback_arg,
int flags)
{
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
int nsegs = -1, error = 0;
M_ASSERTPKTHDR(m0);
@@ -882,7 +898,7 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
for (m = m0; m != NULL && error == 0; m = m->m_next) {
if (m->m_len > 0) {
error = bus_dmamap_load_buffer(dmat,
- dm_segments, map, m->m_data, m->m_len,
+ dmat->segments, map, m->m_data, m->m_len,
kernel_pmap, flags, &lastaddr, &nsegs);
map->len += m->m_len;
}
@@ -895,9 +911,9 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
/*
* force "no valid mappings" on error in callback.
*/
- (*callback)(callback_arg, dm_segments, 0, 0, error);
+ (*callback)(callback_arg, dmat->segments, 0, 0, error);
} else {
- (*callback)(callback_arg, dm_segments, nsegs + 1,
+ (*callback)(callback_arg, dmat->segments, nsegs + 1,
m0->m_pkthdr.len, error);
}
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
@@ -953,11 +969,6 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
int flags)
{
vm_offset_t lastaddr = 0;
-#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT
- bus_dma_segment_t dm_segments[dmat->nsegments];
-#else
- bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
-#endif
int nsegs, i, error;
bus_size_t resid;
struct iovec *iov;
@@ -990,8 +1001,8 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
caddr_t addr = (caddr_t) iov[i].iov_base;
if (minlen > 0) {
- error = bus_dmamap_load_buffer(dmat, dm_segments, map,
- addr, minlen, pmap, flags, &lastaddr, &nsegs);
+ error = bus_dmamap_load_buffer(dmat, dmat->segments,
+ map, addr, minlen, pmap, flags, &lastaddr, &nsegs);
map->len += minlen;
resid -= minlen;
@@ -1002,9 +1013,9 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
/*
* force "no valid mappings" on error in callback.
*/
- (*callback)(callback_arg, dm_segments, 0, 0, error);
+ (*callback)(callback_arg, dmat->segments, 0, 0, error);
} else {
- (*callback)(callback_arg, dm_segments, nsegs+1,
+ (*callback)(callback_arg, dmat->segments, nsegs+1,
uio->uio_resid, error);
}
OpenPOWER on IntegriCloud