summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorkmacy <kmacy@FreeBSD.org>2007-04-08 15:59:07 +0000
committerkmacy <kmacy@FreeBSD.org>2007-04-08 15:59:07 +0000
commit9d80aa52927544096d911e2d1a63845dbfab69d9 (patch)
treea399681be00a5b214a8cd78ef588d53443bbcb6e /sys/dev
parentd5cb13779a69d4d5c087805b81b4a26dc8640657 (diff)
downloadFreeBSD-src-9d80aa52927544096d911e2d1a63845dbfab69d9.zip
FreeBSD-src-9d80aa52927544096d911e2d1a63845dbfab69d9.tar.gz
add busdma function for mapping mbuf iovecs
change m_collapse to return an error code
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/cxgb/sys/mvec.h27
-rw-r--r--sys/dev/cxgb/sys/uipc_mvec.c108
2 files changed, 121 insertions, 14 deletions
diff --git a/sys/dev/cxgb/sys/mvec.h b/sys/dev/cxgb/sys/mvec.h
index d05c380..31febe5 100644
--- a/sys/dev/cxgb/sys/mvec.h
+++ b/sys/dev/cxgb/sys/mvec.h
@@ -29,6 +29,9 @@
*
***************************************************************************/
+#ifndef _MVEC_H_
+#define _MVEC_H_
+
#define mtomv(m) ((struct mbuf_vec *)((m)->m_pktdat))
#define M_IOVEC 0x40000 /* mbuf immediate data area is used for cluster ptrs */
@@ -62,7 +65,7 @@ struct mbuf_vec {
};
int _m_explode(struct mbuf *);
-struct mbuf *_m_collapse(struct mbuf *, int maxbufs);
+int _m_collapse(struct mbuf *, int maxbufs, struct mbuf **);
void mb_free_vec(struct mbuf *m);
@@ -108,13 +111,14 @@ m_explode(struct mbuf *m)
return _m_explode(m);
}
-static __inline struct mbuf *
-m_collapse(struct mbuf *m, int maxbufs)
-{
- if (m->m_next == NULL)
- return (m);
-
- return _m_collapse(m, maxbufs);
+static __inline int
+m_collapse(struct mbuf *m, int maxbufs, struct mbuf **mnew)
+{
+ /*
+ * Add checks here
+ */
+
+ return _m_collapse(m, maxbufs, mnew);
}
static __inline void
@@ -133,3 +137,10 @@ m_freem_vec(struct mbuf *m)
uma_zfree(zone_mbuf, m);
}
}
+
+
+int
+bus_dmamap_load_mvec_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
+ bus_dma_segment_t *segs, int *nsegs, int flags);
+
+#endif
diff --git a/sys/dev/cxgb/sys/uipc_mvec.c b/sys/dev/cxgb/sys/uipc_mvec.c
index 42914d2..6347dda 100644
--- a/sys/dev/cxgb/sys/uipc_mvec.c
+++ b/sys/dev/cxgb/sys/uipc_mvec.c
@@ -37,6 +37,9 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+#include <sys/ktr.h>
+
+#include <machine/bus.h>
#include <dev/cxgb/sys/mvec.h>
@@ -84,8 +87,8 @@ _m_explode(struct mbuf *m)
#define MAX_BUFS 36
-struct mbuf *
-_m_collapse(struct mbuf *m, int maxbufs)
+int
+_m_collapse(struct mbuf *m, int maxbufs, struct mbuf **mnew)
{
struct mbuf *m0, *lvec[MAX_BUFS];
struct mbuf **mnext, **vec = &lvec[0];
@@ -96,7 +99,7 @@ _m_collapse(struct mbuf *m, int maxbufs)
if (maxbufs > MAX_BUFS)
if ((vec = malloc(maxbufs * sizeof(struct mbuf *),
M_DEVBUF, M_NOWAIT)) == NULL)
- return (NULL);
+ return (ENOMEM);
m0 = m;
for (i = 0; i < maxbufs; i++) {
@@ -107,7 +110,7 @@ _m_collapse(struct mbuf *m, int maxbufs)
}
if (i == maxbufs)
- return (NULL);
+ return (EFBIG);
batch:
max = i;
i = 0;
@@ -148,7 +151,8 @@ batch:
}
mhead->m_flags |= (m0->m_flags & M_PKTHDR);
- return (mhead);
+ *mnew = mhead;
+ return (0);
m_getfail:
m0 = mhead;
@@ -156,7 +160,7 @@ m_getfail:
mhead = m0->m_next;
uma_zfree(zone_mbuf, m0);
}
- return (NULL);
+ return (ENOMEM);
}
void
@@ -226,3 +230,95 @@ mb_free_vec(struct mbuf *m)
m->m_flags &= ~M_IOVEC;
uma_zfree(zone_mbuf, m);
}
+
+struct mvec_sg_cb_arg {
+ int error;
+ bus_dma_segment_t seg;
+ int nseg;
+};
+
+struct bus_dma_tag {
+ bus_dma_tag_t parent;
+ bus_size_t alignment;
+ bus_size_t boundary;
+ bus_addr_t lowaddr;
+ bus_addr_t highaddr;
+ bus_dma_filter_t *filter;
+ void *filterarg;
+ bus_size_t maxsize;
+ u_int nsegments;
+ bus_size_t maxsegsz;
+ int flags;
+ int ref_count;
+ int map_count;
+ bus_dma_lock_t *lockfunc;
+ void *lockfuncarg;
+ bus_dma_segment_t *segments;
+ struct bounce_zone *bounce_zone;
+};
+
+static void
+mvec_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct mvec_sg_cb_arg *cb_arg = arg;
+
+ cb_arg->error = error;
+ cb_arg->seg = segs[0];
+ cb_arg->nseg = nseg;
+
+}
+
+int
+bus_dmamap_load_mvec_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
+ bus_dma_segment_t *segs, int *nsegs, int flags)
+{
+ int error;
+ struct mbuf_vec *mv;
+ struct mvec_sg_cb_arg cb_arg;
+
+ M_ASSERTPKTHDR(m0);
+
+ flags |= BUS_DMA_NOWAIT;
+ *nsegs = 0;
+ error = 0;
+ if (m0->m_pkthdr.len <=
+ dmat->maxsize) {
+ struct mbuf *m;
+
+ for (m = m0; m != NULL && error == 0; m = m->m_next) {
+ int count, first, i;
+ if (!(m->m_len > 0))
+ continue;
+
+ mv = mtomv(m);
+ count = mv->mv_count;
+ first = mv->mv_first;
+ for (i = first; i < count; i++) {
+ void *data = mv->mv_vec[i].mi_base;
+ int size = mv->mv_vec[i].mi_size;
+
+ cb_arg.seg = *segs;
+ error = bus_dmamap_load(dmat, map,
+ data, size, mvec_cb, &cb_arg, flags);
+ segs++;
+ *nsegs++;
+ if (error || cb_arg.error)
+ goto err_out;
+ }
+ }
+ } else {
+ error = EINVAL;
+ }
+
+ /* XXX FIXME: Having to increment nsegs is really annoying */
+ ++*nsegs;
+ CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
+ __func__, dmat, dmat->flags, error, *nsegs);
+ return (error);
+
+err_out:
+ if (cb_arg.error)
+ return (cb_arg.error);
+
+ return (error);
+}
OpenPOWER on IntegriCloud