Module Name:    src
Committed By:   matt
Date:           Thu Mar 11 08:19:01 UTC 2010

Modified Files:
        src/sys/arch/mips/include [matt-nb5-mips64]: cpu.h pmap.h vmparam.h
        src/sys/arch/mips/mips [matt-nb5-mips64]: cpu_subr.c pmap.c pmap_tlb.c
            trap.c

Log Message:
Add MP-aware icache support.


To generate a diff of this commit:
cvs rdiff -u -r1.90.16.26 -r1.90.16.27 src/sys/arch/mips/include/cpu.h
cvs rdiff -u -r1.54.26.11 -r1.54.26.12 src/sys/arch/mips/include/pmap.h
cvs rdiff -u -r1.41.28.12 -r1.41.28.13 src/sys/arch/mips/include/vmparam.h
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/sys/arch/mips/mips/cpu_subr.c
cvs rdiff -u -r1.179.16.21 -r1.179.16.22 src/sys/arch/mips/mips/pmap.c
cvs rdiff -u -r1.1.2.9 -r1.1.2.10 src/sys/arch/mips/mips/pmap_tlb.c
cvs rdiff -u -r1.217.12.21 -r1.217.12.22 src/sys/arch/mips/mips/trap.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/mips/include/cpu.h
diff -u src/sys/arch/mips/include/cpu.h:1.90.16.26 src/sys/arch/mips/include/cpu.h:1.90.16.27
--- src/sys/arch/mips/include/cpu.h:1.90.16.26	Thu Mar 11 08:16:59 2010
+++ src/sys/arch/mips/include/cpu.h	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.h,v 1.90.16.26 2010/03/11 08:16:59 matt Exp $	*/
+/*	$NetBSD: cpu.h,v 1.90.16.27 2010/03/11 08:19:01 matt Exp $	*/
 
 /*-
  * Copyright (c) 1992, 1993
@@ -93,12 +93,17 @@
 	void *ci_fpsave_si;		/* FP sync softint handler */
 	struct evcnt ci_evcnt_all_ipis;	/* aggregated IPI counter */
 	struct evcnt ci_evcnt_per_ipi[NIPIS];	/* individual IPI counters*/
+	struct evcnt ci_evcnt_synci_activate_rqst;
+	struct evcnt ci_evcnt_synci_onproc_rqst;
+	struct evcnt ci_evcnt_synci_deferred_rqst;
+	struct evcnt ci_evcnt_synci_ipi_rqst;
 
 #define	CPUF_PRIMARY	0x01		/* CPU is primary CPU */
 #define	CPUF_PRESENT	0x02		/* CPU is present */
 #define	CPUF_RUNNING	0x04		/* CPU is running */
 #define	CPUF_PAUSED	0x08		/* CPU is paused */
 #define	CPUF_FPUSAVE	0x10		/* CPU is currently in fpusave_cpu() */
+#define	CPUF_USERPMAP	0x20		/* CPU has a user pmap activated */
 #endif
 };
 

Index: src/sys/arch/mips/include/pmap.h
diff -u src/sys/arch/mips/include/pmap.h:1.54.26.11 src/sys/arch/mips/include/pmap.h:1.54.26.12
--- src/sys/arch/mips/include/pmap.h:1.54.26.11	Sat Feb 27 07:58:52 2010
+++ src/sys/arch/mips/include/pmap.h	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.h,v 1.54.26.11 2010/02/27 07:58:52 matt Exp $	*/
+/*	$NetBSD: pmap.h,v 1.54.26.12 2010/03/11 08:19:01 matt Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -179,10 +179,10 @@
 };
 
 struct pmap_tlb_info {
+	char ti_name[8];
 	uint32_t ti_asid_hint;		/* probable next ASID to use */
 	uint32_t ti_asids_free;		/* # of ASIDs free */
 #define	tlbinfo_noasids_p(ti)	((ti)->ti_asids_free == 0)
-	u_long ti_asid_bitmap[MIPS_TLB_NUM_PIDS / (sizeof(u_long) * 8)];
 	kmutex_t *ti_lock;
 	u_int ti_wired;			/* # of wired TLB entries */
 	uint32_t ti_asid_mask;
@@ -190,13 +190,21 @@
 	LIST_HEAD(, pmap_asid_info) ti_pais; /* list of active ASIDs */
 #ifdef MULTIPROCESSOR
 	pmap_t ti_victim;
+	uint32_t ti_synci_page_bitmap;	/* page indices needing a syncicache */
 	uint32_t ti_cpu_mask;		/* bitmask of CPUs sharing this TLB */
 	enum tlb_invalidate_op ti_tlbinvop;
 	u_int ti_index;
 #define tlbinfo_index(ti)	((ti)->ti_index)
+	struct evcnt ti_evcnt_synci_asts;
+	struct evcnt ti_evcnt_synci_all;
+	struct evcnt ti_evcnt_synci_pages;
+	struct evcnt ti_evcnt_synci_deferred;
+	struct evcnt ti_evcnt_synci_desired;
+	struct evcnt ti_evcnt_synci_duplicate;
 #else
 #define tlbinfo_index(ti)	(0)
 #endif
+	u_long ti_asid_bitmap[256 / (sizeof(u_long) * 8)];
 };
 
 
@@ -211,6 +219,10 @@
 
 extern struct pmap_kernel kernel_pmap_store;
 extern struct pmap_tlb_info pmap_tlb0_info;
