Module Name:    src
Committed By:   matt
Date:           Thu Feb 16 23:02:22 UTC 2012

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

Log Message:
Move the ksegx tlb init code into its own function.
Fix a problem with concurrent shootdowns by tracking what cpus want a
shootdown for a pmap, and if anoter cpu wants a shootdown, perform the
shootdown on ourselves.


To generate a diff of this commit:
cvs rdiff -u -r1.54.26.23 -r1.54.26.24 src/sys/arch/mips/include/pmap.h
cvs rdiff -u -r1.179.16.42 -r1.179.16.43 src/sys/arch/mips/mips/pmap.c
cvs rdiff -u -r1.1.2.22 -r1.1.2.23 src/sys/arch/mips/mips/pmap_tlb.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/pmap.h
diff -u src/sys/arch/mips/include/pmap.h:1.54.26.23 src/sys/arch/mips/include/pmap.h:1.54.26.24
--- src/sys/arch/mips/include/pmap.h:1.54.26.23	Thu Jan 19 08:28:48 2012
+++ src/sys/arch/mips/include/pmap.h	Thu Feb 16 23:02:21 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.h,v 1.54.26.23 2012/01/19 08:28:48 matt Exp $	*/
+/*	pmap.h,v 1.54.26.23 2012/01/19 08:28:48 matt Exp	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -180,7 +180,7 @@ typedef struct pmap {
 #ifdef MULTIPROCESSOR
 	volatile uint32_t	pm_active;	/* pmap was active on ... */
 	volatile uint32_t	pm_onproc;	/* pmap is active on ... */
-	volatile u_int		pm_shootdown_pending;
+	volatile uint32_t	pm_shootdown_pending;
 #endif
 	union segtab		*pm_segtab;	/* pointers to pages of PTEs */
 	u_int			pm_count;	/* pmap reference count */
@@ -254,6 +254,7 @@ extern vaddr_t mips_virtual_end;
  *	Bootstrap the system enough to run with virtual memory.
  */
 void	pmap_bootstrap(void);
+void	pmap_ksegx_bootstrap(void);
 
 void	pmap_remove_all(pmap_t);
 void	pmap_set_modified(paddr_t);
