Change the way that DMA map syncs are done. Instead of remembering

the virtual address for each DMA segment, just cache a pointer to the
original buffer/buftype used to load the DMA map, and use that.  This
lets us shrink the bus_dma_segment_t down from 12 bytes to 8, and the
cache flushing is also more efficient.

Tested on an i80321 -- changes to others are mechanical.
This commit is contained in:
thorpej 2002-07-28 17:54:05 +00:00
parent 08ea4bc534
commit 7b652cb939
6 changed files with 198 additions and 64 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus_dma.c,v 1.13 2002/06/28 15:21:00 briggs Exp $ */
/* $NetBSD: bus_dma.c,v 1.14 2002/07/28 17:54:05 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@ -106,6 +106,8 @@ _bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
map->_dm_maxsegsz = maxsegsz;
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_proc = NULL;
map->dm_mapsize = 0; /* no valid mappings */
map->dm_nsegs = 0;
@ -134,6 +136,8 @@ _bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
*/
map->dm_mapsize = 0;
map->dm_nsegs = 0;
map->_dm_origbuf = NULL;
map->_dm_buftype = ARM32_BUFTYPE_INVALID;
map->_dm_proc = NULL;
free(map, M_DEVBUF);
@ -170,6 +174,8 @@ _bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (error == 0) {
map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = buf;
map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
map->_dm_proc = p;
}
#ifdef DEBUG_DMA
@ -219,6 +225,8 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = m0;
map->_dm_buftype = ARM32_BUFTYPE_MBUF;
map->_dm_proc = NULL; /* always kernel */
}
#ifdef DEBUG_DMA
@ -278,6 +286,8 @@ _bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
if (error == 0) {
map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = uio;
map->_dm_buftype = ARM32_BUFTYPE_UIO;
map->_dm_proc = p;
}
return (error);
@ -313,9 +323,137 @@ _bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
*/
map->dm_mapsize = 0;
map->dm_nsegs = 0;
map->_dm_origbuf = NULL;
map->_dm_buftype = ARM32_BUFTYPE_INVALID;
map->_dm_proc = NULL;
}
static void
_bus_dmamap_sync_linear(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
vaddr_t addr = (vaddr_t) map->_dm_origbuf;
addr += offset;
len -= offset;
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
cpu_dcache_wbinv_range(addr, len);
break;
case BUS_DMASYNC_PREREAD:
#if 1
cpu_dcache_wbinv_range(addr, len);
#else
cpu_dcache_inv_range(addr, len);
#endif
break;
case BUS_DMASYNC_PREWRITE:
cpu_dcache_wb_range(addr, len);
break;
}
}
static void
_bus_dmamap_sync_mbuf(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
struct mbuf *m, *m0 = map->_dm_origbuf;
bus_size_t minlen, moff;
vaddr_t maddr;
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 = m->m_len - moff;
if (len < minlen)
minlen = len;
maddr = mtod(m, vaddr_t);
maddr += moff;
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
cpu_dcache_wbinv_range(maddr, minlen);
break;
case BUS_DMASYNC_PREREAD:
#if 1
cpu_dcache_wbinv_range(maddr, minlen);
#else
cpu_dcache_inv_range(maddr, minlen);
#endif
break;
case BUS_DMASYNC_PREWRITE:
cpu_dcache_wb_range(maddr, minlen);
break;
}
moff = 0;
len -= minlen;
}
}
static void
_bus_dmamap_sync_uio(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
struct uio *uio = map->_dm_origbuf;
struct iovec *iov;
bus_size_t minlen, ioff;
vaddr_t addr;
for (iov = uio->uio_iov, ioff = offset; len != 0; iov++) {
/* Find the beginning iovec. */
if (ioff >= iov->iov_len) {
ioff -= iov->iov_len;
continue;
}
/*
* Now at the first iovec to sync; nail each one until
* we have exhausted the length.
*/
minlen = iov->iov_len - ioff;
if (len < minlen)
minlen = len;
addr = (vaddr_t) iov->iov_base;
addr += ioff;
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
cpu_dcache_wbinv_range(addr, minlen);
break;
case BUS_DMASYNC_PREREAD:
#if 1
cpu_dcache_wbinv_range(addr, minlen);
#else
cpu_dcache_inv_range(addr, minlen);
#endif
break;
case BUS_DMASYNC_PREWRITE:
cpu_dcache_wb_range(addr, minlen);
break;
}
ioff = 0;
len -= minlen;
}
}
/*
* Common function for DMA map synchronization. May be called
* by bus-specific DMA map synchronization functions.
@ -332,9 +470,6 @@ void
_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
bus_size_t minlen;
bus_addr_t addr;
int i;
#ifdef DEBUG_DMA
printf("dmamap_sync: t=%p map=%p offset=%lx len=%lx ops=%x\n",
@ -391,51 +526,30 @@ _bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
if (__predict_false(map->_dm_proc != NULL && map->_dm_proc != curproc))
return;
for (i = 0; i < map->dm_nsegs && len != 0; i++) {
/* Find beginning segment. */
if (offset >= map->dm_segs[i].ds_len) {
offset -= map->dm_segs[i].ds_len;
continue;
}
switch (map->_dm_buftype) {
case ARM32_BUFTYPE_LINEAR:
_bus_dmamap_sync_linear(t, map, offset, len, ops);
break;
/*
* Now at the first segment to sync; nail
* each segment until we have exhausted the
* length.
*/
minlen = len < map->dm_segs[i].ds_len - offset ?
len : map->dm_segs[i].ds_len - offset;
case ARM32_BUFTYPE_MBUF:
_bus_dmamap_sync_mbuf(t, map, offset, len, ops);
break;
addr = map->dm_segs[i]._ds_vaddr;
case ARM32_BUFTYPE_UIO:
_bus_dmamap_sync_uio(t, map, offset, len, ops);
break;
#ifdef DEBUG_DMA
printf("bus_dmamap_sync: flushing segment %d "
"(0x%lx..0x%lx) ...", i, addr + offset,
addr + offset + minlen - 1);
#endif
case ARM32_BUFTYPE_RAW:
panic("_bus_dmamap_sync: ARM32_BUFTYPE_RAW");
break;
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
cpu_dcache_wbinv_range(addr + offset, minlen);
break;
case ARM32_BUFTYPE_INVALID:
panic("_bus_dmamap_sync: ARM32_BUFTYPE_INVALID");
break;
case BUS_DMASYNC_PREREAD:
#if 1
cpu_dcache_wbinv_range(addr + offset, minlen);
#else
cpu_dcache_inv_range(addr + offset, minlen);
#endif
break;
case BUS_DMASYNC_PREWRITE:
cpu_dcache_wb_range(addr + offset, minlen);
break;
}
#ifdef DEBUG_DMA
printf("\n");
#endif
offset = 0;
len -= minlen;
default:
printf("unknown buffer type %d\n", map->_dm_buftype);
panic("_bus_dmamap_sync");
}
/* Drain the write buffer. */
@ -690,7 +804,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (first) {
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
first = 0;
} else {
if (curaddr == lastaddr &&
@ -705,7 +818,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
break;
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus.h,v 1.4 2002/01/25 20:57:43 thorpej Exp $ */
/* $NetBSD: bus.h,v 1.5 2002/07/28 17:54:06 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
@ -661,11 +661,6 @@ struct arm32_bus_dma_segment {
*/
bus_addr_t ds_addr; /* DMA address */
bus_size_t ds_len; /* length of transfer */
/*
* PRIVATE MEMBERS: not for use by machine-independent code.
*/
bus_addr_t _ds_vaddr; /* Virtual mapped address
* Used by bus_dmamem_sync() */
};
typedef struct arm32_bus_dma_segment bus_dma_segment_t;
@ -761,6 +756,9 @@ struct arm32_bus_dmamap {
bus_size_t _dm_maxsegsz; /* largest possible segment */
bus_size_t _dm_boundary; /* don't cross this */
int _dm_flags; /* misc. flags */
void *_dm_origbuf; /* pointer to original buffer */
int _dm_buftype; /* type of buffer */
struct proc *_dm_proc; /* proc that owns the mapping */
void *_dm_cookie; /* cookie for bus-specific functions */
@ -774,6 +772,14 @@ struct arm32_bus_dmamap {
};
#ifdef _ARM32_BUS_DMA_PRIVATE
/* _dm_buftype */
#define ARM32_BUFTYPE_INVALID 0
#define ARM32_BUFTYPE_LINEAR 1
#define ARM32_BUFTYPE_MBUF 2
#define ARM32_BUFTYPE_UIO 3
#define ARM32_BUFTYPE_RAW 4
int _bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, bus_size_t,
bus_size_t, int, bus_dmamap_t *));
void _bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t));