+#ifdef MULTIPROCESSOR
+extern struct pmap_tlb_info *pmap_tlbs[MAXCPUS];
+extern u_int pmap_ntlbs;
+#endif
 extern paddr_t mips_avail_start;
 extern paddr_t mips_avail_end;
 extern vaddr_t mips_virtual_end;
@@ -221,17 +233,12 @@
 
 #define pmap_phys_address(x)	mips_ptob(x)
 
-static __inline void
-pmap_remove_all(struct pmap *pmap)
-{
-	/* Nothing. */
-}
-
 /*
  *	Bootstrap the system enough to run with virtual memory.
  */
 void	pmap_bootstrap(void);
 
+void	pmap_remove_all(pmap_t);
 void	pmap_set_modified(paddr_t);
 void	pmap_procwr(struct proc *, vaddr_t, size_t);
 #define	PMAP_NEED_PROCWR
@@ -240,6 +247,9 @@
 void	pmap_tlb_shootdown_process(void);
 bool	pmap_tlb_shootdown_bystanders(pmap_t pmap);
 void	pmap_tlb_info_attach(struct pmap_tlb_info *, struct cpu_info *);
+void	pmap_tlb_syncicache_ast(struct cpu_info *);
+void	pmap_tlb_syncicache_wanted(struct cpu_info *);
+void	pmap_tlb_syncicache(vaddr_t, uint32_t);
 #endif
 void	pmap_tlb_info_init(struct pmap_tlb_info *);
 void	pmap_tlb_asid_acquire(pmap_t pmap, struct lwp *l);

Index: src/sys/arch/mips/include/vmparam.h
diff -u src/sys/arch/mips/include/vmparam.h:1.41.28.12 src/sys/arch/mips/include/vmparam.h:1.41.28.13
--- src/sys/arch/mips/include/vmparam.h:1.41.28.12	Tue Feb 23 20:33:47 2010
+++ src/sys/arch/mips/include/vmparam.h	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: vmparam.h,v 1.41.28.12 2010/02/23 20:33:47 matt Exp $	*/
+/*	$NetBSD: vmparam.h,v 1.41.28.13 2010/03/11 08:19:01 matt Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -251,8 +251,8 @@
 	u_int pvh_attrs;		/* page attributes */
 #define	VM_PAGE_PVLIST_LOCK_INIT(pg)	do { } while (/*CONSTCOND*/ 0)
 #define	VM_PAGE_PVLIST_LOCKED_P(pg)	true
-#define	VM_PAGE_PVLIST_LOCK(pg, lc)	(0)
-#define	VM_PAGE_PVLIST_UNLOCK(pg)	do { } while (/*CONSTCOND*/ 0)
+#define	VM_PAGE_PVLIST_LOCK(pg, lc)	(mutex_spin_enter(&pmap_pvlist_mutex), 0)
+#define	VM_PAGE_PVLIST_UNLOCK(pg)	mutex_spin_exit(&pmap_pvlist_mutex)
 #define	VM_PAGE_PVLIST_GEN(pg)		(0)
 #endif
 };

Index: src/sys/arch/mips/mips/cpu_subr.c
diff -u src/sys/arch/mips/mips/cpu_subr.c:1.1.2.3 src/sys/arch/mips/mips/cpu_subr.c:1.1.2.4
--- src/sys/arch/mips/mips/cpu_subr.c:1.1.2.3	Mon Mar  1 23:54:49 2010
+++ src/sys/arch/mips/mips/cpu_subr.c	Thu Mar 11 08:19:01 2010
@@ -32,7 +32,7 @@
 #include "opt_multiprocessor.h"
 #include "opt_sa.h"
 
-__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.1.2.3 2010/03/01 23:54:49 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.1.2.4 2010/03/11 08:19:01 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -186,6 +186,18 @@
 		cpu_info_last->ci_next = ci;
 		cpu_info_last = ci;
 	}
+	evcnt_attach_dynamic(&ci->ci_evcnt_synci_activate_rqst,
+	    EVCNT_TYPE_MISC, NULL, device_xname(self),
+	    "syncicache activate request");
+	evcnt_attach_dynamic(&ci->ci_evcnt_synci_deferred_rqst,
+	    EVCNT_TYPE_MISC, NULL, device_xname(self),
+	    "syncicache deferred request");
+	evcnt_attach_dynamic(&ci->ci_evcnt_synci_ipi_rqst,
+	    EVCNT_TYPE_MISC, NULL, device_xname(self),
+	    "syncicache ipi request");
+	evcnt_attach_dynamic(&ci->ci_evcnt_synci_onproc_rqst,
+	    EVCNT_TYPE_MISC, NULL, device_xname(self),
+	    "syncicache onproc request");
 
 	/*
 	 * Initialize IPI framework for this cpu instance
@@ -472,7 +484,7 @@
 	KASSERT(lwp_locked(l, NULL));
 	KASSERT(l->l_stat == LSONPROC || l->l_stat == LSRUN);
 
-	l->l_md.md_astpending = 1;		/* force call to ast() */
+	l->l_md.md_astpending = 1; 		/* force call to ast() */
 }
 
 void

