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