Module Name: src
Committed By: skrll
Date: Wed May 24 06:27:33 UTC 2017
Modified Files:
src/sys/arch/arm/arm32: pmap.c
Log Message:
Move closer to the common pmap by using the same pmap_remove_all
optimisation where TLB flushes are avoided by clever ASID assignment.
pmap_remove_all_complete can now be removed.
To generate a diff of this commit:
cvs rdiff -u -r1.347 -r1.348 src/sys/arch/arm/arm32/pmap.c
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/arm/arm32/pmap.c
diff -u src/sys/arch/arm/arm32/pmap.c:1.347 src/sys/arch/arm/arm32/pmap.c:1.348
--- src/sys/arch/arm/arm32/pmap.c:1.347 Mon May 22 06:35:04 2017
+++ src/sys/arch/arm/arm32/pmap.c Wed May 24 06:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.347 2017/05/22 06:35:04 skrll Exp $ */
+/* $NetBSD: pmap.c,v 1.348 2017/05/24 06:27:33 skrll Exp $ */
/*
* Copyright 2003 Wasabi Systems, Inc.
@@ -217,7 +217,7 @@
#include <arm/locore.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.347 2017/05/22 06:35:04 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.348 2017/05/24 06:27:33 skrll Exp $");
//#define PMAP_DEBUG
#ifdef PMAP_DEBUG
@@ -485,6 +485,11 @@ EVCNT_ATTACH_STATIC(pmap_ev_activations)
#define PMAPCOUNT(x) ((void)0)
#endif
+#ifdef ARM_MMU_EXTENDED
+void pmap_md_pdetab_activate(pmap_t, struct lwp *);
+void pmap_md_pdetab_deactivate(pmap_t pm);
+#endif
+
/*
* pmap copy/zero page, and mem(5) hook point
*/
@@ -3411,14 +3416,6 @@ pmap_enter(pmap_t pm, vaddr_t va, paddr_
void
pmap_remove(pmap_t pm, vaddr_t sva, vaddr_t eva)
{
- vaddr_t next_bucket;
- u_int cleanlist_idx, total, cnt;
- struct {
- vaddr_t va;
- pt_entry_t *ptep;
- } cleanlist[PMAP_REMOVE_CLEAN_LIST_SIZE];
- u_int mappings;
-
UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist, " (pm=%p, sva=%#x, eva=%#x)", pm, sva, eva, 0);
@@ -3427,22 +3424,27 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
*/
pmap_acquire_pmap_lock(pm);
+#ifndef ARM_MMU_EXTENDED
+ u_int cleanlist_idx, total, cnt;
+ struct {
+ vaddr_t va;
+ pt_entry_t *ptep;
+ } cleanlist[PMAP_REMOVE_CLEAN_LIST_SIZE];
+
if (pm->pm_remove_all || !pmap_is_cached(pm)) {
cleanlist_idx = PMAP_REMOVE_CLEAN_LIST_SIZE + 1;
-#ifndef ARM_MMU_EXTENDED
if (pm->pm_cstate.cs_tlb == 0)
pm->pm_remove_all = true;
-#endif
} else
cleanlist_idx = 0;
-
total = 0;
+#endif
while (sva < eva) {
/*
* Do one L2 bucket's worth at a time.
*/
- next_bucket = L2_NEXT_BUCKET_VA(sva);
+ vaddr_t next_bucket = L2_NEXT_BUCKET_VA(sva);
if (next_bucket > eva)
next_bucket = eva;
@@ -3453,9 +3455,9 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
}
pt_entry_t *ptep = &l2b->l2b_kva[l2pte_index(sva)];
+ u_int mappings = 0;
- for (mappings = 0;
- sva < next_bucket;
+ for (;sva < next_bucket;
sva += PAGE_SIZE, ptep += PAGE_SIZE / L2_S_SIZE) {
pt_entry_t opte = *ptep;
@@ -3502,13 +3504,12 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
}
#ifdef ARM_MMU_EXTENDED
- if (pm == pmap_kernel()) {
- l2pte_reset(ptep);
- PTE_SYNC(ptep);
- pmap_tlb_flush_SE(pm, sva, flags);
- continue;
+ l2pte_reset(ptep);
+ PTE_SYNC(ptep);
+ if (__predict_false(pm->pm_remove_all == false)) {
+ pmap_tlb_flush_SE(pm, sva, flags);
}
-#endif
+#else
if (cleanlist_idx < PMAP_REMOVE_CLEAN_LIST_SIZE) {
/* Add to the clean list. */
cleanlist[cleanlist_idx].ptep = ptep;
@@ -3540,8 +3541,10 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
pmap_tlb_flush_SE(pm, sva, flags);
}
}
+#endif
}
+#ifndef ARM_MMU_EXTENDED
/*
* Deal with any left overs
*/
@@ -3550,10 +3553,6 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
for (cnt = 0; cnt < cleanlist_idx; cnt++) {
l2pte_reset(cleanlist[cnt].ptep);
PTE_SYNC_CURRENT(pm, cleanlist[cnt].ptep);
-#ifdef ARM_MMU_EXTENDED
- vaddr_t clva = cleanlist[cnt].va;
- pmap_tlb_flush_SE(pm, clva, PVF_REF);
-#else
vaddr_t va = cleanlist[cnt].va;
if (pm->pm_cstate.cs_all != 0) {
vaddr_t clva = va & ~PAGE_MASK;
@@ -3565,7 +3564,6 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
pmap_tlb_flush_SE(pm, clva,
PVF_REF | flags);
}
-#endif /* ARM_MMU_EXTENDED */
}
/*
@@ -3584,7 +3582,7 @@ pmap_remove(pmap_t pm, vaddr_t sva, vadd
pm->pm_remove_all = true;
}
}
-
+#endif /* ARM_MMU_EXTENDED */
pmap_free_l2_bucket(pm, l2b, mappings);
pm->pm_stats.resident_count -= mappings / (PAGE_SIZE/L2_S_SIZE);
@@ -4768,20 +4766,86 @@ pmap_unwire(pmap_t pm, vaddr_t va)
pmap_release_pmap_lock(pm);
}
+#ifdef ARM_MMU_EXTENDED
void
-pmap_activate(struct lwp *l)
+pmap_md_pdetab_activate(pmap_t pm, struct lwp *l)
{
+ UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
+
+ /*
+ * Assume that TTBR1 has only global mappings and TTBR0 only
+ * has non-global mappings. To prevent speculation from doing
+ * evil things we disable translation table walks using TTBR0
+ * before setting the CONTEXTIDR (ASID) or new TTBR0 value.
+ * Once both are set, table walks are reenabled.
+ */
+ const uint32_t old_ttbcr = armreg_ttbcr_read();
+ armreg_ttbcr_write(old_ttbcr | TTBCR_S_PD0);
+ arm_isb();
+
+ pmap_tlb_asid_acquire(pm, l);
+
struct cpu_info * const ci = curcpu();
+ struct pmap_asid_info * const pai = PMAP_PAI(pm, cpu_tlb_info(ci));
+
+ cpu_setttb(pm->pm_l1_pa, pai->pai_asid);
+ /*
+ * Now we can reenable tablewalks since the CONTEXTIDR and TTRB0
+ * have been updated.
+ */
+ arm_isb();
+
+ if (pm != pmap_kernel()) {
+ armreg_ttbcr_write(old_ttbcr & ~TTBCR_S_PD0);
+ }
+ cpu_cpwait();
+
+ UVMHIST_LOG(maphist, " pm %p pm->pm_l1_pa %08x asid %u... done", pm,
+ pm->pm_l1_pa, pai->pai_asid, 0);
+
+ KASSERTMSG(ci->ci_pmap_asid_cur == pai->pai_asid, "%u vs %u",
+ ci->ci_pmap_asid_cur, pai->pai_asid);
+ ci->ci_pmap_cur = pm;
+}
+
+void
+pmap_md_pdetab_deactivate(pmap_t pm)
+{
+
+ UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
+
+ kpreempt_disable();
+ struct cpu_info * const ci = curcpu();
+ /*
+ * Disable translation table walks from TTBR0 while no pmap has been
+ * activated.
+ */
+ const uint32_t old_ttbcr = armreg_ttbcr_read();
+ armreg_ttbcr_write(old_ttbcr | TTBCR_S_PD0);
+ arm_isb();
+ pmap_tlb_asid_deactivate(pm);
+ cpu_setttb(pmap_kernel()->pm_l1_pa, KERNEL_PID);
+ arm_isb();
+
+ ci->ci_pmap_cur = pmap_kernel();
+ KASSERTMSG(ci->ci_pmap_asid_cur == KERNEL_PID, "ci_pmap_asid_cur %u",
+ ci->ci_pmap_asid_cur);
+ kpreempt_enable();
+}
+#endif
+
+void
+pmap_activate(struct lwp *l)
+{
extern int block_userspace_access;
pmap_t npm = l->l_proc->p_vmspace->vm_map.pmap;
-#ifdef ARM_MMU_EXTENDED
- struct pmap_asid_info * const pai = PMAP_PAI(npm, cpu_tlb_info(ci));
-#endif
UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist, "(l=%#x) pm=%#x", l, npm, 0, 0);
+ struct cpu_info * const ci = curcpu();
+
/*
* If activating a non-current lwp or the current lwp is
* already active, just return.
@@ -4831,9 +4895,7 @@ pmap_activate(struct lwp *l)
* entire cache.
*/
pmap_t rpm = ci->ci_pmap_lastuser;
-#endif
-#ifndef ARM_MMU_EXTENDED
/*
* XXXSCW: There's a corner case here which can leave turds in the
* cache as reported in kern/41058. They're probably left over during
@@ -4881,30 +4943,7 @@ pmap_activate(struct lwp *l)
#endif
#ifdef ARM_MMU_EXTENDED
- /*
- * Assume that TTBR1 has only global mappings and TTBR0 only has
- * non-global mappings. To prevent speculation from doing evil things
- * we disable translation table walks using TTBR0 before setting the
- * CONTEXTIDR (ASID) or new TTBR0 value. Once both are set, table
- * walks are reenabled.
- */
- UVMHIST_LOG(maphist, " acquiring asid", 0, 0, 0, 0);
- const uint32_t old_ttbcr = armreg_ttbcr_read();
- armreg_ttbcr_write(old_ttbcr | TTBCR_S_PD0);
- arm_isb();
- pmap_tlb_asid_acquire(npm, l);
- UVMHIST_LOG(maphist, " setting ttbr pa=%#x asid=%#x", npm->pm_l1_pa, pai->pai_asid, 0, 0);
- cpu_setttb(npm->pm_l1_pa, pai->pai_asid);
- /*
- * Now we can reenable tablewalks since the CONTEXTIDR and TTRB0 have
- * been updated.
- */
- arm_isb();
- if (npm != pmap_kernel()) {
- armreg_ttbcr_write(old_ttbcr & ~TTBCR_S_PD0);
- }
- cpu_cpwait();
- ci->ci_pmap_asid_cur = pai->pai_asid;
+ pmap_md_pdetab_activate(npm, l);
#else
cpu_domains(ndacr);
if (npm == pmap_kernel() || npm == rpm) {
@@ -4947,8 +4986,8 @@ pmap_activate(struct lwp *l)
/* But the new one is */
npm->pm_activated = true;
}
-#endif
ci->ci_pmap_cur = npm;
+#endif
UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0);
}
@@ -4962,20 +5001,7 @@ pmap_deactivate(struct lwp *l)
UVMHIST_LOG(maphist, "(l=%#x) pm=%#x", l, pm, 0, 0);
#ifdef ARM_MMU_EXTENDED
- kpreempt_disable();
- struct cpu_info * const ci = curcpu();
- /*
- * Disable translation table walks from TTBR0 while no pmap has been
- * activated.
- */
- const uint32_t old_ttbcr = armreg_ttbcr_read();
- armreg_ttbcr_write(old_ttbcr | TTBCR_S_PD0);
- arm_isb();
- pmap_tlb_asid_deactivate(pm);
- cpu_setttb(pmap_kernel()->pm_l1_pa, KERNEL_PID);
- ci->ci_pmap_cur = pmap_kernel();
- ci->ci_pmap_asid_cur = KERNEL_PID;
- kpreempt_enable();
+ pmap_md_pdetab_deactivate(pm);
#else
/*
* If the process is exiting, make sure pmap_activate() does
@@ -4990,67 +5016,6 @@ pmap_deactivate(struct lwp *l)
UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0);
}
-#ifdef ARM_MMU_EXTENDED
-static inline void
-pmap_remove_all_complete(pmap_t pm)
-{
- KASSERT(pm != pmap_kernel());
-
- KASSERTMSG(curcpu()->ci_pmap_cur != pm
- || pm->pm_pai[0].pai_asid == curcpu()->ci_pmap_asid_cur,
- "pmap/asid %p/%#x != %s cur pmap/asid %p/%#x", pm,
- pm->pm_pai[0].pai_asid, curcpu()->ci_data.cpu_name,
- curcpu()->ci_pmap_cur, curcpu()->ci_pmap_asid_cur);
-
- /*
- * Finish up the pmap_remove_all() optimisation by flushing
- * all our ASIDs.
- */
-#ifdef MULTIPROCESSOR
- // This should be the last CPU with this pmap onproc
-// KASSERT(!kcpuset_isotherset(pm->pm_onproc, cpu_index(curcpu())));
-#if PMAP_TLB_MAX > 1
- for (u_int i = 0; !kcpuset_iszero(pm->pm_active); i++) {
- KASSERT(i < pmap_ntlbs);
- struct pmap_tlb_info * const ti = pmap_tlbs[i];
-#else
- struct pmap_tlb_info * const ti = &pmap_tlb0_info;
-#endif
- struct cpu_info * const ci = curcpu();
- TLBINFO_LOCK(ti);
- struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
- if (PMAP_PAI_ASIDVALID_P(pai, ti)) {
- if (kcpuset_isset(pm->pm_onproc, cpu_index(ci))) {
-#if PMAP_TLB_MAX == 1
- KASSERT(cpu_tlb_info(ci) == ti);
-
- tlb_invalidate_asids(pai->pai_asid,
- pai->pai_asid);
-#else
- if (cpu_tlb_info(ci) == ti) {
- tlb_invalidate_asids(pai->pai_asid,
- pai->pai_asid);
- } else {
- pm->pm_shootdown_needed = 1;
- }
-#endif
- }
- }
- TLBINFO_UNLOCK(ti);
-
-#if PMAP_TLB_MAX > 1
- }
-#endif
-#else /* MULTIPROCESSOR */
-
- struct pmap_asid_info * const pai =
- PMAP_PAI(pm, cpu_tlb_info(ci));
-
- tlb_invalidate_asids(pai->pai_asid, pai->pai_asid);
-#endif /* MULTIPROCESSOR */
-}
-#endif
-
void
pmap_update(pmap_t pm)
{
@@ -5060,39 +5025,16 @@ pmap_update(pmap_t pm)
UVMHIST_LOG(maphist, "pm=%#x remove_all %d", pm, pm->pm_remove_all, 0,
0);
+#ifndef ARM_MMU_EXTENDED
if (pm->pm_remove_all) {
-#ifdef ARM_MMU_EXTENDED
- pmap_remove_all_complete(pm);
-#else
/*
* Finish up the pmap_remove_all() optimisation by flushing
* the TLB.
*/
pmap_tlb_flushID(pm);
-#endif
pm->pm_remove_all = false;
}
-#ifdef ARM_MMU_EXTENDED
-#if defined(MULTIPROCESSOR)
- armreg_bpiallis_write(0);
-#else
- armreg_bpiall_write(0);
-#endif
-
-#if defined(MULTIPROCESSOR) && PMAP_TLB_MAX > 1
- u_int pending = atomic_swap_uint(&pmap->pm_shootdown_pending, 0);
- if (pending && pmap_tlb_shootdown_bystanders(pmap)) {
- PMAP_COUNT(shootdown_ipis);
- }
-#endif
- KASSERTMSG(pm == pmap_kernel()
- || curcpu()->ci_pmap_cur != pm
- || pm->pm_pai[0].pai_asid == curcpu()->ci_pmap_asid_cur,
- "pmap/asid %p/%#x != %s cur pmap/asid %p/%#x", pm,
- pm->pm_pai[0].pai_asid, curcpu()->ci_data.cpu_name,
- curcpu()->ci_pmap_cur, curcpu()->ci_pmap_asid_cur);
-#else
if (pmap_is_current(pm)) {
/*
* If we're dealing with a current userland pmap, move its L1
@@ -5108,6 +5050,40 @@ pmap_update(pmap_t pm)
*/
pm->pm_cstate.cs_all = PMAP_CACHE_STATE_ALL;
}
+#else
+
+ kpreempt_disable();
+#if defined(MULTIPROCESSOR) && PMAP_TLB_MAX > 1
+ u_int pending = atomic_swap_uint(&pmap->pm_shootdown_pending, 0);
+ if (pending && pmap_tlb_shootdown_bystanders(pmap)) {
+ PMAP_COUNT(shootdown_ipis);
+ }
+#endif
+
+ /*
+ * If pmap_remove_all was called, we deactivated ourselves and released
+ * our ASID. Now we have to reactivate ourselves.
+ */
+ if (__predict_false(pm->pm_remove_all)) {
+ pm->pm_remove_all = false;
+
+ KASSERT(pm != pmap_kernel());
+ pmap_md_pdetab_activate(pm, curlwp);
+ }
+
+#if defined(MULTIPROCESSOR)
+ armreg_bpiallis_write(0);
+#else
+ armreg_bpiall_write(0);
+#endif
+ kpreempt_enable();
+
+ KASSERTMSG(pm == pmap_kernel()
+ || curcpu()->ci_pmap_cur != pm
+ || pm->pm_pai[0].pai_asid == curcpu()->ci_pmap_asid_cur,
+ "pmap/asid %p/%#x != %s cur pmap/asid %p/%#x", pm,
+ pm->pm_pai[0].pai_asid, curcpu()->ci_data.cpu_name,
+ curcpu()->ci_pmap_cur, curcpu()->ci_pmap_asid_cur);
#endif
PMAPCOUNT(updates);
@@ -5132,6 +5108,20 @@ pmap_remove_all(pmap_t pm)
#ifdef PMAP_CACHE_VIVT
pmap_cache_wbinv_all(pm, PVF_EXEC);
#endif
+#ifdef ARM_MMU_EXTENDED
+#ifdef MULTIPROCESSOR
+ struct cpu_info * const ci = curcpu();
+ // This should be the last CPU with this pmap onproc
+ KASSERT(!kcpuset_isotherset(pm->pm_onproc, cpu_index(ci)));
+ if (kcpuset_isset(pm->pm_onproc, cpu_index(ci)))
+#endif
+ pmap_tlb_asid_deactivate(pm);
+#ifdef MULTIPROCESSOR
+ KASSERT(kcpuset_iszero(pm->pm_onproc));
+#endif
+
+ pmap_tlb_asid_release_all(pm);
+#endif
pm->pm_remove_all = true;
}
@@ -5154,7 +5144,6 @@ pmap_destroy(pmap_t pm)
if (pm->pm_remove_all) {
#ifdef ARM_MMU_EXTENDED
- pmap_remove_all_complete(pm);
pmap_tlb_asid_release_all(pm);
#else
pmap_tlb_flushID(pm);