summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2001-05-08 18:19:45 +0000
committerJason Wright <jason@cvs.openbsd.org>2001-05-08 18:19:45 +0000
commita3e0598e6d2ed14810f2d1fc8b9ed360ee7be8ec (patch)
treee41152c3afd0856fbb13a157ec858c787b225e0d /sys/arch/i386
parent862af5aef1600fc408b2a00a4c77587d2c918827 (diff)
From netbsd: implementations of _bus_dmamap_load_mbuf() and
_bus_dmamap_load_uio().
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/i386/machdep.c259
-rw-r--r--sys/arch/i386/include/bus.h3
2 files changed, 185 insertions, 77 deletions
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 2d06dc4c7d3..08bebc6137a 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.159 2001/05/05 23:25:37 art Exp $ */
+/* $OpenBSD: machdep.c,v 1.160 2001/05/08 18:19:43 jason Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -281,6 +281,8 @@ void consinit __P((void));
int bus_mem_add_mapping __P((bus_addr_t, bus_size_t,
int, bus_space_handle_t *));
+int _bus_dmamap_load_buffer __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int, paddr_t *, int *, int));
#ifdef KGDB
#ifndef KGDB_DEVNAME
@@ -2850,101 +2852,69 @@ _bus_dmamap_load(t, map, buf, buflen, p, flags)
struct proc *p;
int flags;
{
- bus_size_t sgsize;
- bus_addr_t curaddr, lastaddr, baddr, bmask;
- vaddr_t vaddr = (vaddr_t)buf;
- int first, seg;
- pmap_t pmap;
+ bus_addr_t lastaddr;
+ int seg, error;
/*
* Make sure that on error condition we return "no valid mappings".
*/
+ map->dm_mapsize = 0;
map->dm_nsegs = 0;
if (buflen > map->_dm_size)
return (EINVAL);
- if (p != NULL)
- pmap = p->p_vmspace->vm_map.pmap;
- else
- pmap = pmap_kernel();
-
- lastaddr = ~0; /* XXX gcc */
- bmask = ~(map->_dm_boundary - 1);
-
- for (first = 1, seg = 0; buflen > 0; ) {
- /*
- * Get the physical address for this segment.
- */
- curaddr = (bus_addr_t)pmap_extract(pmap, (vm_offset_t)vaddr);
-
- /*
- * Compute the segment size, and adjust counts.
- */
- sgsize = NBPG - ((u_long)vaddr & PGOFSET);
- if (buflen < sgsize)
- sgsize = buflen;
-
- /*
- * Make sure we don't cross any boundaries.
- */
- if (map->_dm_boundary > 0) {
- baddr = (curaddr + map->_dm_boundary) & bmask;
- if (sgsize > (baddr - curaddr))
- sgsize = (baddr - curaddr);
- }
-
- /*
- * Insert chunk into a segment, coalescing with
- * previous segment if possible.
- */
- if (first) {
- map->dm_segs[seg].ds_addr = curaddr;
- map->dm_segs[seg].ds_len = sgsize;
- first = 0;
- } else {
- if (curaddr == lastaddr &&
- (map->dm_segs[seg].ds_len + sgsize) <=
- map->_dm_maxsegsz &&
- (map->_dm_boundary == 0 ||
- (map->dm_segs[seg].ds_addr & bmask) ==
- (curaddr & bmask)))
- map->dm_segs[seg].ds_len += sgsize;
- else {
- if (++seg >= map->_dm_segcnt)
- break;
- map->dm_segs[seg].ds_addr = curaddr;
- map->dm_segs[seg].ds_len = sgsize;
- }
- }
-
- lastaddr = curaddr + sgsize;
- vaddr += sgsize;
- buflen -= sgsize;
+ seg = 0;
+ error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
+ &lastaddr, &seg, 1);
+ if (error == 0) {
+ map->dm_mapsize = buflen;
+ map->dm_nsegs = seg + 1;
}
-
- /*
- * Did we fit?
- */
- if (buflen != 0)
- return (EFBIG); /* XXX better return value here? */
-
- map->dm_nsegs = seg + 1;
- return (0);
+ return (error);
}
/*
* Like _bus_dmamap_load(), but for mbufs.
*/
int
-_bus_dmamap_load_mbuf(t, map, m, flags)
+_bus_dmamap_load_mbuf(t, map, m0, flags)
bus_dma_tag_t t;
bus_dmamap_t map;
- struct mbuf *m;
+ struct mbuf *m0;
int flags;
{
+ paddr_t lastaddr;
+ int seg, error, first;
+ struct mbuf *m;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+#ifdef DIAGNOSTIC
+ if ((m0->m_flags & M_PKTHDR) == 0)
+ panic("_bus_dmamap_load_mbuf: no packet header");
+#endif
+
+ if (m0->m_pkthdr.len > map->_dm_size)
+ return (EINVAL);
- panic("_bus_dmamap_load: not implemented");
+ first = 1;
+ seg = 1;
+ error = 0;
+ for (m = m0; m != NULL && error == 0; m = m->m_next) {
+ error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
+ NULL, flags, &lastaddr, &seg, first);
+ first = 0;
+ }
+ if (error == 0) {
+ map->dm_mapsize = m0->m_pkthdr.len;
+ map->dm_nsegs = seg + 1;
+ }
+ return (error);
}
/*
@@ -2957,8 +2927,52 @@ _bus_dmamap_load_uio(t, map, uio, flags)
struct uio *uio;
int flags;
{
+ paddr_t lastaddr;
+ int seg, i, error, first;
+ bus_size_t minlen, resid;
+ struct proc *p = NULL;
+ struct iovec *iov;
+ caddr_t addr;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+ resid = uio->uio_resid;
+ iov = uio->uio_iov;
+
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ p = uio->uio_procp;
+#ifdef DIAGNOSTIC
+ if (p == NULL)
+ panic("_bus_dmamap_load_uio: USERSPACE but no proc");
+#endif
+ }
+
+ first = 1;
+ seg = 0;
+ error = 0;
+ for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
+ /*
+ * Now at the first iovec to load. Load each iovec
+ * until we have exhausted the residual count.
+ */
+ minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
+ addr = (caddr_t)iov[i].iov_base;
- panic("_bus_dmamap_load_uio: not implemented");
+ error = _bus_dmamap_load_buffer(t, map, addr, minlen,
+ p, flags, &lastaddr, &seg, first);
+ first = 0;
+
+ resid -= minlen;
+ }
+ if (error == 0) {
+ map->dm_mapsize = uio->uio_resid;
+ map->dm_nsegs = seg + 1;
+ }
+ return (error);
}
/*
@@ -3154,6 +3168,99 @@ _bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
/**********************************************************************
* DMA utility functions
**********************************************************************/
+/*
+ * Utility function to load a linear buffer. lastaddrp holds state
+ * between invocations (for multiple-buffer loads). segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ * first indicates if this is the first invocation of this function.
+ */
+int
+_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ void *buf;
+ bus_size_t buflen;
+ struct proc *p;
+ int flags;
+ paddr_t *lastaddrp;
+ int *segp;
+ int first;
+{
+ bus_size_t sgsize;
+ bus_addr_t curaddr, lastaddr, baddr, bmask;
+ vaddr_t vaddr = (vaddr_t)buf;
+ int seg;
+ pmap_t pmap;
+
+ if (p != NULL)
+ pmap = p->p_vmspace->vm_map.pmap;
+ else
+ pmap = pmap_kernel();
+
+ lastaddr = *lastaddrp;
+ bmask = ~(map->_dm_boundary - 1);
+
+ for (seg = *segp; buflen > 0 ; ) {
+ /*
+ * Get the physical address for this segment.
+ */
+ curaddr = (bus_addr_t)pmap_extract(pmap, (vm_offset_t)vaddr);
+
+ /*
+ * Compute the segment size, and adjust counts.
+ */
+ sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
+ if (buflen < sgsize)
+ sgsize = buflen;
+
+ /*
+ * Make sure we don't cross any boundaries.
+ */
+ if (map->_dm_boundary > 0) {
+ baddr = (curaddr + map->_dm_boundary) & bmask;
+ if (sgsize > (baddr - curaddr))
+ sgsize = (baddr - curaddr);
+ }
+
+ /*
+ * Insert chunk into a segment, coalescing with
+ * previous segment if possible.
+ */
+ if (first) {
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ first = 0;
+ } else {
+ if (curaddr == lastaddr &&
+ (map->dm_segs[seg].ds_len + sgsize) <=
+ map->_dm_maxsegsz &&
+ (map->_dm_boundary == 0 ||
+ (map->dm_segs[seg].ds_addr & bmask) ==
+ (curaddr & bmask)))
+ map->dm_segs[seg].ds_len += sgsize;
+ else {
+ if (++seg >= map->_dm_segcnt)
+ break;
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ }
+ }
+
+ lastaddr = curaddr + sgsize;
+ vaddr += sgsize;
+ buflen -= sgsize;
+ }
+
+ *segp = seg;
+ *lastaddrp = lastaddr;
+
+ /*
+ * Did we fit?
+ */
+ if (buflen != 0)
+ return (EFBIG); /* XXX better return value here? */
+ return (0);
+}
/*
* Allocate physical memory from the given physical address range.
diff --git a/sys/arch/i386/include/bus.h b/sys/arch/i386/include/bus.h
index 50aa7cd6452..d6a73c8b9bb 100644
--- a/sys/arch/i386/include/bus.h
+++ b/sys/arch/i386/include/bus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus.h,v 1.27 2001/02/06 23:13:31 mickey Exp $ */
+/* $OpenBSD: bus.h,v 1.28 2001/05/08 18:19:44 jason Exp $ */
/* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */
/*-
@@ -891,6 +891,7 @@ struct i386_bus_dmamap {
/*
* PUBLIC MEMBERS: these are used by machine-independent code.
*/
+ bus_size_t dm_mapsize; /* size of the mapping */
int dm_nsegs; /* # valid segments in mapping */
bus_dma_segment_t dm_segs[1]; /* segments; variable length */
};