Use proper mips_dcache_{wb,inv,wbinv}_range() ops in dmamap sync function

if possible. Tested on my O2 (with r5ksc patch).

XXX should we apply similar changes to mips/bus_dma.c and use it?
This commit is contained in:
tsutsui 2003-10-07 16:03:09 +00:00
parent 24679f3c3d
commit 608b19ae28
2 changed files with 86 additions and 29 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus.h,v 1.9 2003/10/05 15:38:08 tsutsui Exp $ */ /* $NetBSD: bus.h,v 1.10 2003/10/07 16:03:09 tsutsui Exp $ */
/* /*
* Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
@ -613,6 +613,7 @@ struct sgimips_bus_dmamap {
bus_size_t _dm_maxsegsz; /* largest possible segment */ bus_size_t _dm_maxsegsz; /* largest possible segment */
bus_size_t _dm_boundary; /* don't cross this */ bus_size_t _dm_boundary; /* don't cross this */
int _dm_flags; /* misc. flags */ int _dm_flags; /* misc. flags */
struct proc *_dm_proc; /* proc that owns the mapping */
/* /*
* PUBLIC MEMBERS: these are used by machine-independent code. * PUBLIC MEMBERS: these are used by machine-independent code.

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus.c,v 1.21 2003/10/07 14:37:06 tsutsui Exp $ */ /* $NetBSD: bus.c,v 1.22 2003/10/07 16:03:09 tsutsui Exp $ */
/* /*
* Copyright (c) 1998 The NetBSD Foundation, Inc. * Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.21 2003/10/07 14:37:06 tsutsui Exp $"); __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.22 2003/10/07 16:03:09 tsutsui Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -314,6 +314,7 @@ _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
map->_dm_maxsegsz = maxsegsz; map->_dm_maxsegsz = maxsegsz;
map->_dm_boundary = boundary; map->_dm_boundary = boundary;
map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
map->_dm_proc = NULL;
map->dm_mapsize = 0; /* no valid mappings */ map->dm_mapsize = 0; /* no valid mappings */
map->dm_nsegs = 0; map->dm_nsegs = 0;
@ -460,6 +461,7 @@ _bus_dmamap_load(t, map, buf, buflen, p, flags)
if (error == 0) { if (error == 0) {
map->dm_mapsize = buflen; map->dm_mapsize = buflen;
map->dm_nsegs = seg + 1; map->dm_nsegs = seg + 1;
map->_dm_proc = p;
/* /*
* For linear buffers, we support marking the mapping * For linear buffers, we support marking the mapping
@ -513,6 +515,7 @@ _bus_dmamap_load_mbuf(t, map, m0, flags)
if (error == 0) { if (error == 0) {
map->dm_mapsize = m0->m_pkthdr.len; map->dm_mapsize = m0->m_pkthdr.len;
map->dm_nsegs = seg + 1; map->dm_nsegs = seg + 1;
map->_dm_proc = NULL; /* always kernel */
} }
return error; return error;
} }
@ -571,6 +574,7 @@ _bus_dmamap_load_uio(t, map, uio, flags)
if (error == 0) { if (error == 0) {
map->dm_mapsize = uio->uio_resid; map->dm_mapsize = uio->uio_resid;
map->dm_nsegs = seg + 1; map->dm_nsegs = seg + 1;
map->_dm_proc = p;
} }
return error; return error;
} }
@ -623,8 +627,8 @@ _bus_dmamap_sync(t, map, offset, len, ops)
int ops; int ops;
{ {
bus_size_t minlen; bus_size_t minlen;
bus_addr_t addr; bus_addr_t addr, start, end, preboundary, firstboundary, lastboundary;
int i; int i, useindex;
/* /*
* Mising PRE and POST operations is not allowed. * Mising PRE and POST operations is not allowed.
@ -641,11 +645,38 @@ _bus_dmamap_sync(t, map, offset, len, ops)
panic("_bus_dmamap_sync: bad length"); panic("_bus_dmamap_sync: bad length");
#endif #endif
/*
* Since we're dealing with a virtually-indexed, write-back
* cache, we need to do the following things:
*
* PREREAD -- Invalidate D-cache. Note we might have
* to also write-back here if we have to use an Index
* op, or if the buffer start/end is not cache-line aligned.
*
* PREWRITE -- Write-back the D-cache. If we have to use
* an Index op, we also have to invalidate. Note that if
* we are doing PREREAD|PREWRITE, we can collapse everything
* into a single op.
*
* POSTREAD -- Nothing.
*
* POSTWRITE -- Nothing.
*/
/* /*
* Flush the write buffer. * Flush the write buffer.
* XXX Is this always necessary?
*/ */
wbflush(); wbflush();
/*
* No cache flushes are necessary if we're only doing
* POSTREAD or POSTWRITE (i.e. not doing PREREAD or PREWRITE).
*/
ops &= (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
if (ops == 0)
return;
/* /*
* If the mapping is of COHERENT DMA-safe memory, no cache * If the mapping is of COHERENT DMA-safe memory, no cache
* flush is necessary. * flush is necessary.
@ -654,23 +685,16 @@ _bus_dmamap_sync(t, map, offset, len, ops)
return; return;
/* /*
* No cache flushes are necessary if we're only doing * If the mapping belongs to the kernel, or it belongs
* POSTREAD or POSTWRITE (i.e. not doing PREREAD or PREWRITE). * to the currently-running process (XXX actually, vmspace),
*/ * then we can use Hit ops. Otherwise, Index ops.
if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) == 0)
return;
/*
* Flush data cache for PREREAD. This has the side-effect
* of invalidating the cache. Done at PREREAD since it
* causes the cache line(s) to be written back to memory.
* *
* Flush data cache for PREWRITE, so that the contents of * This should be true the vast majority of the time.
* the data buffer in memory reflect reality.
*
* Given the test above, we know we're doing one of these
* two operations, so no additional tests are necessary.
*/ */
if (__predict_true(map->_dm_proc == NULL || map->_dm_proc == curproc))
useindex = 0;
else
useindex = 1;
for (i = 0; i < map->dm_nsegs && len != 0; i++) { for (i = 0; i < map->dm_nsegs && len != 0; i++) {
/* Find the beginning segment. */ /* Find the beginning segment. */
@ -694,16 +718,48 @@ _bus_dmamap_sync(t, map, offset, len, ops)
"(0x%lx+%lx, 0x%lx+0x%lx) (olen = %ld)...", i, "(0x%lx+%lx, 0x%lx+0x%lx) (olen = %ld)...", i,
addr, offset, addr, offset + minlen - 1, len); addr, offset, addr, offset + minlen - 1, len);
#endif #endif
#if 0
MachFlushDCache(addr + offset, minlen);
#endif
#if 1
mips_dcache_wbinv_range(addr + offset, minlen);
#endif
#if 0
MachFlushCache();
#endif
/*
* If we are forced to use Index ops, it's always a
* Write-back,Invalidate, so just do one test.
*/
if (__predict_false(useindex)) {
mips_dcache_wbinv_range_index(addr + offset, minlen);
#ifdef BUS_DMA_DEBUG
printf("\n");
#endif
offset = 0;
len -= minlen;
continue;
}
start = addr + offset;
switch (ops) {
case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
mips_dcache_wbinv_range(start, minlen);
break;
case BUS_DMASYNC_PREREAD:
end = start + minlen;
preboundary = start & ~mips_dcache_align_mask;
firstboundary = (start + mips_dcache_align_mask)
& ~mips_dcache_align_mask;
lastboundary = end & ~mips_dcache_align_mask;
if (preboundary < start && preboundary < lastboundary)
mips_dcache_wbinv_range(preboundary,
mips_dcache_align);
if (firstboundary < lastboundary)
mips_dcache_inv_range(firstboundary,
lastboundary - firstboundary);
if (lastboundary < end)
mips_dcache_wbinv_range(lastboundary,
mips_dcache_align);
break;
case BUS_DMASYNC_PREWRITE:
mips_dcache_wb_range(start, minlen);
break;
}
#ifdef BUS_DMA_DEBUG #ifdef BUS_DMA_DEBUG
printf("\n"); printf("\n");
#endif #endif