Index: src/sys/arch/mips/mips/pmap.c
diff -u src/sys/arch/mips/mips/pmap.c:1.179.16.21 src/sys/arch/mips/mips/pmap.c:1.179.16.22
--- src/sys/arch/mips/mips/pmap.c:1.179.16.21	Sun Feb 28 23:45:06 2010
+++ src/sys/arch/mips/mips/pmap.c	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.179.16.21 2010/02/28 23:45:06 matt Exp $	*/
+/*	$NetBSD: pmap.c,v 1.179.16.22 2010/03/11 08:19:01 matt Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.179.16.21 2010/02/28 23:45:06 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.179.16.22 2010/03/11 08:19:01 matt Exp $");
 
 /*
  *	Manages physical address maps.
@@ -113,8 +113,13 @@
 
 #include "opt_sysv.h"
 #include "opt_cputype.h"
+#include "opt_multiprocessor.h"
 #include "opt_mips_cache.h"
 
+#ifdef MULTIPROCESSOR
+#define PMAP_NO_PV_UNCACHED
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
@@ -253,7 +258,9 @@
 #define	PMAP_SIZE	offsetof(struct pmap, pm_pai[MAXCPUS])
 #else
 #define	PMAP_SIZE	sizeof(struct pmap)
+kmutex_t pmap_pvlist_mutex __aligned(COHERENCY_UNIT);
 #endif
+
 struct pmap_kernel kernel_pmap_store = {
 	.kernel_pmap = {
 		.pm_count = 1,
@@ -281,9 +288,7 @@
 } poolpage;
 #endif
 
-#ifdef MULTIPROCESSOR
 static void pmap_pvlist_lock_init(void);
-#endif
 
 /*
  * The pools from which pmap structures and sub-structures are allocated.
@@ -365,6 +370,22 @@
 static inline void
 pmap_page_syncicache(struct vm_page *pg)
 {
+#ifdef MULTIPROCESSOR
+	pv_entry_t pv = &pg->mdpage.pvh_first;
+	uint32_t onproc = 0;
+	(void)VM_PAGE_PVLIST_LOCK(pg, false);
+	if (pv->pv_pmap != NULL) {
+		for (; pv != NULL; pv = pv->pv_next) {
+			onproc |= pv->pv_pmap->pm_onproc;
+			if (onproc == cpus_running)
+				break;
+		}
+	}
+	VM_PAGE_PVLIST_UNLOCK(pg);
+	kpreempt_disable();
+	pmap_tlb_syncicache(pg->mdpage.pvh_first.pv_va, onproc);
+	kpreempt_enable();
+#else
 	if (MIPS_HAS_R4K_MMU) {
 		if (PG_MD_CACHED_P(pg)) {
 			mips_icache_sync_range_index(
@@ -374,6 +395,7 @@
 		mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(pg)),
 		    PAGE_SIZE);
 	}
+#endif
 }
 
 static vaddr_t
@@ -514,9 +536,7 @@
 		    (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / NBPG;
 	}
 #endif
-#ifdef MULTIPROCESSOR
 	pmap_pvlist_lock_init();
-#endif
 
 	/*
 	 * Now actually allocate the kernel PTE array (must be done
@@ -809,10 +829,12 @@
 
 	PMAP_COUNT(activate);
 
+	kpreempt_disable();
 	pmap_tlb_asid_acquire(pmap, l);
 	if (l == curlwp) {
 		pmap_segtab_activate(pmap, l);
 	}
+	kpreempt_enable();
 }
 
 /*
@@ -825,6 +847,7 @@
 
 #ifdef MULTIPROCESSOR
 	kpreempt_disable();
+	curcpu()->ci_pmap_segbase = (void *)(MIPS_KSEG2_START + 0x1eadbeef);
 	pmap_tlb_asid_deactivate(l->l_proc->p_vmspace->vm_map.pmap);
 	kpreempt_enable();
 #endif
@@ -861,6 +884,7 @@
 		   __func__, pmap, sva, eva, pte, flags);
 	}
 #endif
+	KASSERT(kpreempt_disabled());
 
 	for (; sva < eva; sva += NBPG, pte++) {
 		struct vm_page *pg;
@@ -983,12 +1007,13 @@
 		 */
 		if (pv->pv_pmap != NULL) {
 			while (pv != NULL) {
-				const uint32_t gen = VM_PAGE_PVLIST_GEN(pg);
+				const pmap_t pmap = pv->pv_pmap;
+				const uint16_t gen = VM_PAGE_PVLIST_GEN(pg);
 				va = pv->pv_va;
 				VM_PAGE_PVLIST_UNLOCK(pg);
-				pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE,
-				    prot);
-				pmap_update(pv->pv_pmap);
+				pmap_protect(pmap, va, va + PAGE_SIZE, prot);
+				KASSERT(pv->pv_pmap == pmap);
+				pmap_update(pmap);
 				if (gen != VM_PAGE_PVLIST_LOCK(pg, false)) {
 					pv = &pg->mdpage.pvh_first;
 				} else {
@@ -1011,10 +1036,11 @@
 		(void)VM_PAGE_PVLIST_LOCK(pg, false);
 		pv = &pg->mdpage.pvh_first;
 		while (pv->pv_pmap != NULL) {
+			const pmap_t pmap = pv->pv_pmap;
 			va = pv->pv_va;
 			VM_PAGE_PVLIST_UNLOCK(pg);
-			pmap_remove(pv->pv_pmap, va, va + PAGE_SIZE);
-			pmap_update(pv->pv_pmap);
+			pmap_remove(pmap, va, va + PAGE_SIZE);
+			pmap_update(pmap);
 			(void)VM_PAGE_PVLIST_LOCK(pg, false);
 		}
 		VM_PAGE_PVLIST_UNLOCK(pg);
@@ -1027,6 +1053,7 @@
 {
 	const uint32_t pg_mask = ~(mips_pg_m_bit() | mips_pg_ro_bit());
 	const uint32_t p = (flags & VM_PROT_WRITE) ? mips_pg_rw_bit() : mips_pg_ro_bit();
+	KASSERT(kpreempt_disabled());
 	/*
 	 * Change protection on every valid mapping within this segment.
 	 */
@@ -1083,6 +1110,7 @@
 
 	p = (prot & VM_PROT_WRITE) ? mips_pg_rw_bit() : mips_pg_ro_bit();
 
+	kpreempt_disable();
 	if (pmap == pmap_kernel()) {
 		/*
 		 * Change entries in kernel pmap.
@@ -1107,6 +1135,7 @@
 			pte->pt_entry = pt_entry;
 			pmap_tlb_update_addr(pmap, sva, pt_entry, true);
 		}
+		kpreempt_enable();
 		return;
 	}
 
@@ -1129,7 +1158,6 @@
 	/*
 	 * Change protection on every valid mapping within this segment.
 	 */
-	kpreempt_disable();
 	pmap_pte_process(pmap, sva, eva, pmap_pte_protect, p);
 	kpreempt_enable();
 }
@@ -1209,6 +1237,7 @@
 {
 	const uint32_t newmode = cached ? MIPS3_PG_CACHED : MIPS3_PG_UNCACHED;
 
+	KASSERT(kpreempt_disabled());
 #ifdef DEBUG
 	if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))
 		printf("pmap_page_uncache(%#"PRIxPADDR")\n", VM_PAGE_TO_PHYS(pg));
@@ -1402,6 +1431,7 @@
 #endif
 #endif
 
+	kpreempt_disable();
 	if (pmap == pmap_kernel()) {
 		if (pg)
 			pmap_enter_pv(pmap, va, pg, &npte);
@@ -1432,12 +1462,11 @@
 		/*
 		 * Update the same virtual address entry.
 		 */
-
 		pmap_tlb_update_addr(pmap, va, npte, resident);
+		kpreempt_enable();
 		return 0;
 	}
 
-	kpreempt_disable();
 	pte = pmap_pte_reserve(pmap, va, flags);
 	if (__predict_false(pte == NULL)) {
 		kpreempt_enable();
@@ -1593,6 +1622,20 @@
 	kpreempt_enable();
 }
 
+void
+pmap_remove_all(struct pmap *pmap)
+{
+	KASSERT(pmap != pmap_kernel());
+
+	kpreempt_disable();
+	/*
+	 * Free all of our ASIDs which means we can skip doing all the
+	 * tlb_invalidate_addrs().
+	 */
+	pmap_tlb_asid_deactivate(pmap);
+	pmap_tlb_asid_release_all(pmap);
+	kpreempt_enable();
+}
 /*
  *	Routine:	pmap_unwire
  *	Function:	Clear the wired attribute for a map/virtual-address
@@ -1665,7 +1708,6 @@
 	if (pmapdebug & PDB_FOLLOW)
 		printf("pmap_extract(%p, %#"PRIxVADDR") -> ", pmap, va);
 #endif
-	kpreempt_disable();
 	if (pmap == pmap_kernel()) {
 		if (MIPS_KSEG0_P(va)) {
 			pa = MIPS_KSEG0_TO_PHYS(va);
@@ -1681,9 +1723,12 @@
 		if (MIPS_KSEG1_P(va))
 			panic("pmap_extract: kseg1 address %#"PRIxVADDR"", va);
 #endif
-		else
-			pte = kvtopte(va);
+		if (va >= mips_virtual_end)
+			panic("pmap_extract: illegal kernel mapped address %#"PRIxVADDR"", va);
+		pte = kvtopte(va);
+		kpreempt_disable();
 	} else {
+		kpreempt_disable();
 		if (!(pte = pmap_pte_lookup(pmap, va))) {
 #ifdef DEBUG
 			if (pmapdebug & PDB_FOLLOW)
@@ -1702,11 +1747,11 @@
 		return false;
 	}
 	pa = mips_tlbpfn_to_paddr(pte->pt_entry) | (va & PGOFSET);
+	kpreempt_enable();
 done:
 	if (pap != NULL) {
 		*pap = pa;
 	}
-	kpreempt_enable();
 #ifdef DEBUG
 	if (pmapdebug & PDB_FOLLOW)
 		printf("pa %#"PRIxPADDR"\n", pa);
@@ -1968,7 +2013,9 @@
 pmap_enter_pv(pmap_t pmap, vaddr_t va, struct vm_page *pg, u_int *npte)
 {
 	pv_entry_t pv, npv, apv;
+	int16_t gen;
 
+        KASSERT(kpreempt_disabled());
         KASSERT(!MIPS_KSEG0_P(va));
         KASSERT(!MIPS_KSEG1_P(va));
 #ifdef _LP64
@@ -1982,8 +2029,7 @@
 		printf("pmap_enter: pv %p: was %#"PRIxVADDR"/%p/%p\n",
 		    pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
 #endif
-	kpreempt_disable();
-	(void)VM_PAGE_PVLIST_LOCK(pg, true);
+	gen = VM_PAGE_PVLIST_LOCK(pg, true);
 	pmap_check_pvlist(pg);
 #if defined(MIPS3_NO_PV_UNCACHED) || defined(MULTIPROCESSOR)
 again:
@@ -2093,7 +2139,6 @@
 #endif
 				PMAP_COUNT(remappings);
 				VM_PAGE_PVLIST_UNLOCK(pg);
-				kpreempt_enable();
 				if (__predict_false(apv != NULL))
 					pmap_pv_free(apv);
 				return;
@@ -2111,7 +2156,6 @@
 			 * so get the page generation.  We allocate the PV, and
 			 * then reacquire the lock.  
 			 */
-			uint16_t gen = VM_PAGE_PVLIST_GEN(pg);
 			VM_PAGE_PVLIST_UNLOCK(pg);
 #endif
 			apv = (pv_entry_t)pmap_pv_alloc();
@@ -2123,7 +2167,9 @@
 			 * tinkered with this page so we should
 			 * start over.
 			 */
-			if (gen != VM_PAGE_PVLIST_LOCK(pg, true))
+			uint16_t oldgen = gen;
+			gen = VM_PAGE_PVLIST_LOCK(pg, true);
+			if (gen != oldgen)
 				goto again;
 #endif
 		}
@@ -2137,7 +2183,6 @@
 	}
 	pmap_check_pvlist(pg);
 	VM_PAGE_PVLIST_UNLOCK(pg);
