Eliminate unnecessary TLB invalidations by pmap_enter(). Specifically,

eliminate TLB invalidations when permissions are relaxed, such as when a
read-only mapping is changed to a read/write mapping.  Additionally,
eliminate TLB invalidations when bits that are ignored by the hardware,
such as PG_W ("wired mapping"), are changed.

Reviewed by:	tegge
This commit is contained in:
alc 2005-09-04 19:06:27 +00:00
parent ea45d0596e
commit 9a159e7bd9
2 changed files with 45 additions and 32 deletions

View File

@ -1872,6 +1872,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
vm_paddr_t opa;
pt_entry_t origpte, newpte;
vm_page_t mpte, om;
boolean_t invlva;
va = trunc_page(va);
#ifdef PMAP_DIAGNOSTIC
@ -1935,14 +1936,6 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
else if (!wired && (origpte & PG_W))
pmap->pm_stats.wired_count--;
#if defined(PMAP_DIAGNOSTIC)
if (pmap_nw_modified((pt_entry_t) origpte)) {
printf(
"pmap_enter: modified page not writable: va: 0x%lx, pte: 0x%lx\n",
va, origpte);
}
#endif
/*
* Remove extra pte reference
*/
@ -2014,17 +2007,30 @@ validate:
* to update the pte.
*/
if ((origpte & ~(PG_M|PG_A)) != newpte) {
if (origpte & PG_MANAGED) {
if (origpte & PG_V) {
invlva = FALSE;
origpte = pte_load_store(pte, newpte | PG_A);
if ((origpte & PG_M) && pmap_track_modified(va))
vm_page_dirty(om);
if (origpte & PG_A)
vm_page_flag_set(om, PG_REFERENCED);
if (origpte & PG_A) {
if (origpte & PG_MANAGED)
vm_page_flag_set(om, PG_REFERENCED);
if (opa != VM_PAGE_TO_PHYS(m) || ((origpte &
PG_NX) == 0 && (newpte & PG_NX)))
invlva = TRUE;
}
if (origpte & PG_M) {
KASSERT((origpte & PG_RW),
("pmap_enter: modified page not writable:"
" va: 0x%lx, pte: 0x%lx", va, origpte));
if ((origpte & PG_MANAGED) &&
pmap_track_modified(va))
vm_page_dirty(om);
if ((newpte & PG_RW) == 0)
invlva = TRUE;
}
if (invlva)
pmap_invalidate_page(pmap, va);
} else
pte_store(pte, newpte | PG_A);
if (origpte) {
pmap_invalidate_page(pmap, va);
}
}
vm_page_unlock_queues();
PMAP_UNLOCK(pmap);

View File

@ -5,6 +5,8 @@
* All rights reserved.
* Copyright (c) 1994 David Greenman
* All rights reserved.
* Copyright (c) 2005 Alan L. Cox <alc@cs.rice.edu>
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
@ -1853,6 +1855,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
vm_paddr_t opa;
pt_entry_t origpte, newpte;
vm_page_t mpte, om;
boolean_t invlva;
va &= PG_FRAME;
#ifdef PMAP_DIAGNOSTIC
@ -1926,14 +1929,6 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
else if (!wired && (origpte & PG_W))
pmap->pm_stats.wired_count--;
#if defined(PMAP_DIAGNOSTIC)
if (pmap_nw_modified((pt_entry_t) origpte)) {
printf(
"pmap_enter: modified page not writable: va: 0x%x, pte: 0x%x\n",
va, origpte);
}
#endif
/*
* Remove extra pte reference
*/
@ -2003,17 +1998,29 @@ validate:
* to update the pte.
*/
if ((origpte & ~(PG_M|PG_A)) != newpte) {
if (origpte & PG_MANAGED) {
if (origpte & PG_V) {
invlva = FALSE;
origpte = pte_load_store(pte, newpte | PG_A);
if ((origpte & PG_M) && pmap_track_modified(va))
vm_page_dirty(om);
if (origpte & PG_A)
vm_page_flag_set(om, PG_REFERENCED);
if (origpte & PG_A) {
if (origpte & PG_MANAGED)
vm_page_flag_set(om, PG_REFERENCED);
if (opa != VM_PAGE_TO_PHYS(m))
invlva = TRUE;
}
if (origpte & PG_M) {
KASSERT((origpte & PG_RW),
("pmap_enter: modified page not writable:"
" va: 0x%x, pte: 0x%x", va, origpte));
if ((origpte & PG_MANAGED) &&
pmap_track_modified(va))
vm_page_dirty(om);
if ((prot & VM_PROT_WRITE) == 0)
invlva = TRUE;
}
if (invlva)
pmap_invalidate_page(pmap, va);
} else
pte_store(pte, newpte | PG_A);
if (origpte) {
pmap_invalidate_page(pmap, va);
}
}
sched_unpin();
vm_page_unlock_queues();