#define MAX_BPAGES 1024
+/*
+ * 16 x N declared on stack.
+ */
+#define BUS_DMA_CACHE_SEGMENTS 8
+
struct bounce_zone;
struct bus_dmamap;
int map_count;
bus_dma_segment_t *segments;
struct bounce_zone *bounce_zone;
+#ifdef SMP
+ struct spinlock spin;
+#else
+ int unused0;
+#endif
};
/*
return (retval);
}
+static __inline
+bus_dma_segment_t *
+bus_dma_tag_lock(bus_dma_tag_t tag, bus_dma_segment_t *cache)
+{
+ if (tag->nsegments <= BUS_DMA_CACHE_SEGMENTS)
+ return(cache);
+#ifdef SMP
+ spin_lock_wr(&tag->spin);
+#endif
+ return(tag->segments);
+}
+
+static __inline
+void
+bus_dma_tag_unlock(bus_dma_tag_t tag)
+{
+#ifdef SMP
+ if (tag->nsegments > BUS_DMA_CACHE_SEGMENTS)
+ spin_unlock_wr(&tag->spin);
+#endif
+}
+
/*
* Allocate a device specific dma_tag.
*/
/* Return a NULL tag on failure */
*dmat = NULL;
- newtag = kmalloc(sizeof(*newtag), M_DEVBUF, M_INTWAIT);
+ newtag = kmalloc(sizeof(*newtag), M_DEVBUF, M_INTWAIT | M_ZERO);
+ spin_init(&newtag->spin);
newtag->parent = parent;
newtag->alignment = alignment;
newtag->boundary = boundary;
return (0);
}
+bus_size_t
+bus_dma_tag_getmaxsize(bus_dma_tag_t tag)
+{
+ return(tag->maxsize);
+}
+
/*
* Allocate a handle for mapping from kva/uva/physical
* address space into bus device space.
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
vm_paddr_t lastaddr = 0;
int error, nsegs = 1;
map->callback_arg = callback_arg;
}
+ segments = bus_dma_tag_lock(dmat, cache_segments);
error = _bus_dmamap_load_buffer(dmat, map, buf, buflen,
- dmat->segments, dmat->nsegments,
+ segments, dmat->nsegments,
NULL, flags, &lastaddr, &nsegs, 1);
- if (error == EINPROGRESS)
+ if (error == EINPROGRESS) {
+ bus_dma_tag_unlock(dmat);
return error;
-
- callback(callback_arg, dmat->segments, nsegs, error);
+ }
+ callback(callback_arg, segments, nsegs, error);
+ bus_dma_tag_unlock(dmat);
return 0;
}
bus_dmamap_callback2_t *callback, void *callback_arg,
int flags)
{
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
int nsegs, error;
/*
flags &= ~BUS_DMA_WAITOK;
flags |= BUS_DMA_NOWAIT;
+ segments = bus_dma_tag_lock(dmat, cache_segments);
error = bus_dmamap_load_mbuf_segment(dmat, map, m0,
- dmat->segments, dmat->nsegments, &nsegs, flags);
+ segments, dmat->nsegments, &nsegs, flags);
if (error) {
/* force "no valid mappings" in callback */
- callback(callback_arg, dmat->segments, 0, 0, error);
+ callback(callback_arg, segments, 0,
+ 0, error);
} else {
- callback(callback_arg, dmat->segments, nsegs,
+ callback(callback_arg, segments, nsegs,
m0->m_pkthdr.len, error);
}
+ bus_dma_tag_unlock(dmat);
return error;
}
bus_size_t resid;
struct iovec *iov;
pmap_t pmap;
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
+ bus_dma_segment_t *segs;
+ int nsegs_left;
+
+ if (dmat->nsegments <= BUS_DMA_CACHE_SEGMENTS)
+ segments = cache_segments;
+ else
+ segments = kmalloc(sizeof(bus_dma_segment_t) * dmat->nsegments,
+ M_DEVBUF, M_WAITOK | M_ZERO);
/*
* XXX
resid = uio->uio_resid;
iov = uio->uio_iov;
+ segs = segments;
+ nsegs_left = dmat->nsegments;
+
if (uio->uio_segflg == UIO_USERSPACE) {
struct thread *td;
caddr_t addr = (caddr_t) iov[i].iov_base;
error = _bus_dmamap_load_buffer(dmat, map, addr, minlen,
- dmat->segments, dmat->nsegments,
+ segs, nsegs_left,
pmap, flags, &lastaddr, &nsegs, first);
first = 0;
resid -= minlen;
+ if (error == 0) {
+ nsegs_left -= nsegs;
+ segs += nsegs;
+ }
}
+ /*
+ * Minimum one DMA segment, even if 0-length buffer.
+ */
+ if (nsegs_left == dmat->nsegments)
+ --nsegs_left;
+
if (error) {
/* force "no valid mappings" in callback */
- callback(callback_arg, dmat->segments, 0, 0, error);
+ callback(callback_arg, segments, 0, 0, error);
} else {
- callback(callback_arg, dmat->segments, nsegs,
+ callback(callback_arg, segments, dmat->nsegments - nsegs_left,
uio->uio_resid, error);
}
+ if (dmat->nsegments > BUS_DMA_CACHE_SEGMENTS)
+ kfree(segments, M_DEVBUF);
return error;
}
#define MAX_BPAGES 1024
+/*
+ * 16 x N declared on stack.
+ */
+#define BUS_DMA_CACHE_SEGMENTS 8
+
struct bounce_zone;
struct bus_dmamap;
int map_count;
bus_dma_segment_t *segments;
struct bounce_zone *bounce_zone;
+#ifdef SMP
+ struct spinlock spin;
+#else
+ int unused0;
+#endif
};
/*
/* Return a NULL tag on failure */
*dmat = NULL;
- newtag = kmalloc(sizeof(*newtag), M_DEVBUF, M_INTWAIT);
+ newtag = kmalloc(sizeof(*newtag), M_DEVBUF, M_INTWAIT | M_ZERO);
+ spin_init(&newtag->spin);
newtag->parent = parent;
newtag->alignment = alignment;
newtag->boundary = boundary;
return (0);
}
+bus_size_t
+bus_dma_tag_getmaxsize(bus_dma_tag_t tag)
+{
+ return(tag->maxsize);
+}
+
/*
* Allocate a handle for mapping from kva/uva/physical
* address space into bus device space.
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
vm_paddr_t lastaddr = 0;
int error, nsegs = 1;
map->callback_arg = callback_arg;
}
+ segments = bus_dma_tag_lock(dmat, cache_segments);
error = _bus_dmamap_load_buffer(dmat, map, buf, buflen,
- dmat->segments, dmat->nsegments,
+ segments, dmat->nsegments,
NULL, flags, &lastaddr, &nsegs, 1);
- if (error == EINPROGRESS)
+ if (error == EINPROGRESS) {
+ bus_dma_tag_unlock(dmat);
return error;
+ }
- callback(callback_arg, dmat->segments, nsegs, error);
+ callback(callback_arg, segments, nsegs, error);
+ callback(callback_arg, segments, nsegs, error);
+ bus_dma_tag_unlock(dmat);
return 0;
}
bus_dmamap_callback2_t *callback, void *callback_arg,
int flags)
{
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
int nsegs, error;
/*
flags &= ~BUS_DMA_WAITOK;
flags |= BUS_DMA_NOWAIT;
+ segments = bus_dma_tag_lock(dmat, cache_segments);
error = bus_dmamap_load_mbuf_segment(dmat, map, m0,
- dmat->segments, dmat->nsegments, &nsegs, flags);
+ segments, dmat->nsegments, &nsegs, flags);
if (error) {
/* force "no valid mappings" in callback */
- callback(callback_arg, dmat->segments, 0, 0, error);
+ callback(callback_arg, segments, 0,
+ 0, error);
} else {
- callback(callback_arg, dmat->segments, nsegs,
+ callback(callback_arg, segments, nsegs,
m0->m_pkthdr.len, error);
}
+ bus_dma_tag_unlock(dmat);
return error;
}
bus_size_t resid;
struct iovec *iov;
pmap_t pmap;
+ bus_dma_segment_t cache_segments[BUS_DMA_CACHE_SEGMENTS];
+ bus_dma_segment_t *segments;
+ bus_dma_segment_t *segs;
+ int nsegs_left;
+
+ if (dmat->nsegments <= BUS_DMA_CACHE_SEGMENTS)
+ segments = cache_segments;
+ else
+ segments = kmalloc(sizeof(bus_dma_segment_t) * dmat->nsegments,
+ M_DEVBUF, M_WAITOK | M_ZERO);
/*
* XXX
resid = uio->uio_resid;
iov = uio->uio_iov;
+ segs = segments;
+ nsegs_left = dmat->nsegments;
+
if (uio->uio_segflg == UIO_USERSPACE) {
struct thread *td;
caddr_t addr = (caddr_t) iov[i].iov_base;
error = _bus_dmamap_load_buffer(dmat, map, addr, minlen,
- dmat->segments, dmat->nsegments,
+ segs, nsegs_left,
pmap, flags, &lastaddr, &nsegs, first);
first = 0;
resid -= minlen;
+ if (error == 0) {
+ nsegs_left -= nsegs;
+ segs += nsegs;
+ }
}
+ /*
+ * Minimum one DMA segment, even if 0-length buffer.
+ */
+ if (nsegs_left == dmat->nsegments)
+ --nsegs_left;
+
if (error) {
/* force "no valid mappings" in callback */
- callback(callback_arg, dmat->segments, 0, 0, error);
+ callback(callback_arg, segments, 0,
+ 0, error);
} else {
- callback(callback_arg, dmat->segments, nsegs,
+ callback(callback_arg, segments, dmat->nsegments - nsegs_left,
uio->uio_resid, error);
}
+ if (dmat->nsegments > BUS_DMA_CACHE_SEGMENTS)
+ kfree(segments, M_DEVBUF);
return error;
}