-	kpreempt_enable();
 	if (__predict_false(apv != NULL))
 		pmap_pv_free(apv);
 }
@@ -2160,7 +2205,7 @@
 		printf("pmap_remove_pv(%p, %#"PRIxVADDR", %#"PRIxPADDR")\n", pmap, va,
 		    VM_PAGE_TO_PHYS(pg));
 #endif
-
+	KASSERT(kpreempt_disabled());
 	pv = &pg->mdpage.pvh_first;
 
 	(void)VM_PAGE_PVLIST_LOCK(pg, true);
@@ -2317,6 +2362,12 @@
 	 */
 	return gen;
 }
+#else
+static void
+pmap_pvlist_lock_init(void)
+{
+	mutex_init(&pmap_pvlist_mutex, MUTEX_DEFAULT, IPL_VM);
+}
 #endif /* MULTIPROCESSOR */
 
 /*

Index: src/sys/arch/mips/mips/pmap_tlb.c
diff -u src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.9 src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.10
--- src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.9	Mon Mar  1 23:53:26 2010
+++ src/sys/arch/mips/mips/pmap_tlb.c	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap_tlb.c,v 1.1.2.9 2010/03/01 23:53:26 matt Exp $	*/
+/*	$NetBSD: pmap_tlb.c,v 1.1.2.10 2010/03/11 08:19:01 matt Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.1.2.9 2010/03/01 23:53:26 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.1.2.10 2010/03/11 08:19:01 matt Exp $");
 
 /*
  * Manages address spaces in a TLB.
@@ -144,6 +144,7 @@
 static kmutex_t pmap_tlb0_mutex __aligned(32);
 
 struct pmap_tlb_info pmap_tlb0_info = {
+	.ti_name = "tlb0",
 	.ti_asid_hint = 1,
 	.ti_asid_mask = MIPS_TLB_NUM_PIDS - 1,
 	.ti_asid_max = MIPS_TLB_NUM_PIDS - 1,
@@ -159,10 +160,12 @@
 };
 
 #ifdef MULTIPROCESSOR
-static struct pmap_tlb_info *pmap_tlbs[MAXCPUS] = {
+struct pmap_tlb_info *pmap_tlbs[MAXCPUS] = {
 	[0] = &pmap_tlb0_info,
 };
-static u_int pmap_ntlbs = 1;
+u_int pmap_ntlbs = 1;
+u_int pmap_tlb_synci_page_mask;
+u_int pmap_tlb_synci_map_mask;
 #endif
 #define	__BITMAP_SET(bm, n) \
 	((bm)[(n) / (8*sizeof(bm[0]))] |= 1LU << ((n) % (8*sizeof(bm[0]))))
@@ -211,6 +214,31 @@
 #endif /* MULTIPROCESSOR */
 }
 
