svn commit: r255612 - head/sys/arm/arm
Zbigniew Bodek
zbb at FreeBSD.org
Mon Sep 16 10:39:36 UTC 2013
Author: zbb
Date: Mon Sep 16 10:39:35 2013
New Revision: 255612
URL: http://svnweb.freebsd.org/changeset/base/255612
Log:
Implement pmap_advise() for ARMv6/v7 pmap module
Apply the given advice to the specified range of addresses within the
given pmap. Depending on the advice, clear the referenced and/or
modified flags in each mapping. Superpage within the given range will
be demoted or destroyed.
Reviewed by: alc
Approved by: cognet (mentor)
Approved by: re
Modified:
head/sys/arm/arm/pmap-v6.c
Modified: head/sys/arm/arm/pmap-v6.c
==============================================================================
--- head/sys/arm/arm/pmap-v6.c Mon Sep 16 10:34:44 2013 (r255611)
+++ head/sys/arm/arm/pmap-v6.c Mon Sep 16 10:39:35 2013 (r255612)
@@ -4767,11 +4767,116 @@ pmap_is_modified(vm_page_t m)
}
/*
- * This function is advisory.
+ * Apply the given advice to the specified range of addresses within the
+ * given pmap. Depending on the advice, clear the referenced and/or
+ * modified flags in each mapping.
*/
void
pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice)
{
+ struct l2_bucket *l2b;
+ struct pv_entry *pve;
+ pd_entry_t *pl1pd, l1pd;
+ pt_entry_t *ptep, opte, pte;
+ vm_offset_t next_bucket;
+ vm_page_t m;
+
+ if (advice != MADV_DONTNEED && advice != MADV_FREE)
+ return;
+ rw_wlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+ for (; sva < eva; sva = next_bucket) {
+ next_bucket = L2_NEXT_BUCKET(sva);
+ if (next_bucket < sva)
+ next_bucket = eva;
+ pl1pd = &pmap->pm_l1->l1_kva[L1_IDX(sva)];
+ l1pd = *pl1pd;
+ if ((l1pd & L1_TYPE_MASK) == L1_S_PROTO) {
+ if (pmap == pmap_kernel())
+ continue;
+ if (!pmap_demote_section(pmap, sva)) {
+ /*
+ * The large page mapping was destroyed.
+ */
+ continue;
+ }
+ /*
+ * Unless the page mappings are wired, remove the
+ * mapping to a single page so that a subsequent
+ * access may repromote. Since the underlying
+ * l2_bucket is fully populated, this removal
+ * never frees an entire l2_bucket.
+ */
+ l2b = pmap_get_l2_bucket(pmap, sva);
+ KASSERT(l2b != NULL,
+ ("pmap_advise: no l2 bucket for "
+ "va 0x%#x, pmap 0x%p", sva, pmap));
+ ptep = &l2b->l2b_kva[l2pte_index(sva)];
+ opte = *ptep;
+ m = PHYS_TO_VM_PAGE(l2pte_pa(*ptep));
+ KASSERT(m != NULL,
+ ("pmap_advise: no vm_page for demoted superpage"));
+ pve = pmap_find_pv(&m->md, pmap, sva);
+ KASSERT(pve != NULL,
+ ("pmap_advise: no PV entry for managed mapping"));
+ if ((pve->pv_flags & PVF_WIRED) == 0) {
+ pmap_free_l2_bucket(pmap, l2b, 1);
+ pve = pmap_remove_pv(m, pmap, sva);
+ pmap_free_pv_entry(pmap, pve);
+ *ptep = 0;
+ PTE_SYNC(ptep);
+ if (pmap_is_current(pmap)) {
+ if (PTE_BEEN_EXECD(opte))
+ cpu_tlb_flushID_SE(sva);
+ else if (PTE_BEEN_REFD(opte))
+ cpu_tlb_flushD_SE(sva);
+ }
+ }
+ }
+ if (next_bucket > eva)
+ next_bucket = eva;
+ l2b = pmap_get_l2_bucket(pmap, sva);
+ if (l2b == NULL)
+ continue;
+ for (ptep = &l2b->l2b_kva[l2pte_index(sva)];
+ sva != next_bucket; ptep++, sva += PAGE_SIZE) {
+ opte = pte = *ptep;
+ if ((opte & L2_S_PROTO) == 0)
+ continue;
+ m = PHYS_TO_VM_PAGE(l2pte_pa(opte));
+ if (m == NULL || (m->oflags & VPO_UNMANAGED) != 0)
+ continue;
+ else if (L2_S_WRITABLE(opte)) {
+ if (advice == MADV_DONTNEED) {
+ /*
+ * Don't need to mark the page
+ * dirty as it was already marked as
+ * such in pmap_fault_fixup() or
+ * pmap_enter_locked().
+ * Just clear the state.
+ */
+ } else
+ pte |= L2_APX;
+
+ pte &= ~L2_S_REF;
+ *ptep = pte;
+ PTE_SYNC(ptep);
+ } else if (L2_S_REFERENCED(opte)) {
+ pte &= ~L2_S_REF;
+ *ptep = pte;
+ PTE_SYNC(ptep);
+ } else
+ continue;
+ if (pmap_is_current(pmap)) {
+ if (PTE_BEEN_EXECD(opte))
+ cpu_tlb_flushID_SE(sva);
+ else if (PTE_BEEN_REFD(opte))
+ cpu_tlb_flushD_SE(sva);
+ }
+ }
+ }
+ rw_wunlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
}
/*
More information about the svn-src-head
mailing list