Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm Add bounce buffer support for ARM bus_dma(9). ...



details:   https://anonhg.NetBSD.org/src/rev/d8f0a63ccf71
branches:  trunk
changeset: 781612:d8f0a63ccf71
user:      matt <matt%NetBSD.org@localhost>
date:      Tue Sep 18 05:47:26 2012 +0000

description:
Add bounce buffer support for ARM bus_dma(9).  Add macros to help initialize
bus_dma_tag structures.

diffstat:

 sys/arch/arm/arm32/bus_dma.c             |  566 ++++++++++++++++++++++++++++--
 sys/arch/arm/at91/at91_bus_dma.c         |   27 +-
 sys/arch/arm/broadcom/bcm2835_dma.c      |   27 +-
 sys/arch/arm/broadcom/bcm53xx_board.c    |   21 +-
 sys/arch/arm/ep93xx/ep93xx_busdma.c      |   27 +-
 sys/arch/arm/footbridge/footbridge_pci.c |   26 +-
 sys/arch/arm/gemini/gemini_dma.c         |   24 +-
 sys/arch/arm/imx/imx_dma.c               |   24 +-
 sys/arch/arm/include/bus_defs.h          |   65 +++-
 sys/arch/arm/include/bus_funcs.h         |   45 ++-
 sys/arch/arm/ixp12x0/ixp12x0_pci_dma.c   |    7 +-
 sys/arch/arm/marvell/mvsoc_dma.c         |   27 +-
 sys/arch/arm/omap/omap_dma.c             |   25 +-
 sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c    |   27 +-
 sys/arch/arm/xscale/becc.c               |    7 +-
 sys/arch/arm/xscale/i80312.c             |    7 +-
 sys/arch/arm/xscale/i80321.c             |    7 +-
 sys/arch/arm/xscale/ixp425_ixme.c        |    8 +-
 sys/arch/arm/xscale/ixp425_pci_dma.c     |    7 +-
 sys/arch/arm/xscale/pxa2x0_dma.c         |   25 +-
 20 files changed, 705 insertions(+), 294 deletions(-)

diffs (truncated from 1650 to 300 lines):

diff -r 334493e08413 -r d8f0a63ccf71 sys/arch/arm/arm32/bus_dma.c
--- a/sys/arch/arm/arm32/bus_dma.c      Tue Sep 18 05:31:32 2012 +0000
+++ b/sys/arch/arm/arm32/bus_dma.c      Tue Sep 18 05:47:26 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: bus_dma.c,v 1.57 2012/09/11 17:54:12 matt Exp $        */
+/*     $NetBSD: bus_dma.c,v 1.58 2012/09/18 05:47:26 matt Exp $        */
 
 /*-
  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #define _ARM32_BUS_DMA_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.57 2012/09/11 17:54:12 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.58 2012/09/18 05:47:26 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -55,10 +55,44 @@
 
 #include <arm/cpufunc.h>
 
+static struct evcnt bus_dma_creates =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "creates");
+static struct evcnt bus_dma_bounced_creates =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "bounced creates");
+static struct evcnt bus_dma_loads =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "loads");
+static struct evcnt bus_dma_bounced_loads =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "bounced loads");
+static struct evcnt bus_dma_read_bounces =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "read bounces");
+static struct evcnt bus_dma_write_bounces =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "write bounces");
+static struct evcnt bus_dma_bounced_unloads =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "bounced unloads");
+static struct evcnt bus_dma_unloads =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "unloads");
+static struct evcnt bus_dma_bounced_destroys =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "bounced destroys");
+static struct evcnt bus_dma_destroys =
+       EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "busdma", "destroys");
+
+EVCNT_ATTACH_STATIC(bus_dma_creates);
+EVCNT_ATTACH_STATIC(bus_dma_bounced_creates);
+EVCNT_ATTACH_STATIC(bus_dma_loads);
+EVCNT_ATTACH_STATIC(bus_dma_bounced_loads);
+EVCNT_ATTACH_STATIC(bus_dma_read_bounces);
+EVCNT_ATTACH_STATIC(bus_dma_write_bounces);
+EVCNT_ATTACH_STATIC(bus_dma_unloads);
+EVCNT_ATTACH_STATIC(bus_dma_bounced_unloads);
+EVCNT_ATTACH_STATIC(bus_dma_destroys);
+EVCNT_ATTACH_STATIC(bus_dma_bounced_destroys);
+
+#define        STAT_INCR(x)    (bus_dma_ ## x.ev_count++)
+
 int    _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
            bus_size_t, struct vmspace *, int);
-struct arm32_dma_range *_bus_dma_inrange(struct arm32_dma_range *,
-           int, bus_addr_t);
+static struct arm32_dma_range *
+       _bus_dma_inrange(struct arm32_dma_range *, int, bus_addr_t);
 
 /*
  * Check to see if the specified page is in an allowed DMA range.
@@ -89,13 +123,16 @@
 {
        bus_dma_segment_t * const segs = map->dm_segs;
        int nseg = map->dm_nsegs;
-       bus_addr_t lastaddr = 0xdead;   /* XXX gcc */
+       bus_addr_t lastaddr;
        bus_addr_t bmask = ~(map->_dm_boundary - 1);
        bus_addr_t curaddr;
        bus_size_t sgsize;
 
        if (nseg > 0)
                lastaddr = segs[nseg-1].ds_addr + segs[nseg-1].ds_len;