+static void
+pmap_tlb_attach_evcnt(struct pmap_tlb_info *ti)
+{
+#ifdef MULTIPROCESSOR
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_desired,
+	    EVCNT_TYPE_MISC, NULL,
+	    ti->ti_name, "icache syncs desired");
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_asts,
+	    EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired,
+	    ti->ti_name, "icache sync asts");
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_all,
+	    EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_asts,
+	    ti->ti_name, "iacche full syncs");
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_pages,
+	    EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_asts,
+	    ti->ti_name, "icache pages synced");
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_duplicate,
+	    EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired,
+	    ti->ti_name, "icache dup pages skipped");
+	evcnt_attach_dynamic(&ti->ti_evcnt_synci_deferred,
+	    EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired,
+	    ti->ti_name, "icache pages deferred");
+#endif /* MULTIPROCESSOR */
+}
+
 void
 pmap_tlb_info_init(struct pmap_tlb_info *ti)
 {
@@ -231,6 +259,17 @@
 				ti->ti_asid_mask |= ti->ti_asid_mask >> 1;
 			}
 		}
+#ifdef MULTIPROCESSOR
+		const u_int icache_way_pages =
+			mips_cache_info.mci_picache_way_size >> PGSHIFT; 
+		KASSERT(icache_way_pages <= 8*sizeof(pmap_tlb_synci_page_mask));
+		pmap_tlb_synci_page_mask = icache_way_pages - 1;
+		pmap_tlb_synci_map_mask = ~(~0 << icache_way_pages);
+		printf("tlb0: synci page mask %#x and map mask %#x used for %u pages\n", 
+		    pmap_tlb_synci_page_mask, pmap_tlb_synci_map_mask,
+		    icache_way_pages);
+#endif
+		pmap_tlb_attach_evcnt(ti);
 		return;
 #ifdef MULTIPROCESSOR
 	}
