Module Name:    src
Committed By:   ryo
Date:           Wed Feb  6 05:33:41 UTC 2019

Modified Files:
        src/sys/arch/aarch64/aarch64: pmap.c
        src/sys/arch/aarch64/include: pmap.h

Log Message:
improve pmap_remove
- don't lock/unlock per page in pmap_remove()
- speedup pte lookup for continuous addresses
- bring out pool_cache_put(&_pmap_pv_pool, pv) from lock/unlock section


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/sys/arch/aarch64/aarch64/pmap.c
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/aarch64/include/pmap.h

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/aarch64/aarch64/pmap.c
diff -u src/sys/arch/aarch64/aarch64/pmap.c:1.34 src/sys/arch/aarch64/aarch64/pmap.c:1.35
--- src/sys/arch/aarch64/aarch64/pmap.c:1.34	Fri Dec 21 08:01:01 2018
+++ src/sys/arch/aarch64/aarch64/pmap.c	Wed Feb  6 05:33:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.34 2018/12/21 08:01:01 ryo Exp $	*/
+/*	$NetBSD: pmap.c,v 1.35 2019/02/06 05:33:41 ryo Exp $	*/
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.34 2018/12/21 08:01:01 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.35 2019/02/06 05:33:41 ryo Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_ddb.h"
@@ -187,12 +187,15 @@ struct pv_entry {
 	paddr_t pv_pa;		/* debug */
 	pt_entry_t *pv_ptep;	/* for fast pte lookup */
 };
+#define pv_next	pv_link.tqe_next
+
+#define L3INDEXMASK	(L3_SIZE * Ln_ENTRIES - 1)
 
 static pt_entry_t *_pmap_pte_lookup_l3(struct pmap *, vaddr_t);
 static pt_entry_t *_pmap_pte_lookup_bs(struct pmap *, vaddr_t, vsize_t *);
 static pt_entry_t _pmap_pte_adjust_prot(pt_entry_t, vm_prot_t, vm_prot_t, bool);
 static pt_entry_t _pmap_pte_adjust_cacheflags(pt_entry_t, u_int);
-static void _pmap_remove(struct pmap *, vaddr_t, bool);
+static void _pmap_remove(struct pmap *, vaddr_t, vaddr_t, bool, struct pv_entry **);
 static int _pmap_enter(struct pmap *, vaddr_t, paddr_t, vm_prot_t, u_int, bool);
 
 static struct pmap kernel_pmap;
