svn commit: r264130 - head/sys/arm/arm

Ian Lepore ian at FreeBSD.org
Fri Apr 4 17:57:50 UTC 2014


Author: ian
Date: Fri Apr  4 17:57:49 2014
New Revision: 264130
URL: http://svnweb.freebsd.org/changeset/base/264130

Log:
  Allocate per-cpu resources for doing pmap_zero_page() and pmap_copy_page().
  This is performance enhancement rather than bugfix.

Modified:
  head/sys/arm/arm/pmap-v6.c

Modified: head/sys/arm/arm/pmap-v6.c
==============================================================================
--- head/sys/arm/arm/pmap-v6.c	Fri Apr  4 17:45:39 2014	(r264129)
+++ head/sys/arm/arm/pmap-v6.c	Fri Apr  4 17:57:49 2014	(r264130)
@@ -265,9 +265,18 @@ vm_offset_t vm_max_kernel_address;
 
 struct pmap kernel_pmap_store;
 
-static pt_entry_t *csrc_pte, *cdst_pte;
-static vm_offset_t csrcp, cdstp;
-static struct mtx cmtx;
+/*
+ * Resources for quickly copying and zeroing pages using virtual address space
+ * and page table entries that are pre-allocated per-CPU by pmap_init().
+ */
+struct czpages {
+	struct	mtx 	lock;
+	pt_entry_t	*srcptep;
+	pt_entry_t	*dstptep;
+	vm_offset_t	srcva;
+	vm_offset_t	dstva;
+};
+static struct czpages cpu_czpages[MAXCPU];
 
 static void		pmap_init_l1(struct l1_ttable *, pd_entry_t *);
 /*
@@ -1803,13 +1812,14 @@ pmap_bootstrap(vm_offset_t firstaddr, st
 	struct l1_ttable *l1 = &static_l1;
 	struct l2_dtable *l2;
 	struct l2_bucket *l2b;
+	struct czpages *czp;
 	pd_entry_t pde;
 	pd_entry_t *kernel_l1pt = (pd_entry_t *)l1pt->pv_va;
 	pt_entry_t *ptep;
 	vm_paddr_t pa;
 	vm_offset_t va;
 	vm_size_t size;
-	int l1idx, l2idx, l2next = 0;
+	int i, l1idx, l2idx, l2next = 0;
 
 	PDEBUG(1, printf("firstaddr = %08x, lastaddr = %08x\n",
 	    firstaddr, vm_max_kernel_address));
@@ -1921,13 +1931,16 @@ pmap_bootstrap(vm_offset_t firstaddr, st
 
 	/*
 	 * Reserve some special page table entries/VA space for temporary
-	 * mapping of pages.
+	 * mapping of pages that are being copied or zeroed.
 	 */
+	for (czp = cpu_czpages, i = 0; i < MAXCPU; ++i, ++czp) {
+		mtx_init(&czp->lock, "czpages", NULL, MTX_DEF);
+		pmap_alloc_specials(&virtual_avail, 1, &czp->srcva, &czp->srcptep);
+		pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)czp->srcptep);
+		pmap_alloc_specials(&virtual_avail, 1, &czp->dstva, &czp->dstptep);
+		pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)czp->dstptep);
+	}
 