@@ -262,7 +263,7 @@ void	pmap_procwr(struct proc *, vaddr_t,
 
 #ifdef MULTIPROCESSOR
 void	pmap_tlb_shootdown_process(void);
-bool	pmap_tlb_shootdown_bystanders(pmap_t pmap);
+bool	pmap_tlb_shootdown_bystanders(pmap_t pmap, uint32_t);
 void	pmap_tlb_info_attach(struct pmap_tlb_info *, struct cpu_info *);
 #endif
 void	pmap_syncicache_page(struct vm_page *, uint32_t);

Index: src/sys/arch/mips/mips/pmap.c
diff -u src/sys/arch/mips/mips/pmap.c:1.179.16.42 src/sys/arch/mips/mips/pmap.c:1.179.16.43
--- src/sys/arch/mips/mips/pmap.c:1.179.16.42	Tue Feb 14 01:51:11 2012
+++ src/sys/arch/mips/mips/pmap.c	Thu Feb 16 23:02:22 2012
@@ -443,6 +443,37 @@ pmap_unmap_ephemeral_page(struct vm_page
 #endif
 }
 
+#ifdef ENABLE_MIPS_KSEGX
+void
+pmap_ksegx_bootstrap(void)
+{
+	const vaddr_t kva_inc = 1 << ((VM_KSEGX_SHIFT - 1) & ~1);
+	const uint32_t tlb_mask = (2 * kva_inc - 1) & 0x1ffffc00;
+
+	if (mips_ksegx_tlb_slot < 0) {
+		mips_ksegx_tlb_slot = pmap_tlb0_info.ti_wired;
+		pmap_tlb0_info.ti_wired += VM_KSEGX_SIZE / (2 * kva_inc);
+		mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
+	}
+
+	u_int tlb_slot = mips_ksegx_tlb_slot;
+	for (vaddr_t kva = 0;
+	     kva < VM_KSEGX_SIZE;
+	     kva += 2 * kva_inc, tlb_slot++) {
+		extern pt_entry_t mips_ksegx_pte;
+		struct tlbmask tlb = {
+		    .tlb_hi = VM_KSEGX_ADDRESS + kva,
+		    .tlb_lo0 = mips_ksegx_pte.pt_entry
+			+ mips_paddr_to_tlbpfn(kva),
+		    .tlb_lo1 = mips_ksegx_pte.pt_entry
+			+ mips_paddr_to_tlbpfn(kva + kva_inc),
+		    .tlb_mask = tlb_mask,
+		};
+		tlb_write_indexed(tlb_slot, &tlb);
+	}
+}
+#endif
+
 /*
  *	Bootstrap the system enough to run with virtual memory.
  *	firstaddr is the first unused kseg0 address (not page aligned).
@@ -460,22 +491,7 @@ pmap_bootstrap(void)
 	pmap_tlb_info_init(&pmap_tlb0_info);		/* init the lock */
 
 #ifdef ENABLE_MIPS_KSEGX
-	const vaddr_t kva_inc = 1 << ((VM_KSEGX_SHIFT - 1) & ~1);
-	const uint32_t tlb_mask = (2 * kva_inc - 1) & 0x1ffffc00;
-	for (vaddr_t kva = 0; kva < VM_KSEGX_SIZE; kva += 2 * kva_inc) {
-		extern pt_entry_t mips_ksegx_pte;
-		struct tlbmask tlb = {
-		    .tlb_hi = VM_KSEGX_ADDRESS + kva,
-		    .tlb_lo0 = mips_ksegx_pte.pt_entry
-			+ mips_paddr_to_tlbpfn(kva),
-		    .tlb_lo1 = mips_ksegx_pte.pt_entry
-			+ mips_paddr_to_tlbpfn(kva + kva_inc),
-		    .tlb_mask = tlb_mask,
-		};
-		tlb_write_indexed(pmap_tlb0_info.ti_wired, &tlb);
-		pmap_tlb0_info.ti_wired++;
-	}
-	mips3_cp0_wired_write(pmap_tlb0_info.ti_wired);
+	pmap_ksegx_bootstrap();
 #endif
 
 	/*
@@ -918,7 +934,7 @@ pmap_update(struct pmap *pm)
 	kpreempt_disable();
 #ifdef MULTIPROCESSOR
 	u_int pending = atomic_swap_uint(&pm->pm_shootdown_pending, 0);
-	if (pending && pmap_tlb_shootdown_bystanders(pm))
+	if (pending && pmap_tlb_shootdown_bystanders(pm, pending))
 		PMAP_COUNT(shootdown_ipis);
 #endif
 	/*

Index: src/sys/arch/mips/mips/pmap_tlb.c
diff -u src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.22 src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.23
--- src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.22	Thu Jan 19 08:28:50 2012
+++ src/sys/arch/mips/mips/pmap_tlb.c	Thu Feb 16 23:02:22 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap_tlb.c,v 1.1.2.22 2012/01/19 08:28:50 matt Exp $	*/
+/*	pmap_tlb.c,v 1.1.2.22 2012/01/19 08:28:50 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.22 2012/01/19 08:28:50 matt Exp $");
+__KERNEL_RCSID(0, "pmap_tlb.c,v 1.1.2.22 2012/01/19 08:28:50 matt Exp");
 
 /*
  * Manages address spaces in a TLB.
@@ -221,6 +221,9 @@ pmap_pai_reset(struct pmap_tlb_info *ti,
 void
 pmap_tlb_info_evcnt_attach(struct pmap_tlb_info *ti)
 {
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
 	evcnt_attach_dynamic(&ti->ti_evcnt_asid_reinits,
 	    EVCNT_TYPE_MISC, NULL,
 	    ti->ti_name, "asid pool reinit");
@@ -290,6 +293,9 @@ pmap_tlb_info_init(struct pmap_tlb_info 
 	 */
 	ti->ti_wired = (cpu_info_store.ci_tlb_slot >= 0);
 	pmap_tlbs[ti->ti_index] = ti;
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
 #endif /* MULTIPROCESSOR */
 }
 