+       else
+               lastaddr = 0xdead;
+       
  again:
        sgsize = size;
 
@@ -156,6 +193,55 @@
        return (0);
 }
 
+#ifdef _ARM32_NEED_BUS_DMA_BOUNCE
+static int _bus_dma_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map,
+           bus_size_t size, int flags);
+static void _bus_dma_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map);
+static int _bus_dma_uiomove(void *buf, struct uio *uio, size_t n,
+           int direction);
+
+static int
+_bus_dma_load_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+       size_t buflen, int buftype, int flags)
+{
+       struct arm32_bus_dma_cookie * const cookie = map->_dm_cookie;
+       struct vmspace * const vm = vmspace_kernel();
+       int error;
+
+       KASSERT(cookie != NULL);
+       KASSERT(cookie->id_flags & _BUS_DMA_MIGHT_NEED_BOUNCE);
+
+       /*
+        * Allocate bounce pages, if necessary.
+        */
+       if ((cookie->id_flags & _BUS_DMA_HAS_BOUNCE) == 0) {
+               error = _bus_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;
+       error = _bus_dmamap_load_buffer(t, map, cookie->id_bouncebuf,
+           buflen, vm, flags);
+       if (error)
+               return (error);
+
+       STAT_INCR(bounced_loads);
+       map->dm_mapsize = buflen;
+       map->_dm_vmspace = vm;
+       map->_dm_buftype = buftype;
+
+       /* ...so _bus_dmamap_sync() knows we're bouncing */
+       cookie->id_flags |= _BUS_DMA_IS_BOUNCING;
+       return 0;
+}
+#endif /* _ARM32_NEED_BUS_DMA_BOUNCE */
+
 /*
  * Common function for DMA map creation.  May be called by bus-specific
  * DMA map creation functions.
@@ -187,11 +273,10 @@
         */
        mapsize = sizeof(struct arm32_bus_dmamap) +
            (sizeof(bus_dma_segment_t) * (nsegments - 1));
-       if ((mapstore = malloc(mapsize, M_DMAMAP,
-           (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
+       const int mallocflags = M_ZERO|(flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK;
+       if ((mapstore = malloc(mapsize, M_DMAMAP, mallocflags)) == NULL)
                return (ENOMEM);
 
-       memset(mapstore, 0, mapsize);
        map = (struct arm32_bus_dmamap *)mapstore;
        map->_dm_size = size;
        map->_dm_segcnt = nsegments;
@@ -199,13 +284,61 @@
        map->_dm_boundary = boundary;
        map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
        map->_dm_origbuf = NULL;
-       map->_dm_buftype = ARM32_BUFTYPE_INVALID;
+       map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID;
        map->_dm_vmspace = vmspace_kernel();
+       map->_dm_cookie = NULL;
        map->dm_maxsegsz = maxsegsz;
        map->dm_mapsize = 0;            /* no valid mappings */
        map->dm_nsegs = 0;
 
        *dmamp = map;
+
+#ifdef _ARM32_NEED_BUS_DMA_BOUNCE
+       struct arm32_bus_dma_cookie *cookie;
+       int cookieflags;
+       void *cookiestore;
+       size_t cookiesize;
+       int error;
+
+       cookieflags = 0;
+
+       if (t->_may_bounce != NULL) {
+               error = (*t->_may_bounce)(t, map, flags, &cookieflags);
+               if (error != 0)
+                       goto out;
+       }
+
+       if (t->_ranges != NULL)
+               cookieflags |= _BUS_DMA_MIGHT_NEED_BOUNCE;
+
+       if ((cookieflags & _BUS_DMA_MIGHT_NEED_BOUNCE) == 0) {
+               STAT_INCR(creates);
+               return 0;
+       }
+
+       cookiesize = sizeof(struct arm32_bus_dma_cookie) +
+           (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
+
+       /*
+        * Allocate our cookie.
+        */
+       if ((cookiestore = malloc(cookiesize, M_DMAMAP, mallocflags)) == NULL) {
+               error = ENOMEM;
+               goto out;
+       }
+       cookie = (struct arm32_bus_dma_cookie *)cookiestore;
+       cookie->id_flags = cookieflags;
+       map->_dm_cookie = cookie;
+       STAT_INCR(bounced_creates);
+
+       error = _bus_dma_alloc_bouncebuf(t, map, size, flags);
+ out:
+       if (error)
+               _bus_dmamap_destroy(t, map);
+#else
+       STAT_INCR(creates);
+#endif /* _ARM32_NEED_BUS_DMA_BOUNCE */
+
 #ifdef DEBUG_DMA
        printf("dmamap_create:map=%p\n", map);
 #endif /* DEBUG_DMA */
@@ -223,16 +356,26 @@
 #ifdef DEBUG_DMA
        printf("dmamap_destroy: t=%p map=%p\n", t, map);
 #endif /* DEBUG_DMA */
+#ifdef _ARM32_NEED_BUS_DMA_BOUNCE
+       struct arm32_bus_dma_cookie *cookie = map->_dm_cookie;
 
        /*
-        * Explicit unload.
+        * Free any bounce pages this map might hold.
         */
-       map->dm_maxsegsz = map->_dm_maxmaxsegsz;
-       map->dm_mapsize = 0;
-       map->dm_nsegs = 0;
-       map->_dm_origbuf = NULL;
-       map->_dm_buftype = ARM32_BUFTYPE_INVALID;
-       map->_dm_vmspace = NULL;
+       if (cookie != NULL) {
+               if (cookie->id_flags & _BUS_DMA_IS_BOUNCING)
+                       STAT_INCR(bounced_unloads);
+               map->dm_nsegs = 0;
+               if (cookie->id_flags & _BUS_DMA_HAS_BOUNCE)
+                       _bus_dma_free_bouncebuf(t, map);
+               STAT_INCR(bounced_destroys);
+               free(cookie, M_DMAMAP);
+       } else
+#endif
+       STAT_INCR(destroys);
+
+       if (map->dm_nsegs > 0)
+               STAT_INCR(unloads);
 
        free(map, M_DMAMAP);
 }
@@ -245,19 +388,33 @@
 _bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
     bus_size_t buflen, struct proc *p, int flags)
 {
+       struct vmspace *vm;
        int error;
-       struct vmspace *vm;
 
 #ifdef DEBUG_DMA
        printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
            t, map, buf, buflen, p, flags);
 #endif /* DEBUG_DMA */
 
+       if (map->dm_nsegs > 0) {
+#ifdef _ARM32_NEED_BUS_DMA_BOUNCE
+               struct arm32_bus_dma_cookie *cookie = map->_dm_cookie;
+               if (cookie != NULL) {
+                       if (cookie->id_flags & _BUS_DMA_IS_BOUNCING) {
+                               STAT_INCR(bounced_unloads);
+                               cookie->id_flags &= ~_BUS_DMA_IS_BOUNCING;
+                       }
+               } else
+#endif
+               STAT_INCR(unloads);
+       }
+
        /*
         * Make sure that on error condition we return "no valid mappings".
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;
+       map->_dm_buftype = _BUS_DMA_BUFTYPE_INVALID;
        KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz);
 
        if (buflen > map->_dm_size)
@@ -270,18 +427,23 @@
        }
 
        /* _bus_dmamap_load_buffer() clears this if we're not... */
-       map->_dm_flags |= ARM32_DMAMAP_COHERENT;
+       map->_dm_flags |= _BUS_DMAMAP_COHERENT;
 
        error = _bus_dmamap_load_buffer(t, map, buf, buflen, vm, flags);
        if (error == 0) {
                map->dm_mapsize = buflen;
+               map->_dm_vmspace = vm;
                map->_dm_origbuf = buf;
-               map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
-               map->_dm_vmspace = vm;
+               map->_dm_buftype = _BUS_DMA_BUFTYPE_LINEAR;



Home | Main Index | Thread Index | Old Index