Module Name: src
Committed By: msaitoh
Date: Wed Jun 11 15:38:05 UTC 2014
Modified Files:
src/sys/arch/mips/include [netbsd-6]: pmap.h
src/sys/arch/mips/mips [netbsd-6]: pmap.c pmap_segtab.c
Log Message:
Pull up following revision(s) (requested by skrll in ticket #1068):
sys/arch/mips/mips/pmap.c: revision 1.214
sys/arch/mips/include/pmap.h: revision 1.63
sys/arch/mips/mips/pmap_segtab.c: revision 1.8
Deal with incompatible cache aliases. Specifically,
- always flush an ephemeral page on unmap
- track unmanaged mappings (mappings entered via pmap_kenter_pa) for
aliases where required and handle appropriately (via pmap_enter_pv)
Hopefully this (finally) addresses the instability reported in the
following PRs:
PR/44900 - R5000/Rm5200 mips ports are broken
PR/46890 - upcoming NetBSD 6.0 release is very unstable/unusable on cobalt qube2
PR/48628 - cobalt and hpcmips ports are dead
To generate a diff of this commit:
cvs rdiff -u -r1.61.8.1 -r1.61.8.2 src/sys/arch/mips/include/pmap.h
cvs rdiff -u -r1.207.2.2 -r1.207.2.3 src/sys/arch/mips/mips/pmap.c
cvs rdiff -u -r1.4.2.1 -r1.4.2.2 src/sys/arch/mips/mips/pmap_segtab.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/mips/include/pmap.h
diff -u src/sys/arch/mips/include/pmap.h:1.61.8.1 src/sys/arch/mips/include/pmap.h:1.61.8.2
--- src/sys/arch/mips/include/pmap.h:1.61.8.1 Thu Jul 5 18:39:42 2012
+++ src/sys/arch/mips/include/pmap.h Wed Jun 11 15:38:04 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.61.8.1 2012/07/05 18:39:42 riz Exp $ */
+/* $NetBSD: pmap.h,v 1.61.8.2 2014/06/11 15:38:04 msaitoh Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -283,6 +283,7 @@ void pmap_prefer(vaddr_t, vaddr_t *, vsi
#endif /* MIPS3_PLUS */
#define PMAP_STEAL_MEMORY /* enable pmap_steal_memory() */
+#define PMAP_ENABLE_PMAP_KMPAGE /* enable the PMAP_KMPAGE flag */
/*
* Alternate mapping hooks for pool pages. Avoids thrashing the TLB.
@@ -329,6 +330,7 @@ typedef struct pv_entry {
struct pv_entry *pv_next; /* next pv_entry */
struct pmap *pv_pmap; /* pmap where mapping lies */
vaddr_t pv_va; /* virtual address for mapping */
+#define PV_KENTER 0x001
} *pv_entry_t;
#define PG_MD_UNCACHED 0x0001 /* page is mapped uncached */
Index: src/sys/arch/mips/mips/pmap.c
diff -u src/sys/arch/mips/mips/pmap.c:1.207.2.2 src/sys/arch/mips/mips/pmap.c:1.207.2.3
--- src/sys/arch/mips/mips/pmap.c:1.207.2.2 Wed May 21 20:39:17 2014
+++ src/sys/arch/mips/mips/pmap.c Wed Jun 11 15:38:05 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.207.2.2 2014/05/21 20:39:17 bouyer Exp $ */
+/* $NetBSD: pmap.c,v 1.207.2.3 2014/06/11 15:38:05 msaitoh Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.207.2.2 2014/05/21 20:39:17 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.207.2.3 2014/06/11 15:38:05 msaitoh Exp $");
/*
* Manages physical address maps.
@@ -317,7 +317,7 @@ u_int pmap_page_colormask;
/* Forward function declarations */
void pmap_remove_pv(pmap_t, vaddr_t, struct vm_page *, bool);
-void pmap_enter_pv(pmap_t, vaddr_t, struct vm_page *, u_int *);
+void pmap_enter_pv(pmap_t, vaddr_t, struct vm_page *, u_int *, int);
pt_entry_t *pmap_pte(pmap_t, vaddr_t);
/*
@@ -386,13 +386,13 @@ pmap_page_syncicache(struct vm_page *pg)
}
PG_MD_PVLIST_UNLOCK(md);
kpreempt_disable();
- pmap_tlb_syncicache(md->pvh_first.pv_va, onproc);
+ pmap_tlb_syncicache(trunc_page(md->pvh_first.pv_va), onproc);
kpreempt_enable();
#else
if (MIPS_HAS_R4K_MMU) {
if (PG_MD_CACHED_P(md)) {
mips_icache_sync_range_index(
- md->pvh_first.pv_va, PAGE_SIZE);
+ trunc_page(md->pvh_first.pv_va), PAGE_SIZE);
}
} else {
mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(pg)),
@@ -436,10 +436,10 @@ pmap_map_ephemeral_page(struct vm_page *
*/
(void)PG_MD_PVLIST_LOCK(md, false);
if (PG_MD_CACHED_P(md)
- && mips_cache_badalias(pv->pv_va, va))
- mips_dcache_wbinv_range_index(pv->pv_va, PAGE_SIZE);
- if (pv->pv_pmap == NULL)
- pv->pv_va = va;
+ && mips_cache_badalias(pv->pv_va, va)) {
+ mips_dcache_wbinv_range_index(trunc_page(pv->pv_va),
+ PAGE_SIZE);
+ }
PG_MD_PVLIST_UNLOCK(md);
}
@@ -450,23 +450,13 @@ static void
pmap_unmap_ephemeral_page(struct vm_page *pg, vaddr_t va,
pt_entry_t old_pt_entry)
{
- struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
- pv_entry_t pv = &md->pvh_first;
-
- if (MIPS_CACHE_VIRTUAL_ALIAS) {
- (void)PG_MD_PVLIST_LOCK(md, false);
- if (PG_MD_CACHED_P(md)
- || (pv->pv_pmap != NULL
- && mips_cache_badalias(pv->pv_va, va))) {
- /*
- * If this page was previously cached or we had to use an
- * incompatible alias and it has a valid mapping, flush it
- * from the cache.
- */
- mips_dcache_wbinv_range(va, PAGE_SIZE);
- }
- PG_MD_PVLIST_UNLOCK(md);
+ if (MIPS_CACHE_VIRTUAL_ALIAS) {
+ /*
+ * Flush the page to avoid future incompatible aliases
+ */
+ KASSERT((va & PAGE_MASK) == 0);
+ mips_dcache_wbinv_range(va, PAGE_SIZE);
}
#ifndef _LP64
/*
@@ -1073,7 +1063,7 @@ pmap_page_protect(struct vm_page *pg, vm
while (pv != NULL) {
const pmap_t pmap = pv->pv_pmap;
const uint16_t gen = PG_MD_PVLIST_GEN(md);
- va = pv->pv_va;
+ va = trunc_page(pv->pv_va);
PG_MD_PVLIST_UNLOCK(md);
pmap_protect(pmap, va, va + PAGE_SIZE, prot);
KASSERT(pv->pv_pmap == pmap);
@@ -1101,7 +1091,7 @@ pmap_page_protect(struct vm_page *pg, vm
pv = &md->pvh_first;
while (pv->pv_pmap != NULL) {
const pmap_t pmap = pv->pv_pmap;
- va = pv->pv_va;
+ va = trunc_page(pv->pv_va);
PG_MD_PVLIST_UNLOCK(md);
pmap_remove(pmap, va, va + PAGE_SIZE);
pmap_update(pmap);
@@ -1118,6 +1108,9 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv
const uint32_t pg_mask = ~(mips_pg_m_bit() | mips_pg_ro_bit());
const uint32_t p = (flags & VM_PROT_WRITE) ? mips_pg_rw_bit() : mips_pg_ro_bit();
KASSERT(kpreempt_disabled());
+ KASSERT((sva & PAGE_MASK) == 0);
+ KASSERT((eva & PAGE_MASK) == 0);
+
/*
* Change protection on every valid mapping within this segment.
*/
@@ -1162,6 +1155,8 @@ pmap_protect(pmap_t pmap, vaddr_t sva, v
pt_entry_t *pte;
u_int p;
+ KASSERT((sva & PAGE_MASK) == 0);
+ KASSERT((eva & PAGE_MASK) == 0);
PMAP_COUNT(protect);
#ifdef DEBUG
if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
@@ -1315,7 +1310,7 @@ pmap_page_cache(struct vm_page *pg, bool
pv != NULL;
pv = pv->pv_next) {
pmap_t pmap = pv->pv_pmap;
- vaddr_t va = pv->pv_va;
+ vaddr_t va = trunc_page(pv->pv_va);
pt_entry_t *pte;
uint32_t pt_entry;
@@ -1493,6 +1488,7 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
PMAP_COUNT(enter_exec_mapping);
if (!PG_MD_EXECPAGE_P(md)) {
+ KASSERT((pa & PAGE_MASK) == 0);
mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(pa),
PAGE_SIZE);
pmap_set_mdpage_attributes(md, PG_MD_EXECPAGE);
@@ -1505,7 +1501,7 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
kpreempt_disable();
if (pmap == pmap_kernel()) {
if (pg)
- pmap_enter_pv(pmap, va, pg, &npte);
+ pmap_enter_pv(pmap, va, pg, &npte, 0);
/* enter entries into kernel pmap */
pte = kvtopte(va);
@@ -1546,7 +1542,7 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd
/* Done after case that may sleep/return. */
if (pg)
- pmap_enter_pv(pmap, va, pg, &npte);
+ pmap_enter_pv(pmap, va, pg, &npte, 0);
/*
* Now validate mapping with desired protection/wiring.
@@ -1663,6 +1659,17 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v
kpreempt_disable();
pte = kvtopte(va);
KASSERT(!mips_pg_v(pte->pt_entry));
+
+ /*
+ * No need to track non-managed pages or PMAP_KMPAGEs pages for aliases
+ */
+ if (managed && (flags & PMAP_KMPAGE) == 0) {
+ pmap_t pmap = pmap_kernel();
+ struct vm_page *pg = PHYS_TO_VM_PAGE(pa);
+
+ pmap_enter_pv(pmap, va, pg, &npte, PV_KENTER);
+ }
+
pte->pt_entry = npte;
pmap_tlb_update_addr(pmap_kernel(), va, npte, false);
kpreempt_enable();
@@ -1688,23 +1695,10 @@ pmap_kremove(vaddr_t va, vsize_t len)
}
PMAP_COUNT(kremove_pages);
- if (MIPS_HAS_R4K_MMU && MIPS_CACHE_VIRTUAL_ALIAS) {
- struct vm_page * const pg =
- PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(pt_entry));
- if (pg != NULL) {
- struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
- (void)PG_MD_PVLIST_LOCK(md, false);
- pv_entry_t pv = &md->pvh_first;
- if (pv->pv_pmap == NULL) {
- pv->pv_va = va;
- } else if (PG_MD_CACHED_P(md)
- && mips_cache_badalias(pv->pv_va, va)) {
- mips_dcache_wbinv_range(va, PAGE_SIZE);
- }
- PG_MD_PVLIST_UNLOCK(md);
- }
- }
-
+ struct vm_page * const pg =
+ PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(pt_entry));
+ if (pg)
+ pmap_remove_pv(pmap_kernel(), va, pg, false);
pte->pt_entry = new_pt_entry;
pmap_tlb_invalidate_addr(pmap_kernel(), va);
}
@@ -2001,10 +1995,13 @@ pmap_clear_modify(struct vm_page *pg)
gen = PG_MD_PVLIST_LOCK(md, false);
for (; pv != NULL; pv = pv_next) {
pmap_t pmap = pv->pv_pmap;
- vaddr_t va = pv->pv_va;
+ vaddr_t va = trunc_page(pv->pv_va);
pt_entry_t *pte;
uint32_t pt_entry;
+
pv_next = pv->pv_next;
+ if (pv->pv_va & PV_KENTER)
+ continue;
if (pmap == pmap_kernel()) {
pte = kvtopte(va);
} else {
@@ -2083,8 +2080,13 @@ pmap_check_pvlist(struct vm_page_md *md)
#ifdef _LP64
KASSERT(!MIPS_XKPHYS_P(pv->pv_va));
#endif
+ pv_entry_t opv = &md->pvh_first;
+ for (; opv != NULL; opv = opv->pv_next) {
+ if (mips_cache_badalias(pv->pv_va, opv->pv_va)) {
+ KASSERT(PG_MD_UNCACHED_P(md));
+ }
+ }
}
- pv = &md->pvh_first;
}
#endif /* PARANOIADIAG */
}
@@ -2094,7 +2096,8 @@ pmap_check_pvlist(struct vm_page_md *md)
* physical to virtual map table.
*/
void
-pmap_enter_pv(pmap_t pmap, vaddr_t va, struct vm_page *pg, u_int *npte)
+pmap_enter_pv(pmap_t pmap, vaddr_t va, struct vm_page *pg, u_int *npte,
+ int flags)
{
struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
pv_entry_t pv, npv, apv;
@@ -2133,7 +2136,7 @@ again:
PMAP_COUNT(mappings);
pmap_clear_mdpage_attributes(md, PG_MD_UNCACHED);
pv->pv_pmap = pmap;
- pv->pv_va = va;
+ pv->pv_va = va | flags;
} else {
#if defined(MIPS3_PLUS) && !defined(MULTIPROCESSOR) /* XXX mmu XXX */
if (MIPS_CACHE_VIRTUAL_ALIAS) {
@@ -2154,8 +2157,9 @@ again:
if (mips_cache_badalias(pv->pv_va, va)) {
for (npv = pv; npv; npv = npv->pv_next) {
- pmap_remove(npv->pv_pmap, npv->pv_va,
- npv->pv_va + PAGE_SIZE);
+ vaddr_t nva = trunc_page(npv->pv_va);
+ pmap_remove(npv->pv_pmap, nva,
+ nva + PAGE_SIZE);
pmap_update(npv->pv_pmap);
goto again;
}
@@ -2174,9 +2178,10 @@ again:
* share the same cache index again.
*/
if (mips_cache_badalias(pv->pv_va, va)) {
+ vaddr_t nva = trunc_page(pv->pv_va);
pmap_page_cache(pg, false);
- mips_dcache_wbinv_range_index(
- pv->pv_va, PAGE_SIZE);
+ mips_dcache_wbinv_range_index(nva,
+ PAGE_SIZE);
*npte = (*npte &
~MIPS3_PG_CACHEMODE) |
MIPS3_PG_UNCACHED;
@@ -2200,7 +2205,8 @@ again:
*/
for (npv = pv; npv; npv = npv->pv_next) {
- if (pmap == npv->pv_pmap && va == npv->pv_va) {
+ if (pmap == npv->pv_pmap &&
+ va == trunc_page(npv->pv_va)) {
#ifdef PARANOIADIAG
pt_entry_t *pte;
uint32_t pt_entry;
@@ -2264,7 +2270,7 @@ again:
}
npv = apv;
apv = NULL;
- npv->pv_va = va;
+ npv->pv_va = va | flags;
npv->pv_pmap = pmap;
npv->pv_next = pv->pv_next;
pv->pv_next = npv;
@@ -2296,6 +2302,7 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va,
VM_PAGE_TO_PHYS(pg));
#endif
KASSERT(kpreempt_disabled());
+ KASSERT((va & PAGE_MASK) == 0);
pv = &md->pvh_first;
(void)PG_MD_PVLIST_LOCK(md, true);
@@ -2309,13 +2316,12 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va,
*/
last = false;
- if (pmap == pv->pv_pmap && va == pv->pv_va) {
+ if (pmap == pv->pv_pmap && va == trunc_page(pv->pv_va)) {
npv = pv->pv_next;
if (npv) {
*pv = *npv;
KASSERT(pv->pv_pmap != NULL);
} else {
- pmap_clear_mdpage_attributes(md, PG_MD_UNCACHED);
pv->pv_pmap = NULL;
last = true; /* Last mapping removed */
}
@@ -2323,7 +2329,8 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va,
} else {
for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) {
PMAP_COUNT(remove_pvsearch);
- if (pmap == npv->pv_pmap && va == npv->pv_va)
+ if (pmap == npv->pv_pmap &&
+ va == trunc_page(npv->pv_va))
break;
}
if (npv) {
@@ -2338,11 +2345,13 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va,
* removed. If it was, then reenable caching.
*/
pv = &md->pvh_first;
- for (pv_entry_t pv0 = pv->pv_next; pv0; pv0 = pv0->pv_next) {
+ pv_entry_t pv0 = pv->pv_next;
+
+ for (; pv0; pv0 = pv0->pv_next) {
if (mips_cache_badalias(pv->pv_va, pv0->pv_va))
break;
}
- if (npv == NULL)
+ if (pv0 == NULL)
pmap_page_cache(pg, true);
}
#endif
@@ -2496,8 +2505,10 @@ pmap_pv_page_free(struct pool *pp, void
pa = MIPS_KSEG0_TO_PHYS(va);
#endif
#ifdef MIPS3_PLUS
- if (MIPS_CACHE_VIRTUAL_ALIAS)
+ if (MIPS_CACHE_VIRTUAL_ALIAS) {
+ KASSERT((va & PAGE_MASK) == 0);
mips_dcache_inv_range(va, PAGE_SIZE);
+ }
#endif
struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
KASSERT(pg != NULL);
@@ -2622,7 +2633,7 @@ mips_pmap_map_poolpage(paddr_t pa)
*/
(void)PG_MD_PVLIST_LOCK(md, false);
pv_entry_t pv = &md->pvh_first;
- vaddr_t last_va = pv->pv_va;
+ vaddr_t last_va = trunc_page(pv->pv_va);
KASSERT(pv->pv_pmap == NULL);
pv->pv_va = va;
if (PG_MD_CACHED_P(md) && mips_cache_badalias(last_va, va))
@@ -2655,6 +2666,8 @@ mips_pmap_unmap_poolpage(vaddr_t va)
/*
* We've unmapped a poolpage. Its contents are irrelevant.
*/
+
+ KASSERT((va & PAGE_MASK) == 0);
mips_dcache_inv_range(va, PAGE_SIZE);
}
#endif
Index: src/sys/arch/mips/mips/pmap_segtab.c
diff -u src/sys/arch/mips/mips/pmap_segtab.c:1.4.2.1 src/sys/arch/mips/mips/pmap_segtab.c:1.4.2.2
--- src/sys/arch/mips/mips/pmap_segtab.c:1.4.2.1 Thu Jul 5 18:39:42 2012
+++ src/sys/arch/mips/mips/pmap_segtab.c Wed Jun 11 15:38:05 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap_segtab.c,v 1.4.2.1 2012/07/05 18:39:42 riz Exp $ */
+/* $NetBSD: pmap_segtab.c,v 1.4.2.2 2014/06/11 15:38:05 msaitoh Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.4.2.1 2012/07/05 18:39:42 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.4.2.2 2014/06/11 15:38:05 msaitoh Exp $");
/*
* Manages physical address maps.
@@ -217,18 +217,7 @@ pmap_segtab_release(union segtab *stp, u
}
#endif
-#ifdef MIPS3_PLUS /* XXX mmu XXX */
- /*
- * The pica pmap.c flushed the segmap pages here. I'm
- * not sure why, but I suspect it's because the page(s)
- * were being accessed by KSEG0 (cached) addresses and
- * may cause cache coherency problems when the page
- * is reused with KSEG2 (mapped) addresses. This may
- * cause problems on machines without VCED/VCEI.
- */
- if (MIPS_CACHE_VIRTUAL_ALIAS)
- mips_dcache_inv_range((vaddr_t)pte, PAGE_SIZE);
-#endif /* MIPS3_PLUS */
+ /* No need to flush page here as unmap poolpage does it */
#ifdef _LP64
KASSERT(MIPS_XKPHYS_P(pte));
#endif