-	pmap_alloc_specials(&virtual_avail, 1, &csrcp, &csrc_pte);
-	pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)csrc_pte);
-	pmap_alloc_specials(&virtual_avail, 1, &cdstp, &cdst_pte);
-	pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)cdst_pte);
 	size = ((vm_max_kernel_address - pmap_curmaxkvaddr) + L1_S_OFFSET) /
 	    L1_S_SIZE;
 	pmap_alloc_specials(&virtual_avail,
@@ -1955,7 +1968,6 @@ pmap_bootstrap(vm_offset_t firstaddr, st
 	virtual_avail = round_page(virtual_avail);
 	virtual_end = vm_max_kernel_address;
 	kernel_vm_end = pmap_curmaxkvaddr;
-	mtx_init(&cmtx, "TMP mappings mtx", NULL, MTX_DEF);
 
 	pmap_set_pcb_pagedir(kernel_pmap, thread0.td_pcb);
 }
@@ -4439,39 +4451,42 @@ pmap_remove(pmap_t pmap, vm_offset_t sva
 static void
 pmap_zero_page_gen(vm_page_t m, int off, int size)
 {
+	struct czpages *czp;
+
+	KASSERT(TAILQ_EMPTY(&m->md.pv_list), 
+	    ("pmap_zero_page_gen: page has mappings"));
 
 	vm_paddr_t phys = VM_PAGE_TO_PHYS(m);
-	if (!TAILQ_EMPTY(&m->md.pv_list))
-		panic("pmap_zero_page: page has mappings");
 
-	mtx_lock(&cmtx);
+	sched_pin();
+	czp = &cpu_czpages[PCPU_GET(cpuid)];
+	mtx_lock(&czp->lock);
+	
 	/*
-	 * Hook in the page, zero it, invalidate the TLB as needed.
-	 *
-	 * Note the temporary zero-page mapping must be a non-cached page in
-	 * order to work without corruption when write-allocate is enabled.
+	 * Hook in the page, zero it.
 	 */
-	*cdst_pte = L2_S_PROTO | phys | pte_l2_s_cache_mode | L2_S_REF;
-	pmap_set_prot(cdst_pte, VM_PROT_WRITE, 0);
-	PTE_SYNC(cdst_pte);
-	cpu_tlb_flushD_SE(cdstp);
+	*czp->dstptep = L2_S_PROTO | phys | pte_l2_s_cache_mode | L2_S_REF;
+	pmap_set_prot(czp->dstptep, VM_PROT_WRITE, 0);
+	PTE_SYNC(czp->dstptep);
+	cpu_tlb_flushD_SE(czp->dstva);
 	cpu_cpwait();
+
 	if (off || size != PAGE_SIZE)
-		bzero((void *)(cdstp + off), size);
+		bzero((void *)(czp->dstva + off), size);
 	else
-		bzero_page(cdstp);
+		bzero_page(czp->dstva);
 
 	/*
-	 * Although aliasing is not possible if we use 
-	 * cdstp temporary mappings with memory that 
-	 * will be mapped later as non-cached or with write-through 
-	 * caches we might end up overwriting it when calling wbinv_all
-	 * So make sure caches are clean after copy operation
+	 * Although aliasing is not possible, if we use temporary mappings with
+	 * memory that will be mapped later as non-cached or with write-through
+	 * caches, we might end up overwriting it when calling wbinv_all.  So
+	 * make sure caches are clean after the operation.
 	 */
-	cpu_idcache_wbinv_range(cdstp, size);
-	pmap_l2cache_wbinv_range(cdstp, phys, size);
+	cpu_idcache_wbinv_range(czp->dstva, size);
+	pmap_l2cache_wbinv_range(czp->dstva, phys, size);
 
-	mtx_unlock(&cmtx);
+	mtx_unlock(&czp->lock);
+	sched_unpin();
 }
 
 /*
@@ -4529,45 +4544,39 @@ pmap_zero_page_idle(vm_page_t m)
 void
 pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst)
 {
-	/*
-	 * Hold the source page's lock for the duration of the copy
-	 * so that no other mappings can be created while we have a
-	 * potentially aliased mapping.
-	 * Map the pages into the page hook points, copy them, and purge
-	 * the cache for the appropriate page. Invalidate the TLB
-	 * as required.
-	 */
-	mtx_lock(&cmtx);
-
-	/* For ARMv6 using System bit is deprecated and mapping with AP
-	 * bits set to 0x0 makes page not accessible. csrc_pte is mapped
-	 * read/write until proper mapping defines are created for ARMv6.
-	 */
-	*csrc_pte = L2_S_PROTO | src | pte_l2_s_cache_mode | L2_S_REF;
-	pmap_set_prot(csrc_pte, VM_PROT_READ, 0);
-	PTE_SYNC(csrc_pte);
-
-	*cdst_pte = L2_S_PROTO | dst | pte_l2_s_cache_mode | L2_S_REF;
-	pmap_set_prot(cdst_pte, VM_PROT_READ | VM_PROT_WRITE, 0);
-	PTE_SYNC(cdst_pte);
+	struct czpages *czp;
 
-	cpu_tlb_flushD_SE(csrcp);
-	cpu_tlb_flushD_SE(cdstp);
+	sched_pin();
+	czp = &cpu_czpages[PCPU_GET(cpuid)];
+	mtx_lock(&czp->lock);
+	
+	/*
+	 * Map the pages into the page hook points, copy them, and purge the
+	 * cache for the appropriate page.
+	 */
+	*czp->srcptep = L2_S_PROTO | src | pte_l2_s_cache_mode | L2_S_REF;
+	pmap_set_prot(czp->srcptep, VM_PROT_READ, 0);
+	PTE_SYNC(czp->srcptep);
+	cpu_tlb_flushD_SE(czp->srcva);
+	*czp->dstptep = L2_S_PROTO | dst | pte_l2_s_cache_mode | L2_S_REF;
+	pmap_set_prot(czp->dstptep, VM_PROT_READ | VM_PROT_WRITE, 0);
+	PTE_SYNC(czp->dstptep);
+	cpu_tlb_flushD_SE(czp->dstva);
 	cpu_cpwait();
 
+	bcopy_page(czp->srcva, czp->dstva);
+
 	/*
-	 * Although aliasing is not possible if we use 
-	 * cdstp temporary mappings with memory that 
-	 * will be mapped later as non-cached or with write-through 
-	 * caches we might end up overwriting it when calling wbinv_all
-	 * So make sure caches are clean after copy operation
+	 * Although aliasing is not possible, if we use temporary mappings with
+	 * memory that will be mapped later as non-cached or with write-through
+	 * caches, we might end up overwriting it when calling wbinv_all.  So
+	 * make sure caches are clean after the operation.
 	 */
-	bcopy_page(csrcp, cdstp);
-
-	cpu_idcache_wbinv_range(cdstp, PAGE_SIZE);
-	pmap_l2cache_wbinv_range(cdstp, dst, PAGE_SIZE);
+	cpu_idcache_wbinv_range(czp->dstva, PAGE_SIZE);
+	pmap_l2cache_wbinv_range(czp->dstva, dst, PAGE_SIZE);
 
-	mtx_unlock(&cmtx);
+	mtx_unlock(&czp->lock);
+	sched_unpin();
 }
 
 int unmapped_buf_allowed = 1;
@@ -4579,8 +4588,12 @@ pmap_copy_pages(vm_page_t ma[], vm_offse
 	vm_page_t a_pg, b_pg;
 	vm_offset_t a_pg_offset, b_pg_offset;
 	int cnt;
+	struct czpages *czp;
+
+	sched_pin();
+	czp = &cpu_czpages[PCPU_GET(cpuid)];
+	mtx_lock(&czp->lock);
 
-	mtx_lock(&cmtx);
 	while (xfersize > 0) {
 		a_pg = ma[a_offset >> PAGE_SHIFT];
 		a_pg_offset = a_offset & PAGE_MASK;
@@ -4588,27 +4601,29 @@ pmap_copy_pages(vm_page_t ma[], vm_offse
 		b_pg = mb[b_offset >> PAGE_SHIFT];
 		b_pg_offset = b_offset & PAGE_MASK;
 		cnt = min(cnt, PAGE_SIZE - b_pg_offset);
-		*csrc_pte = L2_S_PROTO | VM_PAGE_TO_PHYS(a_pg) |
+		*czp->srcptep = L2_S_PROTO | VM_PAGE_TO_PHYS(a_pg) |
 		    pte_l2_s_cache_mode | L2_S_REF;
-		pmap_set_prot(csrc_pte, VM_PROT_READ, 0);
-		PTE_SYNC(csrc_pte);
-		*cdst_pte = L2_S_PROTO | VM_PAGE_TO_PHYS(b_pg) |
+		pmap_set_prot(czp->srcptep, VM_PROT_READ, 0);
+		PTE_SYNC(czp->srcptep);
+		cpu_tlb_flushD_SE(czp->srcva);
+		*czp->dstptep = L2_S_PROTO | VM_PAGE_TO_PHYS(b_pg) |
 		    pte_l2_s_cache_mode | L2_S_REF;
-		pmap_set_prot(cdst_pte, VM_PROT_READ | VM_PROT_WRITE, 0);
-		PTE_SYNC(cdst_pte);
-		cpu_tlb_flushD_SE(csrcp);
-		cpu_tlb_flushD_SE(cdstp);
+		pmap_set_prot(czp->dstptep, VM_PROT_READ | VM_PROT_WRITE, 0);
+		PTE_SYNC(czp->dstptep);
+		cpu_tlb_flushD_SE(czp->dstva);
 		cpu_cpwait();
-		bcopy((char *)csrcp + a_pg_offset, (char *)cdstp + b_pg_offset,
+		bcopy((char *)czp->srcva + a_pg_offset, (char *)czp->dstva + b_pg_offset,
 		    cnt);
-		cpu_idcache_wbinv_range(cdstp + b_pg_offset, cnt);
-		pmap_l2cache_wbinv_range(cdstp + b_pg_offset,
+		cpu_idcache_wbinv_range(czp->dstva + b_pg_offset, cnt);
+		pmap_l2cache_wbinv_range(czp->dstva + b_pg_offset,
 		    VM_PAGE_TO_PHYS(b_pg) + b_pg_offset, cnt);
 		xfersize -= cnt;
 		a_offset += cnt;
 		b_offset += cnt;
 	}
-	mtx_unlock(&cmtx);
+
+	mtx_unlock(&czp->lock);
+	sched_unpin();
 }
 
 void


More information about the svn-src-head mailing list