@@ -247,6 +286,10 @@
 	ti->ti_victim = NULL;
 	ti->ti_cpu_mask = 0;
 	ti->ti_index = pmap_ntlbs++;
+	snprintf(ti->ti_name, sizeof(ti->ti_name), "tlb%u", ti->ti_index);
+
+	pmap_tlb_attach_evcnt(ti);
+
 	/*
 	 * If we are reserving a tlb slot for mapping cpu_info,
 	 * allocate it now.
@@ -299,6 +342,8 @@
 static void
 pmap_tlb_asid_reinitialize(struct pmap_tlb_info *ti, enum tlb_invalidate_op op)
 {
+	const size_t asid_bitmap_words =
+	    ti->ti_asid_max / (8 * sizeof(ti->ti_asid_bitmap[0]));
 	/*
 	 * First, clear the ASID bitmap (except for ASID 0 which belongs
 	 * to the kernel).
@@ -306,8 +351,8 @@
 	ti->ti_asids_free = ti->ti_asid_max;
 	ti->ti_asid_hint = 1;
 	ti->ti_asid_bitmap[0] = 1;
-	for (size_t i = 1; i < __arraycount(ti->ti_asid_bitmap); i++)
-		ti->ti_asid_bitmap[i] = 0;
+	for (size_t word = 1; word <= asid_bitmap_words; word++)
+		ti->ti_asid_bitmap[word] = 0;
 
 	switch (op) {
 	case TLBINV_ALL:
@@ -332,11 +377,8 @@
 		if (__predict_false(asids_found >= ti->ti_asid_max / 2)) {
 			tlb_invalidate_asids(1, ti->ti_asid_mask);
 			ti->ti_asid_bitmap[0] = 1;
-			for (size_t i = 1;
-			     i < __arraycount(ti->ti_asid_bitmap);
-			     i++) {
-				ti->ti_asid_bitmap[i] = 0;
-			}
+			for (size_t word = 1; word <= asid_bitmap_words; word++)
+				ti->ti_asid_bitmap[word] = 0;
 		} else {
 			ti->ti_asids_free -= asids_found;
 		}
@@ -385,6 +427,9 @@
 {
 	struct cpu_info * const ci = curcpu();
 	struct pmap_tlb_info * const ti = ci->ci_tlb_info;
+#ifdef DIAGNOSTIC
+	struct pmap * const curpmap = curlwp->l_proc->p_vmspace->vm_map.pmap;
+#endif
 
 	TLBINFO_LOCK(ti);
 
@@ -409,7 +454,7 @@
 			 * next called for this pmap, it will allocate a new
 			 * ASID.
 			 */
-			KASSERT((curlwp->l_proc->p_vmspace->vm_map.pmap->pm_onproc & ti->ti_cpu_mask) == 0);
+			KASSERT((curpmap->pm_onproc & ti->ti_cpu_mask) == 0);
 			pmap_pai_reset(ti, pai, PAI_PMAP(pai, ti));
 		}
 		break;
@@ -559,6 +604,8 @@
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 	int rv = -1;
 
