summaryrefslogtreecommitdiff
path: root/sys/arch/alpha
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2001-11-05 02:39:58 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2001-11-05 02:39:58 +0000
commit66b6f056afa073b7f8c10d4803073cb4588a1931 (patch)
treeb02d3e0db6cad7425c7a361537eba0cc066e8d6e /sys/arch/alpha
parentfb23a89e7b35b7d7276f349dbbf4833733501e09 (diff)
Code for isadma bouncing.
From NetBSD.
Diffstat (limited to 'sys/arch/alpha')
-rw-r--r--sys/arch/alpha/conf/files.alpha5
-rw-r--r--sys/arch/alpha/isa/isa_machdep.h21
-rw-r--r--sys/arch/alpha/isa/isadma_bounce.c586
3 files changed, 609 insertions, 3 deletions
diff --git a/sys/arch/alpha/conf/files.alpha b/sys/arch/alpha/conf/files.alpha
index ccb6c16595d..dd22a788971 100644
--- a/sys/arch/alpha/conf/files.alpha
+++ b/sys/arch/alpha/conf/files.alpha
@@ -1,4 +1,4 @@
-# $OpenBSD: files.alpha,v 1.51 2001/10/26 01:28:06 nate Exp $
+# $OpenBSD: files.alpha,v 1.52 2001/11/05 02:39:56 art Exp $
# $NetBSD: files.alpha,v 1.32 1996/11/25 04:03:21 cgd Exp $
#
# alpha-specific configuration info
@@ -132,8 +132,9 @@ major { wd = 0 }
#
file arch/alpha/isa/isa_machdep.c isa
+
define isadma_bounce
-file arch/alpha/isa/isadmabounce.c isadma_bounce
+file arch/alpha/isa/isadma_bounce.c isadma_bounce
device isabeep
attach isabeep at pcppi
diff --git a/sys/arch/alpha/isa/isa_machdep.h b/sys/arch/alpha/isa/isa_machdep.h
index cba9d560f33..0fdf551a634 100644
--- a/sys/arch/alpha/isa/isa_machdep.h
+++ b/sys/arch/alpha/isa/isa_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: isa_machdep.h,v 1.8 2001/10/26 01:28:06 nate Exp $ */
+/* $OpenBSD: isa_machdep.h,v 1.9 2001/11/05 02:39:57 art Exp $ */
/* $NetBSD: isa_machdep.h,v 1.3 1996/11/19 04:53:07 cgd Exp $ */
/*
@@ -63,3 +63,22 @@ struct alpha_isa_chipset {
* NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
*/
int isa_display_console __P((bus_space_tag_t, bus_space_tag_t));
+
+#ifdef _ALPHA_BUS_DMA_PRIVATE
+int isadma_bounce_dmamap_create(bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *);
+void isadma_bounce_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
+int isadma_bounce_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int);
+int isadma_bounce_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int);
+int isadma_bounce_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int);
+int isadma_bounce_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int);
+void isadma_bounce_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
+void isadma_bounce_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
+ bus_dmasync_op_t);
+int isadma_bounce_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int);
+#endif /* _ALPHA_BUS_DMA_PRIVATE */
diff --git a/sys/arch/alpha/isa/isadma_bounce.c b/sys/arch/alpha/isa/isadma_bounce.c
new file mode 100644
index 00000000000..7dc9014957d
--- /dev/null
+++ b/sys/arch/alpha/isa/isadma_bounce.c
@@ -0,0 +1,586 @@
+/* $OpenBSD: isadma_bounce.c,v 1.1 2001/11/05 02:39:56 art Exp $ */
+/* $NetBSD: isadma_bounce.c,v 1.3 2000/06/29 09:02:57 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _ALPHA_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+
+#include <machine/bus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <vm/vm.h>
+#include <uvm/uvm_extern.h>
+
+extern paddr_t avail_end;
+
+/*
+ * ISA can only DMA to 0-16M.
+ */
+#define ISA_DMA_BOUNCE_THRESHOLD (16 * 1024 * 1024)
+
+/*
+ * Cookie used by bouncing ISA DMA. A pointer to one of these is stashed
+ * in the DMA map.
+ */
+struct isadma_bounce_cookie {
+ int id_flags; /* flags; see below */
+
+ /*
+ * Information about the original buffer used during
+ * DMA map syncs. Note that origbuflen is only used
+ * for ID_BUFTYPE_LINEAR.
+ */
+ void *id_origbuf; /* pointer to orig buffer if
+ bouncing */
+ bus_size_t id_origbuflen; /* ...and size */
+ int id_buftype; /* type of buffer */
+
+ void *id_bouncebuf; /* pointer to the bounce buffer */
+ bus_size_t id_bouncebuflen; /* ...and size */
+ int id_nbouncesegs; /* number of valid bounce segs */
+ bus_dma_segment_t id_bouncesegs[1]; /* array of bounce buffer
+ physical memory segments */
+};
+
+/* id_flags */
+#define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */
+#define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */
+#define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */
+
+/* id_buftype */
+#define ID_BUFTYPE_INVALID 0
+#define ID_BUFTYPE_LINEAR 1
+#define ID_BUFTYPE_MBUF 2
+#define ID_BUFTYPE_UIO 3
+#define ID_BUFTYPE_RAW 4
+
+int isadma_bounce_alloc_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_size_t, int));
+void isadma_bounce_free_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t));
+
+/*
+ * Create an ISA DMA map.
+ */
+int
+isadma_bounce_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
+ bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
+{
+ struct isadma_bounce_cookie *cookie;
+ bus_dmamap_t map;
+ int error, cookieflags;
+ void *cookiestore;
+ size_t cookiesize;
+
+ /* Call common function to create the basic map. */
+ error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
+ flags, dmamp);
+ if (error)
+ return (error);
+
+ map = *dmamp;
+ map->_dm_cookie = NULL;
+
+ cookiesize = sizeof(*cookie);
+
+ /*
+ * ISA only has 24-bits of address space. This means
+ * we can't DMA to pages over 16M. In order to DMA to
+ * arbitrary buffers, we use "bounce buffers" - pages
+ * in memory below the 16M boundary. On DMA reads,
+ * DMA happens to the bounce buffers, and is copied into
+ * the caller's buffer. On writes, data is copied into
+ * but bounce buffer, and the DMA happens from those
+ * pages. To software using the DMA mapping interface,
+ * this looks simply like a data cache.
+ *
+ * If we have more than 16M of RAM in the system, we may
+ * need bounce buffers. We check and remember that here.
+ *
+ * ...or, there is an opposite case. The most segments
+ * a transfer will require is (maxxfer / PAGE_SIZE) + 1. If
+ * the caller can't handle that many segments (e.g. the
+ * ISA DMA controller), we may have to bounce it as well.
+ */
+ cookieflags = 0;
+ if (avail_end > (t->_wbase + t->_wsize) ||
+ ((map->_dm_size / PAGE_SIZE) + 1) > map->_dm_segcnt) {
+ cookieflags |= ID_MIGHT_NEED_BOUNCE;
+ cookiesize += (sizeof(bus_dma_segment_t) *
+ (map->_dm_segcnt - 1));
+ }
+
+ /*
+ * Allocate our cookie.
+ */
+ if ((cookiestore = malloc(cookiesize, M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ memset(cookiestore, 0, cookiesize);
+ cookie = (struct isadma_bounce_cookie *)cookiestore;
+ cookie->id_flags = cookieflags;
+ map->_dm_cookie = cookie;
+
+ if (cookieflags & ID_MIGHT_NEED_BOUNCE) {
+ /*
+ * Allocate the bounce pages now if the caller
+ * wishes us to do so.
+ */
+ if ((flags & BUS_DMA_ALLOCNOW) == 0)
+ goto out;
+
+ error = isadma_bounce_alloc_bouncebuf(t, map, size, flags);
+ }
+
+ out:
+ if (error) {
+ if (map->_dm_cookie != NULL)
+ free(map->_dm_cookie, M_DEVBUF);
+ _bus_dmamap_destroy(t, map);
+ }
+ return (error);
+}
+
+/*
+ * Destroy an ISA DMA map.
+ */
+void
+isadma_bounce_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+
+ /*
+ * Free any bounce pages this map might hold.
+ */
+ if (cookie->id_flags & ID_HAS_BOUNCE)
+ isadma_bounce_free_bouncebuf(t, map);
+
+ free(cookie, M_DEVBUF);
+ _bus_dmamap_destroy(t, map);
+}
+
+/*
+ * Load an ISA DMA map with a linear buffer.
+ */
+int
+isadma_bounce_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ size_t buflen, struct proc *p, int flags)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+ int error;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings."
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+ /*
+ * Try to load the map the normal way. If this errors out,
+ * and we can bounce, we will.
+ */
+ error = _bus_dmamap_load_direct(t, map, buf, buflen, p, flags);
+ if (error == 0 ||
+ (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0))
+ return (error);
+
+ /*
+ * First attempt failed; bounce it.
+ */
+
+ /*
+ * Allocate bounce pages, if necessary.
+ */
+ if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
+ error = isadma_bounce_alloc_bouncebuf(t, map, buflen, flags);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Cache a pointer to the caller's buffer and load the DMA map
+ * with the bounce buffer.
+ */
+ cookie->id_origbuf = buf;
+ cookie->id_origbuflen = buflen;
+ cookie->id_buftype = ID_BUFTYPE_LINEAR;
+ error = _bus_dmamap_load_direct(t, map, cookie->id_bouncebuf, buflen,
+ p, flags);
+ if (error) {
+ /*
+ * Free the bounce pages, unless our resources
+ * are reserved for our exclusive use.
+ */
+ if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
+ isadma_bounce_free_bouncebuf(t, map);
+ return (error);
+ }
+
+ /* ...so isadma_bounce_dmamap_sync() knows we're bouncing */
+ cookie->id_flags |= ID_IS_BOUNCING;
+ return (0);
+}
+
+/*
+ * Like isadma_bounce_dmamap_load(), but for mbufs.
+ */
+int
+isadma_bounce_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
+ struct mbuf *m0, int flags)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+ int error;
+
+ /*
+ * Make sure 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("isadma_bounce_dmamap_load_mbuf: no packet header");
+#endif
+
+ if (m0->m_pkthdr.len > map->_dm_size)
+ return (EINVAL);
+
+ /*
+ * Try to load the map the normal way. If this errors out,
+ * and we can bounce, we will.
+ */
+ error = _bus_dmamap_load_mbuf_direct(t, map, m0, flags);
+ if (error == 0 ||
+ (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0))
+ return (error);
+
+ /*
+ * First attempt failed; bounce it.
+ */
+
+ /*
+ * Allocate bounce pages, if necessary.
+ */
+ if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
+ error = isadma_bounce_alloc_bouncebuf(t, map, m0->m_pkthdr.len,
+ flags);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Cache a pointer to the caller's buffer and load the DMA map
+ * with the bounce buffer.
+ */
+ cookie->id_origbuf = m0;
+ cookie->id_origbuflen = m0->m_pkthdr.len; /* not really used */
+ cookie->id_buftype = ID_BUFTYPE_MBUF;
+ error = _bus_dmamap_load_direct(t, map, cookie->id_bouncebuf,
+ m0->m_pkthdr.len, NULL, flags);
+ if (error) {
+ /*
+ * Free the bounce pages, unless our resources
+ * are reserved for our exclusive use.
+ */
+ if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
+ isadma_bounce_free_bouncebuf(t, map);
+ return (error);
+ }
+
+ /* ...so isadma_bounce_dmamap_sync() knows we're bouncing */
+ cookie->id_flags |= ID_IS_BOUNCING;
+ return (0);
+}
+
+/*
+ * Like isadma_bounce_dmamap_load(), but for uios.
+ */
+int
+isadma_bounce_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
+ struct uio *uio, int flags)
+{
+
+ panic("isadma_bounce_dmamap_load_uio: not implemented");
+}
+
+/*
+ * Like isadma_bounce_dmamap_load(), but for raw memory allocated with
+ * bus_dmamem_alloc().
+ */
+int
+isadma_bounce_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
+ bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
+{
+
+ panic("isadma_bounce_dmamap_load_raw: not implemented");
+}
+
+/*
+ * Unload an ISA DMA map.
+ */
+void
+isadma_bounce_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+
+ /*
+ * If we have bounce pages, free them, unless they're
+ * reserved for our exclusive use.
+ */
+ if ((cookie->id_flags & ID_HAS_BOUNCE) &&
+ (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
+ isadma_bounce_free_bouncebuf(t, map);
+
+ cookie->id_flags &= ~ID_IS_BOUNCING;
+ cookie->id_buftype = ID_BUFTYPE_INVALID;
+
+ /*
+ * Do the generic bits of the unload.
+ */
+ _bus_dmamap_unload(t, map);
+}
+
+void
+isadma_bounce_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map,
+ bus_dmasync_op_t ops)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+ bus_addr_t offset = 0;
+ bus_size_t len = map->dm_mapsize;
+
+ /*
+ * Mixing PRE and POST operations is not allowed.
+ */
+ if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
+ (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
+ panic("isadma_bounce_dmamap_sync: mix PRE and POST");
+
+#ifdef DIAGNOSTIC
+ if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
+ if (offset >= map->dm_mapsize)
+ panic("isadma_bounce_dmamap_sync: bad offset");
+ if (len == 0 || (offset + len) > map->dm_mapsize)
+ panic("isadma_bounce_dmamap_sync: bad length");
+ }
+#endif
+
+ /*
+ * If we're not bouncing, just drain the write buffer
+ * and return.
+ */
+ if ((cookie->id_flags & ID_IS_BOUNCING) == 0) {
+ alpha_mb();
+ return;
+ }
+
+ switch (cookie->id_buftype) {
+ case ID_BUFTYPE_LINEAR:
+ /*
+ * Nothing to do for pre-read.
+ */
+
+ if (ops & BUS_DMASYNC_PREWRITE) {
+ /*
+ * Copy the caller's buffer to the bounce buffer.
+ */
+ memcpy((char *)cookie->id_bouncebuf + offset,
+ (char *)cookie->id_origbuf + offset, len);
+ }
+
+ if (ops & BUS_DMASYNC_POSTREAD) {
+ /*
+ * Copy the bounce buffer to the caller's buffer.
+ */
+ memcpy((char *)cookie->id_origbuf + offset,
+ (char *)cookie->id_bouncebuf + offset, len);
+ }
+
+ /*
+ * Nothing to do for post-write.
+ */
+ break;
+
+ case ID_BUFTYPE_MBUF:
+ {
+ struct mbuf *m, *m0 = cookie->id_origbuf;
+ bus_size_t minlen, moff;
+
+ /*
+ * Nothing to do for pre-read.
+ */
+
+ if (ops & BUS_DMASYNC_PREWRITE) {
+ /*
+ * Copy the caller's buffer to the bounce buffer.
+ */
+ m_copydata(m0, offset, len,
+ (char *)cookie->id_bouncebuf + offset);
+ }
+
+ if (ops & BUS_DMASYNC_POSTREAD) {
+ /*
+ * Copy the bounce buffer to the caller's buffer.
+ */
+ for (moff = offset, m = m0; m != NULL && len != 0;
+ m = m->m_next) {
+ /* Find the beginning mbuf. */
+ if (moff >= m->m_len) {
+ moff -= m->m_len;
+ continue;
+ }
+
+ /*
+ * Now at the first mbuf to sync; nail
+ * each one until we have exhausted the
+ * length.
+ */
+ minlen = len < m->m_len - moff ?
+ len : m->m_len - moff;
+
+ memcpy(mtod(m, caddr_t) + moff,
+ (char *)cookie->id_bouncebuf + offset,
+ minlen);
+
+ moff = 0;
+ len -= minlen;
+ offset += minlen;
+ }
+ }
+
+ /*
+ * Nothing to do for post-write.
+ */
+ break;
+ }
+
+ case ID_BUFTYPE_UIO:
+ panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_UIO");
+ break;
+
+ case ID_BUFTYPE_RAW:
+ panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_RAW");
+ break;
+
+ case ID_BUFTYPE_INVALID:
+ panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_INVALID");
+ break;
+
+ default:
+ printf("unknown buffer type %d\n", cookie->id_buftype);
+ panic("isadma_bounce_dmamap_sync");
+ }
+
+ /* Drain the write buffer. */
+ alpha_mb();
+}
+
+/*
+ * Allocate memory safe for ISA DMA.
+ */
+int
+isadma_bounce_dmamem_alloc(bus_dma_tag_t t, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
+ int nsegs, int *rsegs, int flags)
+{
+ paddr_t high;
+
+ if (avail_end > ISA_DMA_BOUNCE_THRESHOLD)
+ high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD);
+ else
+ high = trunc_page(avail_end);
+
+ return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
+ segs, nsegs, rsegs, flags, 0, high));
+}
+
+/**********************************************************************
+ * ISA DMA utility functions
+ **********************************************************************/
+
+int
+isadma_bounce_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map,
+ bus_size_t size, int flags)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+ int error = 0;
+
+ cookie->id_bouncebuflen = round_page(size);
+ error = isadma_bounce_dmamem_alloc(t, cookie->id_bouncebuflen,
+ PAGE_SIZE, map->_dm_boundary, cookie->id_bouncesegs,
+ map->_dm_segcnt, &cookie->id_nbouncesegs, flags);
+ if (error)
+ goto out;
+ error = _bus_dmamem_map(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs, cookie->id_bouncebuflen,
+ (caddr_t *)&cookie->id_bouncebuf, flags);
+
+ out:
+ if (error) {
+ _bus_dmamem_free(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs);
+ cookie->id_bouncebuflen = 0;
+ cookie->id_nbouncesegs = 0;
+ } else
+ cookie->id_flags |= ID_HAS_BOUNCE;
+
+ return (error);
+}
+
+void
+isadma_bounce_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ struct isadma_bounce_cookie *cookie = map->_dm_cookie;
+
+ _bus_dmamem_unmap(t, cookie->id_bouncebuf,
+ cookie->id_bouncebuflen);
+ _bus_dmamem_free(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs);
+ cookie->id_bouncebuflen = 0;
+ cookie->id_nbouncesegs = 0;
+ cookie->id_flags &= ~ID_HAS_BOUNCE;
+}