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