Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 7 Oct 2012 18:07:45 +0000 (UTC)
From:      Alan Cox <alc@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r241313 - head/sys/mips/mips
Message-ID:  <201210071807.q97I7jCM044927@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alc
Date: Sun Oct  7 18:07:45 2012
New Revision: 241313
URL: http://svn.freebsd.org/changeset/base/241313

Log:
  Optimize the TLB invalidations performed by pmap_protect().  Use the new
  range-based invalidation function instead of performing per-page
  invalidations.  Don't bother invalidating mappings that don't have PTE_D
  set, since they don't allow write access.

Modified:
  head/sys/mips/mips/pmap.c

Modified: head/sys/mips/mips/pmap.c
==============================================================================
--- head/sys/mips/mips/pmap.c	Sun Oct  7 17:48:38 2012	(r241312)
+++ head/sys/mips/mips/pmap.c	Sun Oct  7 18:07:45 2012	(r241313)
@@ -1913,9 +1913,11 @@ pmap_remove_all(vm_page_t m)
 void
 pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
 {
-	pt_entry_t *pte;
+	pt_entry_t pbits, *pte;
 	pd_entry_t *pde, *pdpe;
-	vm_offset_t va_next;
+	vm_offset_t va, va_next;
+	vm_paddr_t pa;
+	vm_page_t m;
 
 	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
 		pmap_remove(pmap, sva, eva);
@@ -1927,10 +1929,6 @@ pmap_protect(pmap_t pmap, vm_offset_t sv
 	rw_wlock(&pvh_global_lock);
 	PMAP_LOCK(pmap);
 	for (; sva < eva; sva = va_next) {
-		pt_entry_t pbits;
-		vm_page_t m;
-		vm_paddr_t pa;
-
 		pdpe = pmap_segmap(pmap, sva);
 #ifdef __mips_n64
 		if (*pdpe == 0) {
@@ -1947,29 +1945,52 @@ pmap_protect(pmap_t pmap, vm_offset_t sv
 		pde = pmap_pdpe_to_pde(pdpe, sva);
 		if (*pde == NULL)
 			continue;
+
+		/*
+		 * Limit our scan to either the end of the va represented
+		 * by the current page table page, or to the end of the
+		 * range being write protected.
+		 */
 		if (va_next > eva)
 			va_next = eva;
 
+		va = va_next;
 		for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++,
-		     sva += PAGE_SIZE) {
-
-			/* Skip invalid PTEs */
-			if (!pte_test(pte, PTE_V))
-				continue;
+		    sva += PAGE_SIZE) {
 			pbits = *pte;
-			if (pte_test(&pbits, PTE_MANAGED | PTE_D)) {
-				pa = TLBLO_PTE_TO_PA(pbits);
-				m = PHYS_TO_VM_PAGE(pa);
-				vm_page_dirty(m);
+			if (!pte_test(&pbits, PTE_V) || pte_test(&pbits,
+			    PTE_RO)) {
+				if (va != va_next) {
+					pmap_invalidate_range(pmap, va, sva);
+					va = va_next;
+				}
+				continue;
 			}
-			pte_clear(&pbits, PTE_D);
 			pte_set(&pbits, PTE_RO);
-			
-			if (pbits != *pte) {
-				*pte = pbits;
-				pmap_update_page(pmap, sva, pbits);
+			if (pte_test(&pbits, PTE_D)) {
+				pte_clear(&pbits, PTE_D);
+				if (pte_test(&pbits, PTE_MANAGED)) {
+					pa = TLBLO_PTE_TO_PA(pbits);
+					m = PHYS_TO_VM_PAGE(pa);
+					vm_page_dirty(m);
+				}
+				if (va == va_next)
+					va = sva;
+			} else {
+				/*
+				 * Unless PTE_D is set, any TLB entries
+				 * mapping "sva" don't allow write access, so
+				 * they needn't be invalidated.
+				 */
+				if (va != va_next) {
+					pmap_invalidate_range(pmap, va, sva);
+					va = va_next;
+				}
 			}
+			*pte = pbits;
 		}
+		if (va != va_next)
+			pmap_invalidate_range(pmap, va, sva);
 	}
 	rw_wunlock(&pvh_global_lock);
 	PMAP_UNLOCK(pmap);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210071807.q97I7jCM044927>