+	KASSERT(kpreempt_disabled());
+
 	TLBINFO_LOCK(ti);
 	if (pm == pmap_kernel() || PMAP_PAI_ASIDVALID_P(pai, ti)) {
 		va |= pai->pai_asid << MIPS_TLB_PID_SHIFT;
@@ -578,6 +625,8 @@
 	struct pmap_tlb_info * const ti = curcpu()->ci_tlb_info;
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 
+	KASSERT(kpreempt_disabled());
+
 	TLBINFO_LOCK(ti);
 	if (pm == pmap_kernel() || PMAP_PAI_ASIDVALID_P(pai, ti)) {
 		va |= pai->pai_asid << MIPS_TLB_PID_SHIFT;
@@ -611,17 +660,14 @@
 	 * a new one.
 	 */
 	if (__predict_false(TLBINFO_ASID_INUSE_P(ti, ti->ti_asid_hint))) {
-#ifdef DIAGNOSTIC
-		const size_t words = __arraycount(ti->ti_asid_bitmap);
-#endif
 		const size_t nbpw = 8 * sizeof(ti->ti_asid_bitmap[0]);
 		for (size_t i = 0; i < ti->ti_asid_hint / nbpw; i++) {
 			KASSERT(~ti->ti_asid_bitmap[i] == 0);
 		}
 		for (size_t i = ti->ti_asid_hint / nbpw;; i++) {
-			KASSERT(i < words);
+			KASSERT(i <= ti->ti_asid_max / nbpw);
 			/*
-			 * ffs was to find the first bit set while we want the
+			 * ffs wants to find the first bit set while we want
 			 * to find the first bit cleared.
 			 */
 			u_long bits = ~ti->ti_asid_bitmap[i];
@@ -674,6 +720,8 @@
 	struct pmap_tlb_info * const ti = ci->ci_tlb_info;
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 
+	KASSERT(kpreempt_disabled());
+
 	/*
 	 * Kernels use a fixed ASID of 0 and don't need to acquire one.
 	 */
@@ -703,7 +751,17 @@
 		 * be changed while this TLBs lock is held.
 		 */
 		atomic_or_32(&pm->pm_onproc, 1 << cpu_index(ci));
-#endif
+		/*
+		 * If this CPU has had exec pages changes that haven't been
+		 * icache synched, make sure to do that before returning to
+		 * userland.
+		 */
+		if (ti->ti_synci_page_bitmap) {
+			l->l_md.md_astpending = 1; /* force call to ast() */
+			ci->ci_evcnt_synci_activate_rqst.ev_count++;
+		}
+		atomic_or_ulong(&ci->ci_flags, CPUF_USERPMAP);
+#endif /* MULTIPROCESSOR */
 		tlb_set_asid(pai->pai_asid);
 	}
 	TLBINFO_UNLOCK(ti);
@@ -721,6 +779,7 @@
 void
 pmap_tlb_asid_deactivate(pmap_t pm)
 {
+	KASSERT(kpreempt_disabled());
 #ifdef MULTIPROCESSOR
 	/*
 	 * The kernel pmap is aways onproc and active and must never have
@@ -736,6 +795,7 @@
 		 */
 		atomic_and_32(&pm->pm_onproc, ~(1 << cpu_index(ci)));
 		TLBINFO_UNLOCK(ti);
+		atomic_and_ulong(&ci->ci_flags, ~CPUF_USERPMAP);
 	}
 #endif
 }
@@ -759,3 +819,157 @@
 	}
 #endif /* MULTIPROCESSOR */
 }
+
+#ifdef MULTIPROCESSOR
+void
+pmap_tlb_syncicache_ast(struct cpu_info *ci)
+{
+	struct pmap_tlb_info * const ti = ci->ci_tlb_info;
+
+	kpreempt_disable();
+	uint32_t page_bitmap = atomic_swap_32(&ti->ti_synci_page_bitmap, 0);
+#if 0
+	printf("%s: need to sync %#x\n", __func__, page_bitmap);
+#endif
+	ti->ti_evcnt_synci_asts.ev_count++;
+	/*
+	 * If every bit is set in the bitmap, sync the entire icache.
+	 */
+	if (page_bitmap == pmap_tlb_synci_map_mask) {
+		mips_icache_sync_all();
+		ti->ti_evcnt_synci_all.ev_count++;
+		ti->ti_evcnt_synci_pages.ev_count += pmap_tlb_synci_page_mask+1;
+		kpreempt_enable();
+		return;
+	}
+
+	/*
+	 * Loop through the bitmap clearing each set of indices for each page.
+	 */
+	for (vaddr_t va = 0;
+	     page_bitmap != 0;
+	     page_bitmap >>= 1, va += PAGE_SIZE) {
+		if (page_bitmap & 1) {
+			/*
+			 * Each bit set represents a page to be synced.
+			 */
+			mips_icache_sync_range_index(va, PAGE_SIZE);
+			ti->ti_evcnt_synci_pages.ev_count++;
+		}
+	}
+
+	kpreempt_enable();
+}
+
+void
+pmap_tlb_syncicache(vaddr_t va, uint32_t page_onproc)
+{
+	KASSERT(kpreempt_disabled());
+	/*
+	 * We don't sync the icache here but let ast do it for us just before
+	 * returning to userspace.  We do this because we don't really know
+	 * on which CPU we will return to userspace and if we synch the icache
+	 * now it might not be on the CPU we need it on.  In addition, others
+	 * threads might sync the icache before we get to return to userland
+	 * so there's no reason for us to do it.
+	 *
+	 * Each TLB/cache keeps a synci sequence number which gets advanced
+	 * each that TLB/cache performs a mips_sync_icache_all.  When we
+	 * return to userland, we check the pmap's corresponding synci
+	 * sequence number for that TLB/cache.  If they match, it means that
+	 * no one has yet synched the icache so we much do it ourselves.  If
+	 * they don't match someone has already synced the icache for us.
+	 *
+	 * There is a small chance that the generation numbers will wrap and
+	 * then become equal but that's a one in 4 billion cache and will
+	 * just cause an extra sync of the icache.
+	 */
+	const uint32_t cpu_mask = 1L << cpu_index(curcpu());
+	const uint32_t page_mask =
+	    1L << ((va >> PGSHIFT) & pmap_tlb_synci_page_mask);
+	uint32_t onproc = 0;
+	for (size_t i = 0; i < pmap_ntlbs; i++) {
+		struct pmap_tlb_info * const ti = pmap_tlbs[0];
+		TLBINFO_LOCK(ti);
+		for (;;) {
+			uint32_t old_page_bitmap = ti->ti_synci_page_bitmap;
+			if (old_page_bitmap & page_mask) {
+				ti->ti_evcnt_synci_duplicate.ev_count++;
+				break;
+			}
+
+			uint32_t orig_page_bitmap = atomic_cas_32(
+			    &ti->ti_synci_page_bitmap, old_page_bitmap,
+			    old_page_bitmap | page_mask);
+
+			if (orig_page_bitmap == old_page_bitmap) {
+				if (old_page_bitmap == 0) {
+					onproc |= ti->ti_cpu_mask;
+				} else {
+					ti->ti_evcnt_synci_deferred.ev_count++;
+				}
+				ti->ti_evcnt_synci_desired.ev_count++;
+				break;
+			}
+		}
+#if 0
+		printf("%s: %s: %x to %x on cpus %#x\n", __func__,
+		    ti->ti_name, page_mask, ti->ti_synci_page_bitmap,
+		     onproc & page_onproc & ti->ti_cpu_mask);
+#endif
+		TLBINFO_UNLOCK(ti);
+	}
+	onproc &= page_onproc;
+	if (__predict_false(onproc != 0)) {
+		/*
+		 * If the cpu need to sync this page, tell the current lwp
+		 * to sync the icache before it returns to userspace.
+		 */
+		if (onproc & cpu_mask) {
+			if (curcpu()->ci_flags & CPUF_USERPMAP) {
+				curlwp->l_md.md_astpending = 1;	/* force call to ast() */
+				curcpu()->ci_evcnt_synci_onproc_rqst.ev_count++;
+			} else {
+				curcpu()->ci_evcnt_synci_deferred_rqst.ev_count++;
+			}
+			onproc ^= cpu_mask;
+		}
+
+		/*
+		 * For each cpu that is affect, send an IPI telling
+		 * that CPU that the current thread needs to sync its icache.
+		 * We might cause some spurious icache syncs but that's not
+		 * going to break anything.
+		 */
+		for (u_int n = ffs(onproc);
+		     onproc != 0;
+		     onproc >>= n, onproc <<= n, n = ffs(onproc)) {
+			cpu_send_ipi(cpu_lookup(n-1), IPI_SYNCICACHE);
+		}
+	}
+}
+
+void
+pmap_tlb_syncicache_wanted(struct cpu_info *ci)
+{
+	struct pmap_tlb_info * const ti = ci->ci_tlb_info;
+
+	KASSERT(cpu_intr_p());
+
+	TLBINFO_LOCK(ti);
+
+	/*
+	 * We might have been notified because another CPU changed an exec
+	 * page and now needs us to sync the icache so tell the current lwp
+	 * to do the next time it returns to userland (which should be very
+	 * soon).
+	 */
+	if (ti->ti_synci_page_bitmap && (ci->ci_flags & CPUF_USERPMAP)) {
+		curlwp->l_md.md_astpending = 1;	/* force call to ast() */
+		ci->ci_evcnt_synci_ipi_rqst.ev_count++;
+	}
+
+	TLBINFO_UNLOCK(ti);
+
+}
+#endif /* MULTIPROCESSOR */

