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).
This commit is contained in:
parent
35f2b9136a
commit
c22fb1db55
@ -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
|
* This file was extracted from from next68k/include/bus.h
|
||||||
@ -123,7 +123,7 @@ struct mvme68k_bus_dma_segment {
|
|||||||
|
|
||||||
/* PRIVATE */
|
/* PRIVATE */
|
||||||
bus_addr_t _ds_cpuaddr; /* CPU-relative phys addr of segment */
|
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;
|
typedef struct mvme68k_bus_dma_segment bus_dma_segment_t;
|
||||||
|
|
||||||
|
@ -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
|
* Copyright (c) 1987 Carnegie-Mellon University
|
||||||
@ -135,6 +135,7 @@ extern struct pmap kernel_pmap_store;
|
|||||||
|
|
||||||
extern void _pmap_set_page_cacheable __P((struct pmap *, vaddr_t));
|
extern void _pmap_set_page_cacheable __P((struct pmap *, vaddr_t));
|
||||||
extern void _pmap_set_page_cacheinhibit __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 */
|
extern struct pv_entry *pv_table; /* array of entries, one per page */
|
||||||
|
|
||||||
|
@ -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
|
* 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 */
|
#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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
@ -71,12 +71,6 @@ int _bus_dmamap_load_buffer_direct_common __P((bus_dma_tag_t,
|
|||||||
bus_dmamap_t, void *, bus_size_t, struct proc *, int,
|
bus_dmamap_t, void *, bus_size_t, struct proc *, int,
|
||||||
paddr_t *, int *, int));
|
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
|
* Common function for DMA map creation. May be called by bus-specific
|
||||||
* DMA map creation functions.
|
* DMA map creation functions.
|
||||||
@ -162,7 +156,7 @@ _bus_dmamap_load_buffer_direct_common(t, map, buf, buflen, p, flags,
|
|||||||
bus_size_t sgsize;
|
bus_size_t sgsize;
|
||||||
bus_addr_t curaddr, lastaddr, baddr, bmask;
|
bus_addr_t curaddr, lastaddr, baddr, bmask;
|
||||||
vaddr_t vaddr = (vaddr_t)buf;
|
vaddr_t vaddr = (vaddr_t)buf;
|
||||||
int seg;
|
int seg, cacheable, coherent = BUS_DMA_COHERENT;
|
||||||
|
|
||||||
lastaddr = *lastaddrp;
|
lastaddr = *lastaddrp;
|
||||||
bmask = ~(map->_dm_boundary - 1);
|
bmask = ~(map->_dm_boundary - 1);
|
||||||
@ -171,11 +165,20 @@ _bus_dmamap_load_buffer_direct_common(t, map, buf, buflen, p, flags,
|
|||||||
/*
|
/*
|
||||||
* Get the physical address for this segment.
|
* Get the physical address for this segment.
|
||||||
*/
|
*/
|
||||||
if (p != NULL)
|
if (p != NULL) {
|
||||||
(void) pmap_extract(p->p_vmspace->vm_map.pmap,
|
(void) pmap_extract(p->p_vmspace->vm_map.pmap,
|
||||||
vaddr, &curaddr);
|
vaddr, &curaddr);
|
||||||
else
|
cacheable =
|
||||||
|
_pmap_page_is_cacheable(p->p_vmspace->vm_map.pmap,
|
||||||
|
vaddr);
|
||||||
|
} else {
|
||||||
(void) pmap_extract(pmap_kernel(),vaddr, &curaddr);
|
(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.
|
* Compute the segment size, and adjust counts.
|
||||||
@ -201,6 +204,8 @@ _bus_dmamap_load_buffer_direct_common(t, map, buf, buflen, p, flags,
|
|||||||
map->dm_segs[seg].ds_addr =
|
map->dm_segs[seg].ds_addr =
|
||||||
map->dm_segs[seg]._ds_cpuaddr = curaddr;
|
map->dm_segs[seg]._ds_cpuaddr = curaddr;
|
||||||
map->dm_segs[seg].ds_len = sgsize;
|
map->dm_segs[seg].ds_len = sgsize;
|
||||||
|
map->dm_segs[seg]._ds_flags =
|
||||||
|
cacheable ? 0 : BUS_DMA_COHERENT;
|
||||||
first = 0;
|
first = 0;
|
||||||
} else {
|
} else {
|
||||||
if (curaddr == lastaddr &&
|
if (curaddr == lastaddr &&
|
||||||
@ -216,6 +221,8 @@ _bus_dmamap_load_buffer_direct_common(t, map, buf, buflen, p, flags,
|
|||||||
map->dm_segs[seg].ds_addr =
|
map->dm_segs[seg].ds_addr =
|
||||||
map->dm_segs[seg]._ds_cpuaddr = curaddr;
|
map->dm_segs[seg]._ds_cpuaddr = curaddr;
|
||||||
map->dm_segs[seg].ds_len = sgsize;
|
map->dm_segs[seg].ds_len = sgsize;
|
||||||
|
map->dm_segs[seg]._ds_flags =
|
||||||
|
cacheable ? 0 : BUS_DMA_COHERENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +233,8 @@ _bus_dmamap_load_buffer_direct_common(t, map, buf, buflen, p, flags,
|
|||||||
|
|
||||||
*segp = seg;
|
*segp = seg;
|
||||||
*lastaddrp = lastaddr;
|
*lastaddrp = lastaddr;
|
||||||
|
map->_dm_flags &= ~BUS_DMA_COHERENT;
|
||||||
|
map->_dm_flags |= coherent;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Did we fit?
|
* Did we fit?
|
||||||
@ -438,6 +447,7 @@ _bus_dmamap_unload(t, map)
|
|||||||
*/
|
*/
|
||||||
map->dm_mapsize = 0;
|
map->dm_mapsize = 0;
|
||||||
map->dm_nsegs = 0;
|
map->dm_nsegs = 0;
|
||||||
|
map->_dm_flags &= ~BUS_DMA_COHERENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -467,11 +477,18 @@ _bus_dmamap_sync_0460(t, map, offset, len, ops)
|
|||||||
bus_size_t len;
|
bus_size_t len;
|
||||||
int ops;
|
int ops;
|
||||||
{
|
{
|
||||||
bus_addr_t p, e;
|
bus_addr_t p, e, ps, pe;
|
||||||
bus_size_t seglen;
|
bus_size_t seglen;
|
||||||
int i;
|
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;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < map->dm_nsegs && len > 0; i++) {
|
for (i = 0; i < map->dm_nsegs && len > 0; i++) {
|
||||||
@ -486,9 +503,16 @@ _bus_dmamap_sync_0460(t, map, offset, len, ops)
|
|||||||
seglen = len;
|
seglen = len;
|
||||||
len -= seglen;
|
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) {
|
if (ops & BUS_DMASYNC_PREWRITE) {
|
||||||
p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
|
p = ps & ~0xf;
|
||||||
e = p + ((seglen + 15) & ~0xf);
|
e = (pe + 15) & ~0xf;
|
||||||
|
|
||||||
/* flush cache line (060 too) */
|
/* flush cache line (060 too) */
|
||||||
while((p < e) && (p % NBPG)) {
|
while((p < e) && (p % NBPG)) {
|
||||||
@ -509,9 +533,39 @@ _bus_dmamap_sync_0460(t, map, offset, len, ops)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
if (ops & BUS_DMASYNC_POSTREAD) {
|
||||||
p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
|
p = ps & ~0xf;
|
||||||
e = p + ((seglen + 15) & ~0xf);
|
e = (pe + 15) & ~0xf;
|
||||||
|
|
||||||
/* purge cache line */
|
/* purge cache line */
|
||||||
while((p < e) && (p % NBPG)) {
|
while((p < e) && (p % NBPG)) {
|
||||||
@ -583,6 +637,7 @@ _bus_dmamem_alloc_common(t, low, high, size, alignment, boundary,
|
|||||||
lastaddr = VM_PAGE_TO_PHYS(m);
|
lastaddr = VM_PAGE_TO_PHYS(m);
|
||||||
segs[curseg].ds_addr = segs[curseg]._ds_cpuaddr = lastaddr;
|
segs[curseg].ds_addr = segs[curseg]._ds_cpuaddr = lastaddr;
|
||||||
segs[curseg].ds_len = PAGE_SIZE;
|
segs[curseg].ds_len = PAGE_SIZE;
|
||||||
|
segs[curseg]._ds_flags = 0;
|
||||||
m = m->pageq.tqe_next;
|
m = m->pageq.tqe_next;
|
||||||
|
|
||||||
for (; m != NULL; m = m->pageq.tqe_next) {
|
for (; m != NULL; m = m->pageq.tqe_next) {
|
||||||
@ -612,6 +667,7 @@ _bus_dmamem_alloc_common(t, low, high, size, alignment, boundary,
|
|||||||
segs[curseg].ds_addr =
|
segs[curseg].ds_addr =
|
||||||
segs[curseg]._ds_cpuaddr = curaddr;
|
segs[curseg]._ds_cpuaddr = curaddr;
|
||||||
segs[curseg].ds_len = PAGE_SIZE;
|
segs[curseg].ds_len = PAGE_SIZE;
|
||||||
|
segs[curseg]._ds_flags = 0;
|
||||||
}
|
}
|
||||||
lastaddr = curaddr;
|
lastaddr = curaddr;
|
||||||
}
|
}
|
||||||
@ -728,8 +784,11 @@ _bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
|
|||||||
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
|
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
|
||||||
|
|
||||||
/* Cache-inhibit the page if necessary */
|
/* 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);
|
_pmap_set_page_cacheinhibit(pmap_kernel(), va);
|
||||||
|
|
||||||
|
segs[curseg]._ds_flags &= ~BUS_DMA_COHERENT;
|
||||||
|
segs[curseg]._ds_flags |= (flags & BUS_DMA_COHERENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pmap_update();
|
pmap_update();
|
||||||
|
@ -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.
|
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||||
@ -2739,6 +2739,24 @@ _pmap_set_page_cacheinhibit(pm, va)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#ifdef DEBUG
|
||||||
/*
|
/*
|
||||||
* pmap_pvdump:
|
* pmap_pvdump:
|
||||||
|
Loading…
Reference in New Issue
Block a user