@@ -614,7 +617,7 @@ pmap_extract_coherency(struct pmap *pm, 
 bool
 pmap_extract(struct pmap *pm, vaddr_t va, paddr_t *pap)
 {
-	static pt_entry_t *ptep;
+	static pt_entry_t *ptep, pte;
 	paddr_t pa;
 	vsize_t blocksize = 0;
 	extern char __kernel_text[];
@@ -630,7 +633,10 @@ pmap_extract(struct pmap *pm, vaddr_t va
 		ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
 		if (ptep == NULL)
 			return false;
-		pa = lxpde_pa(*ptep) + (va & (blocksize - 1));
+		pte = *ptep;
+		if (!lxpde_valid(pte))
+			return false;
+		pa = lxpde_pa(pte) + (va & (blocksize - 1));
 	}
 
 	if (pap != NULL)
@@ -676,46 +682,30 @@ _pmap_pte_lookup_bs(struct pmap *pm, vad
 	blocksize = L0_SIZE;
 	l0 = pm->pm_l0table;
 	idx = l0pde_index(va);
-	pde = l0[idx];
-	if (!l0pde_valid(pde)) {
-		ptep = NULL;
+	ptep = &l0[idx];
+	pde = *ptep;
+	if (!l0pde_valid(pde))
 		goto done;
-	}
 
 	blocksize = L1_SIZE;
 	l1 = (pd_entry_t *)AARCH64_PA_TO_KVA(l0pde_pa(pde));
 	idx = l1pde_index(va);
-	pde = l1[idx];
-	if (!l1pde_valid(pde)) {
-		ptep = NULL;
-		goto done;
-	}
-	if (l1pde_is_block(pde)) {
-		ptep = &l1[idx];
+	ptep = &l1[idx];
+	pde = *ptep;
+	if (!l1pde_valid(pde) || l1pde_is_block(pde))
 		goto done;
-	}
 
 	blocksize = L2_SIZE;
 	l2 = (pd_entry_t *)AARCH64_PA_TO_KVA(l1pde_pa(pde));
 	idx = l2pde_index(va);
-	pde = l2[idx];
-	if (!l2pde_valid(pde)) {
-		ptep = NULL;
-		goto done;
-	}
-	if (l2pde_is_block(pde)) {
-		ptep = &l2[idx];
+	ptep = &l2[idx];
+	pde = *ptep;
+	if (!l2pde_valid(pde) || l2pde_is_block(pde))
 		goto done;
-	}
 
 	blocksize = L3_SIZE;
 	l3 = (pd_entry_t *)AARCH64_PA_TO_KVA(l2pde_pa(pde));
 	idx = l3pte_index(va);
-	pde = l3[idx];
-	if (!l3pte_valid(pde)) {
-		ptep = NULL;
-		goto done;
-	}
 	ptep = &l3[idx];
 
  done:
@@ -740,21 +730,27 @@ _pmap_pte_lookup_l3(struct pmap *pm, vad
 void
 pmap_icache_sync_range(pmap_t pm, vaddr_t sva, vaddr_t eva)
 {
-	pt_entry_t *ptep, pte;
+	pt_entry_t *ptep = NULL, pte;
 	vaddr_t va;
 	vsize_t blocksize = 0;
 
 	pm_lock(pm);
 
-	for (va = sva; va < eva; va += blocksize) {
-		ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
-		if (blocksize == 0)
-			break;
-		if (ptep != NULL) {
+	for (va = sva; va < eva; va = (va + blocksize) & ~(blocksize - 1)) {
+		/* va is belong to the same L3 table as before? */
+		if ((blocksize == L3_SIZE) && ((va & L3INDEXMASK) != 0)) {
+			ptep++;
+		} else {
+			ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
+			if (ptep == NULL)
+				break;
+		}
+
+		pte = *ptep;
+		if (lxpde_valid(pte)) {
 			vaddr_t eob = (va + blocksize) & ~(blocksize - 1);
 			vsize_t len = ulmin(eva, eob - va);
 
-			pte = *ptep;
 			if (l3pte_writable(pte)) {
 				cpu_icache_sync_range(va, len);
 			} else {
@@ -771,7 +767,6 @@ pmap_icache_sync_range(pmap_t pm, vaddr_
 				atomic_swap_64(ptep, opte);
 				AARCH64_TLBI_BY_ASID_VA(pm->pm_asid, va, true);
 			}
-			va &= ~(blocksize - 1);
 		}
 	}
 
@@ -826,7 +821,7 @@ _pmap_pte_adjust_prot(pt_entry_t pte, vm
 	/* and either to executable */
 	xn = user ? LX_BLKPAG_UXN : LX_BLKPAG_PXN;
 	if (prot & VM_PROT_EXECUTE)
-		pte &= ~xn;			
+		pte &= ~xn;
 
 	return pte;
 }
@@ -942,20 +937,22 @@ pv_dump(struct vm_page_md *md, void (*pr
 	TAILQ_FOREACH(pv, &md->mdpg_pvhead, pv_link) {
 		pr("  pv[%d] pv=%p\n",
 		    i, pv);
-		pr("    pv[%d].pv_pmap =%p (asid=%d)\n",
+		pr("    pv[%d].pv_pmap = %p (asid=%d)\n",
 		    i, pv->pv_pmap, pv->pv_pmap->pm_asid);
-		pr("    pv[%d].pv_va   =%016lx (color=%d)\n",
+		pr("    pv[%d].pv_va   = %016lx (color=%d)\n",
 		    i, pv->pv_va, _pmap_color(pv->pv_va));
-		pr("    pv[%d].pv_pa   =%016lx (color=%d)\n",
+		pr("    pv[%d].pv_pa   = %016lx (color=%d)\n",
 		    i, pv->pv_pa, _pmap_color(pv->pv_pa));
+		pr("    pv[%d].pv_ptep = %p\n",
+		    i, pv->pv_ptep);
 		i++;
 	}
 }
 #endif /* PMAP_PV_DEBUG & DDB */
 
 static int
-_pmap_enter_pv(struct vm_page *pg, struct pmap *pm, struct pv_entry **pvp, vaddr_t va,
-    pt_entry_t *ptep, paddr_t pa, u_int flags)
+_pmap_enter_pv(struct vm_page *pg, struct pmap *pm, struct pv_entry **pvp,
+    vaddr_t va, pt_entry_t *ptep, paddr_t pa, u_int flags)
 {
 	struct vm_page_md *md;
 	struct pv_entry *pv;
@@ -1006,6 +1003,7 @@ _pmap_enter_pv(struct vm_page *pg, struc
 		}
 #endif
 	}
+
 	pmap_pv_unlock(md);
 	return 0;
 }
@@ -1024,7 +1022,6 @@ void
 pmap_kremove(vaddr_t va, vsize_t size)
 {
 	struct pmap *kpm = pmap_kernel();
-	vaddr_t eva;
 	int s;
 
 	UVMHIST_FUNC(__func__);
@@ -1036,14 +1033,12 @@ pmap_kremove(vaddr_t va, vsize_t size)
 	KDASSERT((size & PGOFSET) == 0);
 
 	KDASSERT(!IN_KSEG_ADDR(va));
-
-	eva = va + size;
 	KDASSERT(IN_RANGE(va, VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS));
 
 	s = splvm();
-	for (; va < eva; va += PAGE_SIZE) {
-		_pmap_remove(kpm, va, true);
-	}
+	pm_lock(kpm);
+	_pmap_remove(kpm, va, va + size, true, NULL);
+	pm_unlock(kpm);
 	splx(s);
 }
 
@@ -1089,7 +1084,9 @@ _pmap_protect_pv(struct vm_page *pg, str
 void
 pmap_protect(struct pmap *pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
 {
+	pt_entry_t *ptep = NULL, pte;
 	vaddr_t va;
+	vsize_t blocksize = 0;
 	const bool user = (pm != pmap_kernel());
 
 	KASSERT((prot & VM_PROT_READ) || !(prot & VM_PROT_WRITE));
@@ -1115,8 +1112,7 @@ pmap_protect(struct pmap *pm, vaddr_t sv
 
 	pm_lock(pm);
 
-	for (va = sva; va < eva; va += PAGE_SIZE) {
-		pt_entry_t *ptep, pte;
+	for (va = sva; va < eva; va = (va + blocksize) & ~(blocksize - 1)) {
 #ifdef UVMHIST
 		pt_entry_t opte;
 #endif
@@ -1125,20 +1121,19 @@ pmap_protect(struct pmap *pm, vaddr_t sv
 		uint32_t mdattr;
 		bool executable;
 
-		ptep = _pmap_pte_lookup_l3(pm, va);
-		if (ptep == NULL) {
-			PMAP_COUNT(protect_none);
-			continue;
-		}
+		/* va is belong to the same L3 table as before? */
+		if ((blocksize == L3_SIZE) && ((va & L3INDEXMASK) != 0))
+			ptep++;
+		else
+			ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
 
 		pte = *ptep;
-
-		if (!l3pte_valid(pte)) {
+		if (!lxpde_valid(pte)) {
 			PMAP_COUNT(protect_none);
 			continue;
 		}
 
-		pa = l3pte_pa(pte);
+		pa = lxpde_pa(pte);
 		pg = PHYS_TO_VM_PAGE(pa);
 
 		if (pg != NULL) {
@@ -1152,7 +1147,6 @@ pmap_protect(struct pmap *pm, vaddr_t sv
 			PMAP_COUNT(protect_unmanaged);
 		}
 
-		pte = *ptep;
 #ifdef UVMHIST
 		opte = pte;
 #endif
@@ -1282,6 +1276,7 @@ pmap_destroy(struct pmap *pm)
 
 	_pmap_free_pdp_all(pm);
 	mutex_destroy(&pm->pm_lock);
+
 	pool_cache_put(&_pmap_cache, pm);
 
 	PMAP_COUNT(destroy);
@@ -1555,37 +1550,46 @@ pmap_remove_all(struct pmap *pm)
 }
 
 static void
-_pmap_remove(struct pmap *pm, vaddr_t va, bool kremove)
+_pmap_remove(struct pmap *pm, vaddr_t sva, vaddr_t eva, bool kremove,
+    struct pv_entry **pvtofree)
 {
-	pt_entry_t pte, *ptep;
+	pt_entry_t pte, *ptep = NULL;
 	struct vm_page *pg;
-	struct pv_entry *opv = NULL;
+	struct pv_entry *opv;
 	paddr_t pa;
-
+	vaddr_t va;
+	vsize_t blocksize = 0;
 
 	UVMHIST_FUNC(__func__);
 	UVMHIST_CALLED(pmaphist);
 
-	UVMHIST_LOG(pmaphist, "pm=%p, va=%016lx, kremovemode=%d",
-	    pm, va, kremove, 0);
+	UVMHIST_LOG(pmaphist, "pm=%p, sva=%016lx, eva=%016lx, kremovemode=%d",
+	    pm, sva, eva, kremove);
 
-	pm_lock(pm);
+	for (va = sva; (va < eva) && (pm->pm_stats.resident_count != 0);
+	    va = (va + blocksize) & ~(blocksize - 1)) {
 
-	ptep = _pmap_pte_lookup_l3(pm, va);
-	if (ptep != NULL) {
-		pte = *ptep;
-		if (!l3pte_valid(pte))
-			goto done;
+		/* va is belong to the same L3 table as before? */
+		if ((blocksize == L3_SIZE) && ((va & L3INDEXMASK) != 0))
+			ptep++;
+		else
+			ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
 
-		pa = l3pte_pa(pte);
+		pte = *ptep;
+		if (!lxpde_valid(pte))
+			continue;
 
-		if (kremove)
-			pg = NULL;
-		else
+		if (!kremove) {
+			pa = lxpde_pa(pte);
 			pg = PHYS_TO_VM_PAGE(pa);
-
-		if (pg != NULL)
-			opv = _pmap_remove_pv(pg, pm, va, pte);
+			if (pg != NULL) {
+				opv = _pmap_remove_pv(pg, pm, va, pte);
+				if (opv != NULL) {
+					opv->pv_next = *pvtofree;
+					*pvtofree = opv;
+				}
+			}
+		}
 
 		atomic_swap_64(ptep, 0);
 		AARCH64_TLBI_BY_ASID_VA(pm->pm_asid, va, true);
@@ -1594,23 +1598,25 @@ _pmap_remove(struct pmap *pm, vaddr_t va
 			pm->pm_stats.wired_count--;
 		pm->pm_stats.resident_count--;
 	}
- done:
-	pm_unlock(pm);
-
-	if (opv != NULL)
-		pool_cache_put(&_pmap_pv_pool, opv);
 }
 
 void
 pmap_remove(struct pmap *pm, vaddr_t sva, vaddr_t eva)
 {
-	vaddr_t va;
+	struct pv_entry *pvtofree = NULL;
+	struct pv_entry *pv, *pvtmp;
 
 	KASSERT_PM_ADDR(pm, sva);
 	KASSERT(!IN_KSEG_ADDR(sva));
 
-	for (va = sva; va < eva; va += PAGE_SIZE)
-		_pmap_remove(pm, va, false);
+	pm_lock(pm);
+	_pmap_remove(pm, sva, eva, false, &pvtofree);
+	pm_unlock(pm);
+
+	for (pv = pvtofree; pv != NULL; pv = pvtmp) {
+		pvtmp = pv->pv_next;
+		pool_cache_put(&_pmap_pv_pool, pv);
+	}
 }
 
 void
@@ -1631,6 +1637,7 @@ pmap_page_protect(struct vm_page *pg, vm
 
 	if ((prot & (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
 	    VM_PROT_NONE) {
+		struct pv_entry *pvtofree = NULL;
 
 		/* remove all pages reference to this physical page */
 		pmap_pv_lock(md);
@@ -1646,10 +1653,16 @@ pmap_page_protect(struct vm_page *pg, vm
 
 			TAILQ_REMOVE(&md->mdpg_pvhead, pv, pv_link);
 			PMAP_COUNT(pv_remove);
-			pool_cache_put(&_pmap_pv_pool, pv);
+
+			pv->pv_next = pvtofree;
+			pvtofree = pv;
 		}
 		pmap_pv_unlock(md);
 
+		for (pv = pvtofree; pv != NULL; pv = pvtmp) {
+			pvtmp = pv->pv_next;
+			pool_cache_put(&_pmap_pv_pool, pv);
+		}
 	} else {
 		pmap_pv_lock(md);
 		TAILQ_FOREACH(pv, &md->mdpg_pvhead, pv_link) {

Index: src/sys/arch/aarch64/include/pmap.h
diff -u src/sys/arch/aarch64/include/pmap.h:1.20 src/sys/arch/aarch64/include/pmap.h:1.21
--- src/sys/arch/aarch64/include/pmap.h:1.20	Fri Jan  4 21:57:53 2019
+++ src/sys/arch/aarch64/include/pmap.h	Wed Feb  6 05:33:41 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.20 2019/01/04 21:57:53 jdolecek Exp $ */
+/* $NetBSD: pmap.h,v 1.21 2019/02/06 05:33:41 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -113,20 +113,21 @@ struct vm_page_md {
 #define LX_BLKPAG_ATTR_MASK		LX_BLKPAG_ATTR_INDX
 
 #define lxpde_pa(pde)		((paddr_t)((pde) & LX_TBL_PA))
+#define lxpde_valid(pde)	(((pde) & LX_VALID) == LX_VALID)
 #define l0pde_pa(pde)		lxpde_pa(pde)
 #define l0pde_index(v)		(((vaddr_t)(v) & L0_ADDR_BITS) >> L0_SHIFT)
-#define l0pde_valid(pde)	(((pde) & LX_VALID) == LX_VALID)
+#define l0pde_valid(pde)	lxpde_valid(pde)
 /* l0pte always contains table entries */
 
 #define l1pde_pa(pde)		lxpde_pa(pde)
 #define l1pde_index(v)		(((vaddr_t)(v) & L1_ADDR_BITS) >> L1_SHIFT)
-#define l1pde_valid(pde)	(((pde) & LX_VALID) == LX_VALID)
+#define l1pde_valid(pde)	lxpde_valid(pde)
 #define l1pde_is_block(pde)	(((pde) & LX_TYPE) == LX_TYPE_BLK)
 #define l1pde_is_table(pde)	(((pde) & LX_TYPE) == LX_TYPE_TBL)
 
 #define l2pde_pa(pde)		lxpde_pa(pde)
 #define l2pde_index(v)		(((vaddr_t)(v) & L2_ADDR_BITS) >> L2_SHIFT)
-#define l2pde_valid(pde)	(((pde) & LX_VALID) == LX_VALID)
+#define l2pde_valid(pde)	lxpde_valid(pde)
 #define l2pde_is_block(pde)	(((pde) & LX_TYPE) == LX_TYPE_BLK)
 #define l2pde_is_table(pde)	(((pde) & LX_TYPE) == LX_TYPE_TBL)
 
@@ -137,7 +138,7 @@ struct vm_page_md {
 #define l3pte_writable(pde)	\
     (((pde) & (LX_BLKPAG_AF|LX_BLKPAG_AP)) == (LX_BLKPAG_AF|LX_BLKPAG_AP_RW))
 #define l3pte_index(v)		(((vaddr_t)(v) & L3_ADDR_BITS) >> L3_SHIFT)
-#define l3pte_valid(pde)	(((pde) & LX_VALID) == LX_VALID)
+#define l3pte_valid(pde)	lxpde_valid(pde)
 #define l3pte_is_page(pde)	(((pde) & LX_TYPE) == L3_TYPE_PAG)
 /* l3pte contains always page entries */
 

Reply via email to