Index: src/sys/arch/mips/mips/trap.c
diff -u src/sys/arch/mips/mips/trap.c:1.217.12.21 src/sys/arch/mips/mips/trap.c:1.217.12.22
--- src/sys/arch/mips/mips/trap.c:1.217.12.21	Sun Feb 28 23:45:06 2010
+++ src/sys/arch/mips/mips/trap.c	Thu Mar 11 08:19:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.217.12.21 2010/02/28 23:45:06 matt Exp $	*/
+/*	$NetBSD: trap.c,v 1.217.12.22 2010/03/11 08:19:01 matt Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -78,7 +78,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.217.12.21 2010/02/28 23:45:06 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.217.12.22 2010/03/11 08:19:01 matt Exp $");
 
 #include "opt_cputype.h"	/* which mips CPU levels do we support? */
 #include "opt_ddb.h"
@@ -312,7 +312,8 @@
 			panic("utlbmod: no pte");
 		pt_entry = pte->pt_entry;
 		if (!mips_pg_v(pt_entry))
-			panic("utlbmod: invalid pte");
+			panic("utlbmod: va %"PRIxVADDR" invalid pte %08x @ %p",
+			    vaddr, pt_entry, pte);
 		if (pt_entry & mips_pg_ro_bit()) {
 			/* write to read only page */
 			ftype = VM_PROT_WRITE;
@@ -604,13 +605,20 @@
 void
 ast(void)
 {
-	struct lwp *l = curlwp;
-	struct cpu_info *ci = l->l_cpu;
+	struct lwp * const l = curlwp;
+	struct cpu_info * const ci = l->l_cpu;
+	u_int astpending;
 
-	while (l->l_md.md_astpending) {
+	while ((astpending = l->l_md.md_astpending) != 0) {
 		uvmexp.softs++;
 		l->l_md.md_astpending = 0;
 
+#ifdef MULTIPROCESSOR
+		if (ci->ci_tlb_info->ti_synci_page_bitmap != 0)
+			pmap_tlb_syncicache_ast(ci);
+		KASSERT(ci->ci_tlb_info->ti_synci_page_bitmap == 0);
+#endif
+
 		if (l->l_pflag & LP_OWEUPC) {
 			l->l_pflag &= ~LP_OWEUPC;
 			ADDUPROF(l);

Reply via email to