Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/mvme68k Finally nobble the bus_dmamap_sync() proble...
details: https://anonhg.NetBSD.org/src/rev/44676c52142e
branches: trunk
changeset: 510003:44676c52142e
user: scw <scw%NetBSD.org@localhost>
date: Wed May 16 19:06:46 2001 +0000
description:
Finally nobble the bus_dmamap_sync() problem with osiop(4).
Basically, bus_dmamap_sync() `PREREAD' needs to flush the cache
for the start and end of the region if it is not aligned to
a cacheline boundary, otherwise a subsequent POSTREAD can *purge*
valid data which was in the cacheline but *outside* the region
passed to bus_dmamap_sync().
Bus snooping doesn't always help here because osiop(4) calls
bus_dmamap_sync() with POSTREAD even if no data was actually
transferred! (And we can't rely on snooping on the 68060 models anyway).
diffstat:
sys/arch/mvme68k/include/bus_dma.h | 4 +-
sys/arch/mvme68k/include/pmap.h | 3 +-
sys/arch/mvme68k/mvme68k/bus_dma.c | 95 ++++++++++++++++++++++++++++++-------
sys/arch/mvme68k/mvme68k/pmap.c | 20 +++++++-
4 files changed, 100 insertions(+), 22 deletions(-)
diffs (278 lines):
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/include/bus_dma.h
--- a/sys/arch/mvme68k/include/bus_dma.h Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/include/bus_dma.h Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.h,v 1.7 2001/03/07 22:42:19 thorpej Exp $ */
+/* $NetBSD: bus_dma.h,v 1.8 2001/05/16 19:06:46 scw Exp $ */
/*
* This file was extracted from from next68k/include/bus.h
@@ -123,7 +123,7 @@
/* PRIVATE */
bus_addr_t _ds_cpuaddr; /* CPU-relative phys addr of segment */
- int _ds_padding;
+ int _ds_flags;
};
typedef struct mvme68k_bus_dma_segment bus_dma_segment_t;
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/include/pmap.h
--- a/sys/arch/mvme68k/include/pmap.h Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/include/pmap.h Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.20 2001/04/22 23:19:28 thorpej Exp $ */
+/* $NetBSD: pmap.h,v 1.21 2001/05/16 19:06:46 scw Exp $ */
/*
* Copyright (c) 1987 Carnegie-Mellon University
@@ -135,6 +135,7 @@
extern void _pmap_set_page_cacheable __P((struct pmap *, vaddr_t));
extern void _pmap_set_page_cacheinhibit __P((struct pmap *, vaddr_t));
+extern int _pmap_page_is_cacheable __P((struct pmap *, vaddr_t));
extern struct pv_entry *pv_table; /* array of entries, one per page */
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/mvme68k/bus_dma.c
--- a/sys/arch/mvme68k/mvme68k/bus_dma.c Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/mvme68k/bus_dma.c Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.c,v 1.13 2001/05/11 13:01:44 scw Exp $ */
+/* $NetBSD: bus_dma.c,v 1.14 2001/05/16 19:06:47 scw Exp $ */
/*
* This file was taken from from next68k/dev/bus_dma.c, which was originally
@@ -46,7 +46,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.13 2001/05/11 13:01:44 scw Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.14 2001/05/16 19:06:47 scw Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -72,12 +72,6 @@
paddr_t *, int *, int));
/*
- * Initialised in mvme68k/machdep.c according to the host cpu type
- */
-void (*_bus_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
- bus_size_t, int);
-
-/*
* Common function for DMA map creation. May be called by bus-specific
* DMA map creation functions.
*/
@@ -162,7 +156,7 @@
bus_size_t sgsize;
bus_addr_t curaddr, lastaddr, baddr, bmask;
vaddr_t vaddr = (vaddr_t)buf;
- int seg;
+ int seg, cacheable, coherent = BUS_DMA_COHERENT;
lastaddr = *lastaddrp;
bmask = ~(map->_dm_boundary - 1);
@@ -171,11 +165,20 @@
/*
* Get the physical address for this segment.
*/
- if (p != NULL)
+ if (p != NULL) {
(void) pmap_extract(p->p_vmspace->vm_map.pmap,
vaddr, &curaddr);
- else
+ cacheable =
+ _pmap_page_is_cacheable(p->p_vmspace->vm_map.pmap,
+ vaddr);
+ } else {
(void) pmap_extract(pmap_kernel(),vaddr, &curaddr);
+ cacheable =
+ _pmap_page_is_cacheable(pmap_kernel(), vaddr);
+ }
+
+ if (cacheable)
+ coherent = 0;
/*
* Compute the segment size, and adjust counts.
@@ -201,6 +204,8 @@
map->dm_segs[seg].ds_addr =
map->dm_segs[seg]._ds_cpuaddr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
+ map->dm_segs[seg]._ds_flags =
+ cacheable ? 0 : BUS_DMA_COHERENT;
first = 0;
} else {
if (curaddr == lastaddr &&
@@ -216,6 +221,8 @@
map->dm_segs[seg].ds_addr =
map->dm_segs[seg]._ds_cpuaddr = curaddr;
map->dm_segs[seg].ds_len = sgsize;
+ map->dm_segs[seg]._ds_flags =
+ cacheable ? 0 : BUS_DMA_COHERENT;
}
}
@@ -226,6 +233,8 @@
*segp = seg;
*lastaddrp = lastaddr;
+ map->_dm_flags &= ~BUS_DMA_COHERENT;
+ map->_dm_flags |= coherent;
/*
* Did we fit?
@@ -438,6 +447,7 @@
*/
map->dm_mapsize = 0;
map->dm_nsegs = 0;
+ map->_dm_flags &= ~BUS_DMA_COHERENT;
}
/*
@@ -467,11 +477,18 @@
bus_size_t len;
int ops;
{
- bus_addr_t p, e;
+ bus_addr_t p, e, ps, pe;
bus_size_t seglen;
int i;
- if ((ops & (BUS_DMASYNC_PREWRITE | BUS_DMASYNC_POSTREAD)) == 0)
+ /* If the whole DMA map is uncached, do nothing. */
+ if (map->_dm_flags & BUS_DMA_COHERENT)
+ return;
+
+ /* Short-circuit for unsupported `ops' */
+ if ((ops & (BUS_DMASYNC_PREREAD |
+ BUS_DMASYNC_PREWRITE |
+ BUS_DMASYNC_POSTREAD)) == 0)
return;
for (i = 0; i < map->dm_nsegs && len > 0; i++) {
@@ -486,9 +503,16 @@
seglen = len;
len -= seglen;
+ /* Ignore cache-inhibited segments */
+ if (map->dm_segs[i]._ds_flags & BUS_DMA_COHERENT)
+ continue;
+
+ ps = map->dm_segs[i]._ds_cpuaddr + offset;
+ pe = ps + seglen;
+
if (ops & BUS_DMASYNC_PREWRITE) {
- p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
- e = p + ((seglen + 15) & ~0xf);
+ p = ps & ~0xf;
+ e = (pe + 15) & ~0xf;
/* flush cache line (060 too) */
while((p < e) && (p % NBPG)) {
@@ -509,9 +533,39 @@
}
}
+ /*
+ * Normally, the `PREREAD' flag instructs us to purge the
+ * cache for the specified offset and length. However, if
+ * the offset/length is not aligned to a cacheline boundary,
+ * we may end up purging some legitimate data from the
+ * start/end of the cache. In such a case, *flush* the
+ * cachelines at the start and end of the required region.
+ * We assume someone will do a `POSTREAD' afterwards to
+ * ensure the cache is purged for the remainder of the region.
+ *
+ * Note: Even though the high-end MVME boards support bus-
+ * snooping (well, the 060 isn't *quite* there), the osiop(4)
+ * driver *ALWAYS* issues a `POSTREAD' EVEN IF NO DATA WAS
+ * TRANSFERRED!
+ *
+ * This isn't necessarily a bug, since a SCSI target is free
+ * to disconnect part way through a data-in phase anyway.
+ * Thus, the CPU may never get to snoop the incoming data
+ * before we purge the dmamap region.
+ *
+ * Note #2: All this is necessary on mvme68k because we
+ * normally run the cache in Copy Back mode...
+ */
+ if (ops & BUS_DMASYNC_PREREAD) {
+ if (ps & 0xf)
+ DCFL_40(ps);
+ if (pe & 0xf)
+ DCFL_40(pe);
+ }
+
if (ops & BUS_DMASYNC_POSTREAD) {
- p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
- e = p + ((seglen + 15) & ~0xf);
+ p = ps & ~0xf;
+ e = (pe + 15) & ~0xf;
/* purge cache line */
while((p < e) && (p % NBPG)) {
@@ -583,6 +637,7 @@
lastaddr = VM_PAGE_TO_PHYS(m);
segs[curseg].ds_addr = segs[curseg]._ds_cpuaddr = lastaddr;
segs[curseg].ds_len = PAGE_SIZE;
+ segs[curseg]._ds_flags = 0;
m = m->pageq.tqe_next;
for (; m != NULL; m = m->pageq.tqe_next) {
@@ -612,6 +667,7 @@
segs[curseg].ds_addr =
segs[curseg]._ds_cpuaddr = curaddr;
segs[curseg].ds_len = PAGE_SIZE;
+ segs[curseg]._ds_flags = 0;
}
lastaddr = curaddr;
}
@@ -728,8 +784,11 @@
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
/* Cache-inhibit the page if necessary */
- if ( (flags & BUS_DMA_COHERENT) != 0 )
+ if ((flags & BUS_DMA_COHERENT) != 0)
_pmap_set_page_cacheinhibit(pmap_kernel(), va);
+
+ segs[curseg]._ds_flags &= ~BUS_DMA_COHERENT;
+ segs[curseg]._ds_flags |= (flags & BUS_DMA_COHERENT);
}
}
pmap_update();
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/mvme68k/pmap.c
--- a/sys/arch/mvme68k/mvme68k/pmap.c Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/mvme68k/pmap.c Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.59 2001/05/13 18:35:19 scw Exp $ */
+/* $NetBSD: pmap.c,v 1.60 2001/05/16 19:06:47 scw Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -2739,6 +2739,24 @@
}
}
+int
+_pmap_page_is_cacheable(pm, va)
+ struct pmap *pm;
+ vaddr_t va;
+{
+ pt_entry_t *pte;
+
+ if (!pmap_ste_v(pm, va))
+ return (0);
+
+ pte = pmap_pte(pm, va);
+
+ if (pmap_pte_ci(pte))
+ return (0);
+ else
+ return (1);
+}
+
#ifdef DEBUG
/*
* pmap_pvdump:
Home |
Main Index |
Thread Index |
Old Index