@@ -301,6 +307,10 @@ pmap_tlb_info_attach(struct pmap_tlb_inf
 	KASSERT(ci->ci_data.cpu_idlelwp != NULL);
 	KASSERT(cold);
 
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
+
 	TLBINFO_LOCK(ti);
 	uint32_t cpu_mask = 1 << cpu_index(ci);
 	ti->ti_cpu_mask |= cpu_mask;
@@ -436,10 +446,16 @@ pmap_tlb_shootdown_process(void)
 	struct pmap * const curpmap = curlwp->l_proc->p_vmspace->vm_map.pmap;
 #endif
 
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
+
+#if 0
 	KASSERT(cpu_intr_p());
 	KASSERTMSG(ci->ci_cpl >= IPL_SCHED,
 	    ("%s: cpl (%d) < IPL_SCHED (%d)",
 	    __func__, ci->ci_cpl, IPL_SCHED));
+#endif
 	TLBINFO_LOCK(ti);
 
 	switch (ti->ti_tlbinvop) {
@@ -526,21 +542,84 @@ pmap_tlb_shootdown_process(void)
 	TLBINV_MAP(op, TLBINV_ALLKERNEL, TLBINV_ALL, TLBINV_ALL,	\
 	    TLBINV_ALLKERNEL, TLBINV_ALL)
 
-bool
-pmap_tlb_shootdown_bystanders(pmap_t pm)
+static struct cpu_info *
+pmap_tlb_target_bystander(struct pmap_tlb_info *ti, struct pmap *pm,
+	bool kernel_p)
 {
+	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
+	TLBINFO_LOCK(ti);
+	const uint32_t onproc = (pm->pm_onproc & ti->ti_cpu_mask);
+	if (onproc == 0) {
+		if (pm->pm_active & ti->ti_cpu_mask) {
+			/*
+			 * If this pmap has an ASID assigned but it's not
+			 * currently running, nuke its ASID.  Next time the
+			 * pmap is activated, it will allocate a new ASID.
+			 * And best of all, we avoid an IPI.
+			 */
+			KASSERT(!kernel_p);
+			pmap_pai_reset(ti, pai, pm);
+			//ti->ti_evcnt_lazy_shots.ev_count++;
+		}
+		TLBINFO_UNLOCK(ti);
+		return NULL;
+	}
+	if (kernel_p) {
+		ti->ti_tlbinvop = TLBINV_KERNEL_MAP(ti->ti_tlbinvop);
+		ti->ti_victim = NULL;
+	} else {
+		KASSERT(pai->pai_asid);
+		if (__predict_false(ti->ti_victim == pm)) {
+			KASSERT(ti->ti_tlbinvop == TLBINV_ONE);
+			/*
+			 * We still need to invalidate this one
+			 * ASID so there's nothing to change.
+			 */
+		} else {
+			ti->ti_tlbinvop = TLBINV_USER_MAP(ti->ti_tlbinvop);
+			if (ti->ti_tlbinvop == TLBINV_ONE)
+				ti->ti_victim = pm;
+			else
+				ti->ti_victim = NULL;
+		}
+	}
+	TLBINFO_UNLOCK(ti);
 	/*
-	 * We don't need to deal our own TLB.
+	 * Return a pointer to the cpu_info of one of the tlb_info's cpus
 	 */
-	uint32_t pm_active = pm->pm_active & ~curcpu()->ci_tlb_info->ti_cpu_mask;
+	const u_int j = ffs(onproc) - 1;
+	return cpu_lookup(j);
+}
+
+bool
+pmap_tlb_shootdown_bystanders(pmap_t pm, uint32_t pending)
+{
+	struct cpu_info * const ci = curcpu();
+	struct pmap_tlb_info * const curti = ci->ci_tlb_info;
+	uint32_t pm_active = pm->pm_active & ~curti->ti_cpu_mask;
 	const bool kernel_p = (pm == pmap_kernel());
 	bool ipi_sent = false;
 
+	KDASSERT(curti->ti_name[0] == 't');
+	KDASSERT(curti->ti_name[1] == 'l');
+	KDASSERT(curti->ti_name[2] == 'b');
+
+	if (__predict_false(pending & ~curti->ti_cpu_mask) != 0) {
+		/*
+		 * Now if another cpu (not sharing this tlb_info) wants a
+		 * shootdown, then they must mean us since this pmap is
+		 * obviously active.  But since we cleared their bit, they
+		 * won't know they need to do it.  So we do it ourselves
+		 * and save them from sending an IPI.
+		 */
+		if (pmap_tlb_target_bystander(curti, pm, kernel_p) != NULL)
+			pmap_tlb_shootdown_process();
+	}
+
 	/*
 	 * If pm_active gets more bits set, then it's after all our changes
 	 * have been made so they will already be cognizant of them.
 	 */
-
 	for (size_t i = 0; pm_active != 0; i++) {
 		KASSERT(i < pmap_ntlbs);
 		struct pmap_tlb_info * const ti = pmap_tlbs[i];
@@ -548,35 +627,13 @@ pmap_tlb_shootdown_bystanders(pmap_t pm)
 		/*
 		 * Skip this TLB if there are no active mappings for it.
 		 */
-		if ((pm_active & ti->ti_cpu_mask) == 0)
+		if ((pm_active & ti->ti_cpu_mask) == 0) {
 			continue;
-		struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
+		}
 		pm_active &= ~ti->ti_cpu_mask;
-		TLBINFO_LOCK(ti);
-		const uint32_t onproc = (pm->pm_onproc & ti->ti_cpu_mask);
-		if (onproc != 0) {
-			if (kernel_p) {
-				ti->ti_tlbinvop =
-				    TLBINV_KERNEL_MAP(ti->ti_tlbinvop);
-				ti->ti_victim = NULL;
-			} else {
-				KASSERT(pai->pai_asid);
-				if (__predict_false(ti->ti_victim == pm)) {
-					KASSERT(ti->ti_tlbinvop == TLBINV_ONE);
-					/*
-					 * We still need to invalidate this one
-					 * ASID so there's nothing to change.
-					 */
-				} else {
-					ti->ti_tlbinvop =
-					    TLBINV_USER_MAP(ti->ti_tlbinvop);
-					if (ti->ti_tlbinvop == TLBINV_ONE)
-						ti->ti_victim = pm;
-					else
-						ti->ti_victim = NULL;
-				}
-			}
-			TLBINFO_UNLOCK(ti);
+		struct cpu_info * const ipi_ci =
+		    pmap_tlb_target_bystander(ti, pm, kernel_p);
+		if (ipi_ci != NULL) {
 			/*
 			 * Now we can send out the shootdown IPIs to a CPU
 			 * that shares this TLB and is currently using this
@@ -586,24 +643,9 @@ pmap_tlb_shootdown_bystanders(pmap_t pm)
 			 * change now that we have released the lock but we
 			 * can tolerate spurious shootdowns.
 			 */
-			KASSERT(onproc != 0);
-			u_int j = ffs(onproc) - 1;
-			cpu_send_ipi(cpu_lookup(j), IPI_SHOOTDOWN);
+			cpu_send_ipi(ipi_ci, IPI_SHOOTDOWN);
 			ipi_sent = true;
-			continue;
-		}
-		if (pm->pm_active & ti->ti_cpu_mask) {
-			/*
-			 * If this pmap has an ASID assigned but it's not
-			 * currently running, nuke its ASID.  Next time the
-			 * pmap is activated, it will allocate a new ASID.
-			 * And best of all, we avoid an IPI.
-			 */
-			KASSERT(!kernel_p);
-			pmap_pai_reset(ti, pai, pm);
-			//ti->ti_evcnt_lazy_shots.ev_count++;
 		}
-		TLBINFO_UNLOCK(ti);
 	}
 
 	return ipi_sent;
@@ -617,6 +659,10 @@ pmap_tlb_update_addr(pmap_t pm, vaddr_t 
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 	int rv = -1;
 
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
+
 	KASSERT(kpreempt_disabled());
 
 	TLBINFO_LOCK(ti);
@@ -627,7 +673,9 @@ pmap_tlb_update_addr(pmap_t pm, vaddr_t 
 		pmap_tlb_asid_check();
 	}
 #ifdef MULTIPROCESSOR
-	atomic_or_uint(&pm->pm_shootdown_pending, need_ipi);
+	if (need_ipi && (pm->pm_active & ~ti->ti_cpu_mask) != 0) {
+		atomic_or_uint(&pm->pm_shootdown_pending, 1 << cpu_number());
+	}
 #endif
 	TLBINFO_UNLOCK(ti);
 
@@ -640,6 +688,10 @@ pmap_tlb_invalidate_addr(pmap_t pm, vadd
 	struct pmap_tlb_info * const ti = curcpu()->ci_tlb_info;
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
+
 	KASSERT(kpreempt_disabled());
 
 	TLBINFO_LOCK(ti);
@@ -650,7 +702,9 @@ pmap_tlb_invalidate_addr(pmap_t pm, vadd
 		pmap_tlb_asid_check();
 	}
 #ifdef MULTIPROCESSOR
-	(void) atomic_swap_uint(&pm->pm_shootdown_pending, 1);
+	if ((pm->pm_active & ~ti->ti_cpu_mask) != 0) {
+		atomic_or_uint(&pm->pm_shootdown_pending, 1 << cpu_number());
+	}
 #endif
 	TLBINFO_UNLOCK(ti);
 }
@@ -737,6 +791,10 @@ pmap_tlb_asid_acquire(pmap_t pm, struct 
 	struct pmap_tlb_info * const ti = ci->ci_tlb_info;
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
+
 	KASSERT(kpreempt_disabled());
 
 	/*
@@ -831,6 +889,10 @@ pmap_tlb_asid_release_all(struct pmap *p
 	for (u_int i = 0; pm->pm_active != 0; i++) {
 		KASSERT(i < pmap_ntlbs);
 		struct pmap_tlb_info * const ti = pmap_tlbs[i];
+		KDASSERT(ti->ti_name[0] == 't');
+		KDASSERT(ti->ti_name[1] == 'l');
+		KDASSERT(ti->ti_name[2] == 'b');
+
 		if (pm->pm_active & ti->ti_cpu_mask) {
 			struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
 			TLBINFO_LOCK(ti);
@@ -846,6 +908,9 @@ pmap_tlb_asid_release_all(struct pmap *p
 	 */
 	struct pmap_tlb_info * const ti = curcpu()->ci_tlb_info;
 	struct pmap_asid_info * const pai = PMAP_PAI(pm, ti);
+	KDASSERT(ti->ti_name[0] == 't');
+	KDASSERT(ti->ti_name[1] == 'l');
+	KDASSERT(ti->ti_name[2] == 'b');
 	TLBINFO_LOCK(ti);
 	if (pai->pai_asid) {
 		pmap_pai_reset(ti, pai, pm);

Reply via email to