add a PMAP_NC flag for pmap_kenter_pa() to specific a non-cached mapping.

use this in mbus_dmamem_map() to fix corruption of DMA memory.
note that this TLB bit is ignored on some CPUs (PA7100 and probably
others of that era), so this doesn't fix the problem in general,
but it does work on newer models and will make things easier later.
This commit is contained in:
chs 2004-01-05 02:25:32 +00:00
parent 113854bb28
commit 7e6508e29e
3 changed files with 26 additions and 40 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: mainbus.c,v 1.15 2003/11/24 02:51:35 chs Exp $ */ /* $NetBSD: mainbus.c,v 1.16 2004/01/05 02:25:32 chs Exp $ */
/*- /*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -70,7 +70,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.15 2003/11/24 02:51:35 chs Exp $"); __KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.16 2004/01/05 02:25:32 chs Exp $");
#undef BTLBDEBUG #undef BTLBDEBUG
@ -849,8 +849,7 @@ mbus_dmamap_load(void *v, bus_dmamap_t map, void *addr, bus_size_t size,
mapsize = size; mapsize = size;
off = (bus_size_t)addr & (PAGE_SIZE - 1); off = (bus_size_t)addr & (PAGE_SIZE - 1);
addr = (void *) ((caddr_t)addr - off); addr = (void *) ((caddr_t)addr - off);
for(; size > 0; ) { while (size > 0) {
pa = kvtop(addr); pa = kvtop(addr);
if (pa != pa_next) { if (pa != pa_next) {
if (++seg >= map->_dm_segcnt) if (++seg >= map->_dm_segcnt)
@ -871,7 +870,6 @@ mbus_dmamap_load(void *v, bus_dmamap_t map, void *addr, bus_size_t size,
/* Make the map truly valid. */ /* Make the map truly valid. */
map->dm_nsegs = seg + 1; map->dm_nsegs = seg + 1;
map->dm_mapsize = mapsize; map->dm_mapsize = mapsize;
return (0); return (0);
} }
@ -1111,11 +1109,10 @@ int
mbus_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size, mbus_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size,
caddr_t *kvap, int flags) caddr_t *kvap, int flags)
{ {
struct vm_page *m; struct vm_page *pg;
struct pglist *pglist;
vaddr_t va; vaddr_t va;
struct pglist *mlist; paddr_t pa;
paddr_t pa, pa_next;
int seg;
size = round_page(size); size = round_page(size);
@ -1137,32 +1134,15 @@ mbus_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size,
*kvap = (caddr_t)va; *kvap = (caddr_t)va;
/* Map the allocated pages into the chunk. */ /* Map the allocated pages into the chunk. */
mlist = segs[0]._ds_mlist; pglist = segs[0]._ds_mlist;
pa_next = 0; TAILQ_FOREACH(pg, pglist, pageq) {
seg = -1; KASSERT(size != 0);
for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) { pa = VM_PAGE_TO_PHYS(pg);
pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE | PMAP_NC);
if (size == 0)
panic("mbus_dmamem_map: size botch");
pa = VM_PAGE_TO_PHYS(m);
if (pa != pa_next) {
if (++seg >= nsegs)
panic("mbus_dmamem_map: nsegs botch");
}
pa_next = pa + PAGE_SIZE;
pmap_kenter_pa(va, pa,
VM_PROT_READ|VM_PROT_WRITE);
#if notused
pmap_changebit(va, TLB_UNCACHEABLE, 0); /* XXX for now */
#endif
va += PAGE_SIZE; va += PAGE_SIZE;
size -= PAGE_SIZE; size -= PAGE_SIZE;
} }
pmap_update(); pmap_update();
return (0); return (0);
} }
@ -1407,4 +1387,3 @@ mbsubmatch(struct device *parent, struct cfdata *cf, void *aux)
ca->ca_irq = saved_irq; ca->ca_irq = saved_irq;
return ret; return ret;
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.11 2003/11/28 19:02:25 chs Exp $ */ /* $NetBSD: pmap.c,v 1.12 2004/01/05 02:25:32 chs Exp $ */
/*- /*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -171,7 +171,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.11 2003/11/28 19:02:25 chs Exp $"); __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.12 2004/01/05 02:25:32 chs Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -1826,6 +1826,7 @@ pmap_is_referenced(struct vm_page *pg)
void void
pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
{ {
u_int tlbprot;
int s; int s;
#ifdef PMAPDEBUG #ifdef PMAPDEBUG
int opmapdebug = pmapdebug; int opmapdebug = pmapdebug;
@ -1843,12 +1844,14 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
PMAP_PRINTF(PDB_KENTER, ("(%p, %p, %x)\n", PMAP_PRINTF(PDB_KENTER, ("(%p, %p, %x)\n",
(caddr_t)va, (caddr_t)pa, prot)); (caddr_t)va, (caddr_t)pa, prot));
va = hppa_trunc_page(va); va = hppa_trunc_page(va);
tlbprot = TLB_WIRED | TLB_UNMANAGED;
tlbprot |= (prot & PMAP_NC) ? TLB_UNCACHEABLE : 0;
tlbprot |= pmap_prot(pmap_kernel(), prot & VM_PROT_ALL);
s = splvm(); s = splvm();
KASSERT(pmap_pv_find_va(HPPA_SID_KERNEL, va) == NULL); KASSERT(pmap_pv_find_va(HPPA_SID_KERNEL, va) == NULL);
pmap_pv_enter(pmap_kernel(), HPPA_SID_KERNEL, va, pa, pmap_pv_enter(pmap_kernel(), HPPA_SID_KERNEL, va, pa, tlbprot);
pmap_prot(pmap_kernel(), prot) |
TLB_WIRED | TLB_UNMANAGED);
splx(s); splx(s);
#ifdef PMAPDEBUG #ifdef PMAPDEBUG
pmapdebug = opmapdebug; pmapdebug = opmapdebug;
#endif /* PMAPDEBUG */ #endif /* PMAPDEBUG */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.h,v 1.4 2003/08/31 01:26:37 chs Exp $ */ /* $NetBSD: pmap.h,v 1.5 2004/01/05 02:25:33 chs Exp $ */
/* $OpenBSD: pmap.h,v 1.14 2001/05/09 15:31:24 art Exp $ */ /* $OpenBSD: pmap.h,v 1.14 2001/05/09 15:31:24 art Exp $ */
@ -96,6 +96,9 @@ struct pmap {
extern pmap_t kernel_pmap; /* The kernel's map */ extern pmap_t kernel_pmap; /* The kernel's map */
#ifdef _KERNEL #ifdef _KERNEL
#define PMAP_NC 0x100
#define cache_align(x) (((x) + dcache_line_mask) & ~(dcache_line_mask)) #define cache_align(x) (((x) + dcache_line_mask) & ~(dcache_line_mask))
extern int dcache_line_mask; extern int dcache_line_mask;
@ -142,10 +145,11 @@ pmap_remove_all(struct pmap *pmap)
} }
static __inline int static __inline int
pmap_prot(struct pmap *pmap, int prot) pmap_prot(struct pmap *pmap, vm_prot_t prot)
{ {
extern u_int kern_prot[], user_prot[]; extern u_int kern_prot[], user_prot[];
return (pmap == kernel_pmap? kern_prot: user_prot)[prot];
return (pmap == kernel_pmap ? kern_prot : user_prot)[prot];
} }
#endif /* _KERNEL */ #endif /* _KERNEL */