Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/alpha/alpha Implement pv_entry stealing for the cas...
details: https://anonhg.NetBSD.org/src/rev/22e9ccd126a2
branches: trunk
changeset: 473173:22e9ccd126a2
user: thorpej <thorpej%NetBSD.org@localhost>
date: Sun May 23 16:54:43 1999 +0000
description:
Implement pv_entry stealing for the case when a pool page cannot be
allocated for one.
diffstat:
sys/arch/alpha/alpha/pmap.c | 112 ++++++++++++++++++++++++++++++++++++-------
1 files changed, 94 insertions(+), 18 deletions(-)
diffs (235 lines):
diff -r d4a91e10400f -r 22e9ccd126a2 sys/arch/alpha/alpha/pmap.c
--- a/sys/arch/alpha/alpha/pmap.c Sun May 23 16:15:18 1999 +0000
+++ b/sys/arch/alpha/alpha/pmap.c Sun May 23 16:54:43 1999 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.95 1999/05/21 23:07:59 thorpej Exp $ */
+/* $NetBSD: pmap.c,v 1.96 1999/05/23 16:54:43 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@@ -155,7 +155,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.95 1999/05/21 23:07:59 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.96 1999/05/23 16:54:43 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -474,7 +474,7 @@
*/
void alpha_protection_init __P((void));
boolean_t pmap_remove_mapping __P((pmap_t, vaddr_t, pt_entry_t *,
- boolean_t, long));
+ boolean_t, long, struct pv_entry **));
void pmap_changebit __P((paddr_t, pt_entry_t, pt_entry_t, long));
#ifndef PMAP_NEW
/* It's an interface function if PMAP_NEW. */
@@ -497,7 +497,8 @@
* PV table management functions.
*/
void pmap_pv_enter __P((pmap_t, paddr_t, vaddr_t, boolean_t));
-void pmap_pv_remove __P((pmap_t, paddr_t, vaddr_t, boolean_t));
+void pmap_pv_remove __P((pmap_t, paddr_t, vaddr_t, boolean_t,
+ struct pv_entry **));
struct pv_entry *pmap_pv_alloc __P((void));
void pmap_pv_free __P((struct pv_entry *));
void *pmap_pv_page_alloc __P((u_long, int, int));
@@ -1307,7 +1308,7 @@
l3pte = pmap_l3pte(pmap, sva, l2pte);
if (pmap_pte_v(l3pte))
needisync |= pmap_remove_mapping(pmap, sva, l3pte,
- TRUE, cpu_id);
+ TRUE, cpu_id, NULL);
sva += PAGE_SIZE;
}
@@ -1407,7 +1408,7 @@
#endif
if (!pmap_pte_w(pte))
needisync |= pmap_remove_mapping(pv->pv_pmap,
- pv->pv_va, pte, FALSE, cpu_id);
+ pv->pv_va, pte, FALSE, cpu_id, NULL);
#ifdef DEBUG
else {
if (pmapdebug & PDB_PARANOIA) {
@@ -1714,7 +1715,7 @@
*/
pmap_physpage_addref(pte);
}
- needisync |= pmap_remove_mapping(pmap, va, pte, TRUE, cpu_id);
+ needisync |= pmap_remove_mapping(pmap, va, pte, TRUE, cpu_id, NULL);
validate_enterpv:
/*
@@ -1950,7 +1951,7 @@
pte = PMAP_KERNEL_PTE(va);
if (pmap_pte_v(pte))
needisync |= pmap_remove_mapping(pmap_kernel(), va,
- pte, TRUE, cpu_id);
+ pte, TRUE, cpu_id, NULL);
}
if (needisync)
@@ -2604,12 +2605,13 @@
* be synchronized.
*/
boolean_t
-pmap_remove_mapping(pmap, va, pte, dolock, cpu_id)
+pmap_remove_mapping(pmap, va, pte, dolock, cpu_id, pvp)
pmap_t pmap;
vaddr_t va;
pt_entry_t *pte;
boolean_t dolock;
long cpu_id;
+ struct pv_entry **pvp;
{
paddr_t pa;
int s;
@@ -2620,8 +2622,8 @@
#ifdef DEBUG
if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
- printf("pmap_remove_mapping(%p, %lx, %p, %d, %ld)\n",
- pmap, va, pte, dolock, cpu_id);
+ printf("pmap_remove_mapping(%p, %lx, %p, %d, %ld, %p)\n",
+ pmap, va, pte, dolock, cpu_id, pvp);
#endif
/*
@@ -2681,15 +2683,20 @@
/*
* If the mapping wasn't enterd on the PV list, we're all done.
*/
- if (onpv == FALSE)
+ if (onpv == FALSE) {
+#ifdef DIAGNOSTIC
+ if (pvp != NULL)
+ panic("pmap_removing_mapping: onpv / pvp inconsistent");
+#endif
return (needisync);
+ }
/*
* Otherwise remove it from the PV table
* (raise IPL since we may be called at interrupt time).
*/
s = splimp(); /* XXX needed w/ PMAP_NEW? */
- pmap_pv_remove(pmap, pa, va, dolock);
+ pmap_pv_remove(pmap, pa, va, dolock, pvp);
splx(s);
return (needisync);
@@ -3031,11 +3038,12 @@
* Remove a physical->virtual entry from the pv_table.
*/
void
-pmap_pv_remove(pmap, pa, va, dolock)
+pmap_pv_remove(pmap, pa, va, dolock, pvp)
pmap_t pmap;
paddr_t pa;
vaddr_t va;
boolean_t dolock;
+ struct pv_entry **pvp;
{
struct pv_head *pvh;
pv_entry_t pv;
@@ -3064,9 +3072,14 @@
simple_unlock(&pvh->pvh_slock);
/*
- * ...and free the pv_entry.
+ * If pvp is not NULL, this is pmap_pv_alloc() stealing an
+ * entry from another mapping, and we return the now unused
+ * entry in it. Otherwise, free the pv_entry.
*/
- pmap_pv_free(pv);
+ if (pvp != NULL)
+ *pvp = pv;
+ else
+ pmap_pv_free(pv);
}
/*
@@ -3077,16 +3090,79 @@
struct pv_entry *
pmap_pv_alloc()
{
+ struct pv_head *pvh;
struct pv_entry *pv;
+ int bank, npg, pg;
+ pt_entry_t *pte;
+ pmap_t pvpmap;
+ u_long cpu_id;
pv = pool_get(&pmap_pv_pool, PR_NOWAIT);
if (pv != NULL)
return (pv);
/*
- * XXX Should try to steal a pv_entry from another mapping.
+ * We were unable to allocate one from the pool. Try to
+ * steal one from another mapping. At this point we know that:
+ *
+ * (1) We have not locked the pv table, and we already have
+ * the map-to-head lock, so it is safe for us to do so here.
+ *
+ * (2) The pmap that wants this entry *is* locked. We must
+ * use simple_lock_try() to prevent deadlock from occurring.
+ *
+ * XXX Note that in case #2, there is an exception; it *is* safe to
+ * steal a mapping from the pmap that wants this entry! We may want
+ * to consider passing the pmap to this function so that we can take
+ * advantage of this.
*/
- panic("pmap_pv_alloc: unable to allocate a pv_entry");
+
+ /* XXX This search could probably be improved. */
+ for (bank = 0; bank < vm_nphysseg; bank++) {
+ npg = vm_physmem[bank].end - vm_physmem[bank].start;
+ for (pg = 0; pg < npg; pg++) {
+ pvh = &vm_physmem[bank].pmseg.pvhead[pg];
+ simple_lock(&pvh->pvh_slock);
+ for (pv = LIST_FIRST(&pvh->pvh_list);
+ pv != NULL; pv = LIST_NEXT(pv, pv_list)) {
+ pvpmap = pv->pv_pmap;
+
+ /* Don't steal from kernel pmap. */
+ if (pvpmap == pmap_kernel())
+ continue;
+
+ if (simple_lock_try(&pvpmap->pm_slock) == 0)
+ continue;
+
+ pte = pmap_l3pte(pvpmap, pv->pv_va, NULL);
+
+ /* Don't steal wired mappings. */
+ if (pmap_pte_w(pte)) {
+ simple_unlock(&pvpmap->pm_slock);
+ continue;
+ }
+
+ cpu_id = alpha_pal_whami();
+
+ /*
+ * Okay! We have a mapping we can steal;
+ * remove it and grab the pv_entry.
+ */
+ if (pmap_remove_mapping(pvpmap, pv->pv_va,
+ pte, FALSE, cpu_id, &pv))
+ alpha_pal_imb();
+
+ /* Unlock everything and return. */
+ simple_unlock(&pvpmap->pm_slock);
+ simple_unlock(&pvh->pvh_slock);
+ return (pv);
+ }
+ simple_unlock(&pvh->pvh_slock);
+ }
+ }
+
+ /* Nothing else we can do. */
+ panic("pmap_pv_alloc: unable to allocate or steal pv_entry");
}
/*
Home |
Main Index |
Thread Index |
Old Index