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