Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/evbarm/integrator Add bouncing support
details: https://anonhg.NetBSD.org/src/rev/49b5e45d2445
branches: trunk
changeset: 551391:49b5e45d2445
user: rearnsha <rearnsha%NetBSD.org@localhost>
date: Sat Sep 06 11:12:53 2003 +0000
description:
Add bouncing support
diffstat:
sys/arch/evbarm/integrator/int_bus_dma.c | 618 ++++++++++++++++++++++++++++++-
1 files changed, 599 insertions(+), 19 deletions(-)
diffs (truncated from 652 to 300 lines):
diff -r 858df224b2f9 -r 49b5e45d2445 sys/arch/evbarm/integrator/int_bus_dma.c
--- a/sys/arch/evbarm/integrator/int_bus_dma.c Sat Sep 06 10:57:12 2003 +0000
+++ b/sys/arch/evbarm/integrator/int_bus_dma.c Sat Sep 06 11:12:53 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: int_bus_dma.c,v 1.12 2003/07/15 00:25:00 lukem Exp $ */
+/* $NetBSD: int_bus_dma.c,v 1.13 2003/09/06 11:12:53 rearnsha Exp $ */
/*
* Copyright (c) 2002 Wasabi Systems, Inc.
@@ -39,8 +39,10 @@
* PCI DMA support for the ARM Integrator.
*/
+#define _ARM32_BUS_DMA_PRIVATE
+
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: int_bus_dma.c,v 1.12 2003/07/15 00:25:00 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: int_bus_dma.c,v 1.13 2003/09/06 11:12:53 rearnsha Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -50,35 +52,613 @@
#include <uvm/uvm_extern.h>
-#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bootconfig.h>
+
#include <evbarm/integrator/int_bus_dma.h>
-static struct arm32_dma_range integrator_dma_ranges[1];
+struct integrator_dma_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[0]; /* 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
+
+#define DEBUG(x)
+
+static struct arm32_dma_range integrator_dma_ranges[DRAM_BLOCKS];
+
+extern BootConfig bootconfig;
+
+static int integrator_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *);
+static void integrator_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
+static int integrator_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int);
+static int integrator_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int);
+static int integrator_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int);
+static int integrator_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int);
+static void integrator_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
+static void integrator_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
+ bus_addr_t, bus_size_t, int);
+static int integrator_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t,
+ bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int);
+static int integrator_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t,
+ bus_size_t, int);
+static void integrator_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t);
+
+
+/*
+ * Create an Integrator DMA map.
+ */
+static int
+integrator_bus_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 integrator_dma_cookie *cookie;
+ bus_dmamap_t map;
+ int error, cookieflags;
+ void *cookiestore;
+ size_t cookiesize;
+
+ DEBUG(printf("I_bus_dmamap_create(tag %x, size %x, nseg %d, max %x,"
+ " boundary %x, flags %x, dmamap %p)\n", (unsigned) t,
+ (unsigned) size, nsegments, (unsigned) maxsegsz,
+ (unsigned)boundary, flags, dmamp));
+
+ /* 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(struct integrator_dma_cookie);
+
+ /*
+ * Some CM boards have private memory which is significantly
+ * faster than the normal memory stick. To support this
+ * memory we have to bounce any DMA transfers.
+ *
+ * In order to DMA to arbitrary buffers, we use "bounce
+ * buffers" - pages in in the main PCI visible memory. 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 private RAM in the system, we may need bounce
+ * buffers. We check and remember that here.
+ */
+#if 0
+ cookieflags = ID_MIGHT_NEED_BOUNCE;
+#else
+ cookieflags = 0;
+#endif
+ cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
+
+ /*
+ * Allocate our cookie.
+ */
+ if ((cookiestore = malloc(cookiesize, M_DMAMAP,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ memset(cookiestore, 0, cookiesize);
+ cookie = (struct integrator_dma_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;
+
+ DEBUG(printf("I_bus_dmamap_create bouncebuf alloc\n"));
+ error = integrator_dma_alloc_bouncebuf(t, map, size, flags);
+ }
+
+ out:
+ if (error) {
+ if (map->_dm_cookie != NULL)
+ free(map->_dm_cookie, M_DMAMAP);
+ _bus_dmamap_destroy(t, map);
+ printf("I_bus_dmamap_create failed (%d)\n", error);
+ }
+ return (error);
+}
+
+/*
+ * Destroy an ISA DMA map.
+ */
+static void
+integrator_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ struct integrator_dma_cookie *cookie = map->_dm_cookie;
+
+ DEBUG(printf("I_bus_dmamap_destroy (tag %x, map %x)\n", (unsigned) t,
+ (unsigned) map));
+ /*
+ * Free any bounce pages this map might hold.
+ */
+ if (cookie->id_flags & ID_HAS_BOUNCE) {
+ DEBUG(printf("I_bus_dmamap_destroy bouncebuf\n"));
+ integrator_dma_free_bouncebuf(t, map);
+ }
+
+ free(cookie, M_DMAMAP);
+ _bus_dmamap_destroy(t, map);
+}
+
+/*
+ * Load an Integrator DMA map with a linear buffer.
+ */
+static int
+integrator_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, struct proc *p, int flags)
+{
+ struct integrator_dma_cookie *cookie = map->_dm_cookie;
+ int error;
+
+ DEBUG(printf("I_bus_dmamap_load (tag %x, map %x, buf %p, len %u,"
+ " proc %p, flags %d)\n", (unsigned) t, (unsigned) map, buf,
+ (unsigned) buflen, p, flags));
+ /*
+ * 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(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) {
+ DEBUG(printf("I_bus_dmamap_load alloc bouncebuf\n"));
+ error = integrator_dma_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(t, map, cookie->id_bouncebuf, buflen,
+ 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)
+ integrator_dma_free_bouncebuf(t, map);
+ return (error);
+ }
+
+ /* ...so integrator_bus_dmamap_sync() knows we're bouncing */
+ cookie->id_flags |= ID_IS_BOUNCING;
+ return (0);
+}
+
+/*
+ * Like integrator_bus_dmamap_load(), but for mbufs.
+ */
+static int
+integrator_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
+ struct mbuf *m0, int flags)
+{
+ struct integrator_dma_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;
+
+#ifdef DIAGNOSTIC
+ if ((m0->m_flags & M_PKTHDR) == 0)
+ panic("integrator_bus_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(t, map, m0, flags);
+ if (error == 0 ||
+ (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0))
+ return (error);
+
+ /*
+ * First attempt failed; bounce it.
+ *
Home |
Main Index |
Thread Index |
Old Index