View File

@ -1,4 +1,4 @@
/* $NetBSD: i80312_pci_dma.c,v 1.3 2002/05/02 16:50:39 thorpej Exp $ */
/* $NetBSD: i80312_pci_dma.c,v 1.4 2002/07/28 17:54:06 thorpej Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@ -158,7 +158,6 @@ i80312_pci_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
if (first) {
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
first = 0;
} else {
if (curaddr == lastaddr &&
@ -173,7 +172,6 @@ i80312_pci_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
break;
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
}
}
@ -218,6 +216,8 @@ i80312_pci_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (error == 0) {
map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = buf;
map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
map->_dm_proc = p;
}
@ -262,6 +262,8 @@ i80312_pci_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = m0;
map->_dm_buftype = ARM32_BUFTYPE_MBUF;
map->_dm_proc = NULL; /* always kernel */
}
@ -322,6 +324,8 @@ i80312_pci_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = uio;
map->_dm_buftype = ARM32_BUFTYPE_UIO;
map->_dm_proc = p;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: i80321_local_dma.c,v 1.1 2002/07/25 15:00:49 thorpej Exp $ */
/* $NetBSD: i80321_local_dma.c,v 1.2 2002/07/28 17:54:06 thorpej Exp $ */
/*
* Copyright (c) 2001, 2002 Wasabi Systems, Inc.
@ -138,7 +138,6 @@ i80321_local_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
if (first) {
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
first = 0;
} else {
if (curaddr == lastaddr &&
@ -153,7 +152,6 @@ i80321_local_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
break;
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
}
}
@ -198,6 +196,8 @@ i80321_local_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (error == 0) {
map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = buf;
map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
map->_dm_proc = p;
}
@ -242,6 +242,8 @@ i80321_local_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = m0;
map->_dm_buftype = ARM32_BUFTYPE_MBUF;
map->_dm_proc = NULL; /* always kernel */
}
@ -302,6 +304,8 @@ i80321_local_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = uio;
map->_dm_buftype = ARM32_BUFTYPE_UIO;
map->_dm_proc = p;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: i80321_pci_dma.c,v 1.3 2002/05/02 16:50:40 thorpej Exp $ */
/* $NetBSD: i80321_pci_dma.c,v 1.4 2002/07/28 17:54:06 thorpej Exp $ */
/*
* Copyright (c) 2001, 2002 Wasabi Systems, Inc.
@ -159,7 +159,6 @@ i80321_pci_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
if (first) {
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
first = 0;
} else {
if (curaddr == lastaddr &&
@ -174,7 +173,6 @@ i80321_pci_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map,
break;
map->dm_segs[seg].ds_addr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
}
}
@ -219,6 +217,8 @@ i80321_pci_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (error == 0) {
map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = buf;
map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
map->_dm_proc = p;
}
@ -263,6 +263,8 @@ i80321_pci_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = m0;
map->_dm_buftype = ARM32_BUFTYPE_MBUF;
map->_dm_proc = NULL; /* always kernel */
}
@ -323,6 +325,8 @@ i80321_pci_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
if (error == 0) {
map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = uio;
map->_dm_buftype = ARM32_BUFTYPE_UIO;
map->_dm_proc = p;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: int_bus_dma.c,v 1.8 2002/06/02 14:44:45 drochner Exp $ */
/* $NetBSD: int_bus_dma.c,v 1.9 2002/07/28 17:54:06 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@ -109,6 +109,8 @@ integrator_bus_dmamap_load(t, map, buf, buflen, p, flags)
if (error == 0) {
map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = buf;
map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
map->_dm_proc = p;
}
#ifdef DEBUG_DMA
@ -161,6 +163,8 @@ integrator_bus_dmamap_load_mbuf(t, map, m0, flags)
if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = m0;
map->_dm_buftype = ARM32_BUFTYPE_MBUF;
map->_dm_proc = NULL; /* always kernel */
}
#ifdef DEBUG_DMA
@ -223,6 +227,8 @@ integrator_bus_dmamap_load_uio(t, map, uio, flags)
if (error == 0) {
map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1;
map->_dm_origbuf = uio;
map->_dm_buftype = ARM32_BUFTYPE_UIO;
map->_dm_proc = p;
}
return (error);
@ -480,7 +486,6 @@ integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp,
if (first) {
map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
first = 0;
} else {
if (curaddr == lastaddr &&
@ -495,7 +500,6 @@ integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp,
break;
map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
map->dm_segs[seg].ds_len = sgsize;
map->dm_segs[seg]._ds_vaddr = vaddr;
}
}