changeset 3177:6d48ee59c4fc

6488843 Hashed Cache index mode support for Huron 6489149 colorequivszc[] may be set incorrectly on sun4v 6489393 MTYPE_START/MTYPE_NEXT DR race in ASSERT macro 6493685 randomize effective process user stack start address to avoid thrashing caches on sun4v platforms
author dp78419
date Mon, 27 Nov 2006 13:18:12 -0800
parents a38e922f22b0
children 6f68dd70b05d
files usr/src/uts/common/os/exec.c usr/src/uts/common/sys/vmsystm.h usr/src/uts/i86pc/vm/vm_machdep.c usr/src/uts/sun4/vm/vm_dep.c usr/src/uts/sun4/vm/vm_dep.h usr/src/uts/sun4u/vm/mach_vm_dep.c usr/src/uts/sun4v/cpu/niagara2.c usr/src/uts/sun4v/vm/mach_vm_dep.c
diffstat 8 files changed, 276 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/os/exec.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/common/os/exec.c	Mon Nov 27 13:18:12 2006 -0800
@@ -1576,6 +1576,10 @@
  *
  *	User Stack
  *	+---------------+ <--- curproc->p_usrstack
+ *	|		|
+ *	| slew		|
+ *	|		|
+ *	+---------------+
  *	| NULL		|
  *	+---------------+
  *	|		|
@@ -1622,9 +1626,9 @@
 	user_t *up = PTOU(p);
 	char *usrstack;
 	rctl_entity_p_t e;
-
 	struct as *as;
 	extern int use_stk_lpg;
+	size_t sp_slew;
 
 	args->from_model = p->p_model;
 	if (p->p_model == DATAMODEL_NATIVE) {
@@ -1788,7 +1792,18 @@
 	p->p_flag |= SAUTOLPG;	/* kernel controls page sizes */
 	mutex_exit(&p->p_lock);
 
-	exec_set_sp(size);
+	/*
+	 * Some platforms may choose to randomize real stack start by adding a
+	 * small slew (not more than a few hundred bytes) to the top of the
+	 * stack. This helps avoid cache thrashing when identical processes
+	 * simultaneously share caches that don't provide enough associativity
+	 * (e.g. sun4v systems). In this case stack slewing makes the same hot
+	 * stack variables in different processes to live in different cache
+	 * sets increasing effective associativity.
+	 */
+	sp_slew = exec_get_spslew();
+	ASSERT(P2PHASE(sp_slew, args->stk_align) == 0);
+	exec_set_sp(size + sp_slew);
 
 	as = as_alloc();
 	p->p_as = as;
@@ -1800,7 +1815,7 @@
 	/*
 	 * Finally, write out the contents of the new stack.
 	 */
-	error = stk_copyout(args, usrstack, auxvpp, up);
+	error = stk_copyout(args, usrstack - sp_slew, auxvpp, up);
 	kmem_free(args->stk_base, args->stk_size);
 	return (error);
 }
--- a/usr/src/uts/common/sys/vmsystm.h	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/common/sys/vmsystm.h	Mon Nov 27 13:18:12 2006 -0800
@@ -149,6 +149,8 @@
 
 extern	void	*boot_virt_alloc(void *addr, size_t size);
 
+extern	size_t	exec_get_spslew(void);
+
 #endif	/* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/i86pc/vm/vm_machdep.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/i86pc/vm/vm_machdep.c	Mon Nov 27 13:18:12 2006 -0800
@@ -2140,3 +2140,9 @@
 void
 dcache_flushall()
 {}
+
+size_t
+exec_get_spslew(void)
+{
+	return (0);
+}
--- a/usr/src/uts/sun4/vm/vm_dep.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/sun4/vm/vm_dep.c	Mon Nov 27 13:18:12 2006 -0800
@@ -897,8 +897,10 @@
 
 	if (do_pg_coloring == 0) {
 		page_colors = 1;
-		for (i = 0; i < mmu_page_sizes; i++)
+		for (i = 0; i < mmu_page_sizes; i++) {
+			colorequivszc[i] = 0;
 			hw_page_array[i].hp_colors = 1;
+		}
 		return;
 	}
 
@@ -925,6 +927,7 @@
 		hw_page_array[i].hp_colors = (page_colors_mask >>
 		    (hw_page_array[i].hp_shift - hw_page_array[0].hp_shift))
 		    + 1;
+		colorequivszc[i] = 0;
 	}
 
 	/*
@@ -935,8 +938,8 @@
 	 * The value of cpu_page_colors determines if additional color bins
 	 * need to be checked for a particular color in the page_get routines.
 	 */
-	if ((cpu_page_colors == 0) && (cpu_setsize < ecache_setsize)) {
-
+	if (cpu_setsize > 0 && cpu_page_colors == 0 &&
+	    cpu_setsize < ecache_setsize) {
 		cpu_page_colors = cpu_setsize / MMU_PAGESIZE;
 		a = lowbit(page_colors) - lowbit(cpu_page_colors);
 		ASSERT(a > 0);
@@ -944,7 +947,6 @@
 
 		for (i = 0; i < mmu_page_sizes; i++) {
 			if ((colors = hw_page_array[i].hp_colors) <= 1) {
-				colorequivszc[i] = 0;
 				continue;
 			}
 			while ((colors >> a) == 0)
--- a/usr/src/uts/sun4/vm/vm_dep.h	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/sun4/vm/vm_dep.h	Mon Nov 27 13:18:12 2006 -0800
@@ -361,7 +361,9 @@
  */
 #define	MTYPE_START(mnode, mtype, flags) {				\
 	if (plcnt[mnode][mtype].plc_mt_pgmax == 0) {			\
-		ASSERT(MNODETYPE_PGCNT(mnode, mtype) == 0);		\
+		ASSERT(mtype == MTYPE_RELOC ||				\
+		    MNODETYPE_PGCNT(mnode, mtype) == 0 ||		\
+		    plcnt[mnode][mtype].plc_mt_pgmax != 0);		\
 		MTYPE_NEXT(mnode, mtype, flags);			\
 	}								\
 }
@@ -374,7 +376,8 @@
 	if (!(flags & (PG_NORELOC | PGI_NOCAGE | PGI_RELOCONLY)) &&	\
 	    (kcage_freemem >= kcage_lotsfree)) {			\
 		if (plcnt[mnode][MTYPE_NORELOC].plc_mt_pgmax == 0) {	\
-			ASSERT(MNODETYPE_PGCNT(mnode, MTYPE_NORELOC) == 0); \
+			ASSERT(MNODETYPE_PGCNT(mnode, MTYPE_NORELOC) == 0 || \
+			    plcnt[mnode][MTYPE_NORELOC].plc_mt_pgmax != 0);  \
 			mtype = -1;					\
 		} else {						\
 			mtype = MTYPE_NORELOC;				\
@@ -389,7 +392,6 @@
  * get the ecache setsize for the current cpu.
  */
 #define	CPUSETSIZE()	(cpunodes[CPU->cpu_id].ecache_setsize)
-#define	CPUASSOC()	(cpunodes[CPU->cpu_id].ecache_associativity)
 
 extern struct cpu	cpu0;
 #define	CPU0		&cpu0
@@ -475,9 +477,7 @@
 		pfn = ((uintptr_t)addr >> MMU_PAGESHIFT) +		\
 			(((uintptr_t)addr >> page_coloring_shift) <<	\
 			(vac_shift - MMU_PAGESHIFT));			\
-		if ((szc) == 0 ||					\
-		    (szc == 1 && &page_pfn_2_color_cpu == NULL &&	\
-		    CPUASSOC() > PNUM_SIZE(1))) {			\
+		if ((szc) == 0 || &page_pfn_2_color_cpu == NULL) {	\
 			pfn += slew;					\
 			bin = PFN_2_COLOR(pfn, szc);			\
 		} else {						\
--- a/usr/src/uts/sun4u/vm/mach_vm_dep.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/sun4u/vm/mach_vm_dep.c	Mon Nov 27 13:18:12 2006 -0800
@@ -326,3 +326,9 @@
 {
 	/* not applicable to sun4u */
 }
+
+size_t
+exec_get_spslew(void)
+{
+	return (0);
+}
--- a/usr/src/uts/sun4v/cpu/niagara2.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/sun4v/cpu/niagara2.c	Mon Nov 27 13:18:12 2006 -0800
@@ -34,6 +34,7 @@
 #include <sys/elf_SPARC.h>
 #include <vm/hat_sfmmu.h>
 #include <vm/page.h>
+#include <vm/vm_dep.h>
 #include <sys/cpuvar.h>
 #include <sys/async.h>
 #include <sys/cmn_err.h>
@@ -124,6 +125,13 @@
 	 * Niagara2 has a performance counter overflow interrupt
 	 */
 	cpc_has_overflow_intr = 1;
+
+	/*
+	 * Enable 4M pages for OOB.
+	 */
+	max_uheap_lpsize = MMU_PAGESIZE4M;
+	max_ustack_lpsize = MMU_PAGESIZE4M;
+	max_privmap_lpsize = MMU_PAGESIZE4M;
 }
 
 /*
@@ -230,3 +238,213 @@
 		tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_time = 0;
 	}
 }
+
+/* NI2 L2$ index is pa[32:28]^pa[17:13].pa[19:18]^pa[12:11].pa[10:6] */
+uint_t
+page_pfn_2_color_cpu(pfn_t pfn, uchar_t szc)
+{
+	uint_t color;
+
+	ASSERT(szc <= TTE256M);
+
+	pfn = PFN_BASE(pfn, szc);
+	color = ((pfn >> 15) ^ pfn) & 0x1f;
+	if (szc >= TTE4M)
+		return (color);
+
+	color = (color << 2) | ((pfn >> 5) & 0x3);
+
+	return (szc <= TTE64K ? color : (color >> 1));
+}
+
+#if TTE256M != 5
+#error TTE256M is not 5
+#endif
+
+uint_t
+page_get_nsz_color_mask_cpu(uchar_t szc, uint_t mask)
+{
+	static uint_t ni2_color_masks[5] = {0x63, 0x1e, 0x3e, 0x1f, 0x1f};
+	ASSERT(szc < TTE256M);
+
+	mask &= ni2_color_masks[szc];
+	return ((szc == TTE64K || szc == TTE512K) ? (mask >> 1) : mask);
+}
+
+uint_t
+page_get_nsz_color_cpu(uchar_t szc, uint_t color)
+{
+	ASSERT(szc < TTE256M);
+	return ((szc == TTE64K || szc == TTE512K) ? (color >> 1) : color);
+}
+
+uint_t
+page_get_color_shift_cpu(uchar_t szc, uchar_t nszc)
+{
+	ASSERT(nszc > szc);
+	ASSERT(nszc <= TTE256M);
+
+	if (szc <= TTE64K)
+		return ((nszc >= TTE4M) ? 2 : ((nszc >= TTE512K) ? 1 : 0));
+	if (szc == TTE512K)
+		return (1);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+pfn_t
+page_next_pfn_for_color_cpu(pfn_t pfn, uchar_t szc, uint_t color,
+    uint_t ceq_mask, uint_t color_mask)
+{
+	pfn_t pstep = PNUM_SIZE(szc);
+	pfn_t npfn, pfn_ceq_mask, pfn_color;
+	pfn_t tmpmask, mask = (pfn_t)-1;
+
+	ASSERT((color & ~ceq_mask) == 0);
+
+	if (((page_pfn_2_color_cpu(pfn, szc) ^ color) & ceq_mask) == 0) {
+
+		/* we start from the page with correct color */
+		if (szc >= TTE512K) {
+			if (szc >= TTE4M) {
+				/* page color is PA[32:28] */
+				pfn_ceq_mask = ceq_mask << 15;
+			} else {
+				/* page color is PA[32:28].PA[19:19] */
+				pfn_ceq_mask = ((ceq_mask & 1) << 6) |
+				    ((ceq_mask >> 1) << 15);
+			}
+			pfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask);
+			return (pfn);
+		} else {
+			/*
+			 * We deal 64K or 8K page. Check if we could the
+			 * satisfy the request without changing PA[32:28]
+			 */
+			pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2);
+			npfn = ADD_MASKED(pfn, pstep, pfn_ceq_mask, mask);
+
+			if ((((npfn ^ pfn) >> 15) & 0x1f) == 0)
+				return (npfn);
+
+			/*
+			 * for next pfn we have to change bits PA[32:28]
+			 * set PA[63:28] and PA[19:18] of the next pfn
+			 */
+			npfn = (pfn >> 15) << 15;
+			npfn |= (ceq_mask & color & 3) << 5;
+			pfn_ceq_mask = (szc == TTE8K) ? 0 :
+			    (ceq_mask & 0x1c) << 13;
+			npfn = ADD_MASKED(npfn, (1 << 15), pfn_ceq_mask, mask);
+
+			/*
+			 * set bits PA[17:13] to match the color
+			 */
+			ceq_mask >>= 2;
+			color = (color >> 2) & ceq_mask;
+			npfn |= ((npfn >> 15) ^ color) & ceq_mask;
+			return (npfn);
+		}
+	}
+
+	/*
+	 * we start from the page with incorrect color - rare case
+	 */
+	if (szc >= TTE512K) {
+		if (szc >= TTE4M) {
+			/* page color is in bits PA[32:28] */
+			npfn = ((pfn >> 20) << 20) | (color << 15);
+			pfn_ceq_mask = (ceq_mask << 15) | 0x7fff;
+		} else {
+			/* try get the right color by changing bit PA[19:19] */
+			npfn = pfn + pstep;
+			if (((page_pfn_2_color_cpu(npfn, szc) ^ color) &
+			    ceq_mask) == 0)
+				return (npfn);
+
+			/* page color is PA[32:28].PA[19:19] */
+			pfn_ceq_mask = ((ceq_mask & 1) << 6) |
+			    ((ceq_mask >> 1) << 15) | (0xff << 7);
+			pfn_color = ((color & 1) << 6) | ((color >> 1) << 15);
+			npfn = ((pfn >> 20) << 20) | pfn_color;
+		}
+
+		while (npfn <= pfn) {
+			npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, mask);
+		}
+		return (npfn);
+	}
+
+	/*
+	 * We deal 64K or 8K page of incorrect color.
+	 * Try correcting color without changing PA[32:28]
+	 */
+
+	pfn_ceq_mask = ((ceq_mask & 3) << 5) | (ceq_mask >> 2);
+	pfn_color = ((color & 3) << 5) | (color >> 2);
+	npfn = (pfn & ~(pfn_t)0x7f);
+	npfn |= (((pfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask;
+	npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn;
+
+	if (((page_pfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0) {
+
+		/* the color is fixed - find the next page */
+		while (npfn <= pfn) {
+			npfn = ADD_MASKED(npfn, pstep, pfn_ceq_mask, mask);
+		}
+		if ((((npfn ^ pfn) >> 15) & 0x1f) == 0)
+			return (npfn);
+	}
+
+	/* to fix the color need to touch PA[32:28] */
+	npfn = (szc == TTE8K) ? ((pfn >> 15) << 15) :
+	    (((pfn >> 18) << 18) | ((color & 0x1c) << 13));
+	tmpmask = (szc == TTE8K) ? 0 : (ceq_mask & 0x1c) << 13;
+
+	while (npfn <= pfn) {
+		npfn = ADD_MASKED(npfn, (1 << 15), tmpmask, mask);
+	}
+
+	/* set bits PA[19:13] to match the color */
+	npfn |= (((npfn >> 15) & 0x1f) ^ pfn_color) & pfn_ceq_mask;
+	npfn = (szc == TTE64K) ? (npfn & ~(pfn_t)0x7) : npfn;
+
+	ASSERT(((page_pfn_2_color_cpu(npfn, szc) ^ color) & ceq_mask) == 0);
+
+	return (npfn);
+}
+
+/*
+ * init page coloring
+ */
+void
+page_coloring_init_cpu()
+{
+	int i;
+	uint_t colors;
+
+	hw_page_array[0].hp_colors = 1 << 7;
+	hw_page_array[1].hp_colors = 1 << 7;
+	hw_page_array[2].hp_colors = 1 << 6;
+
+	for (i = 3; i < mmu_page_sizes; i++) {
+		hw_page_array[i].hp_colors = 1 << 5;
+	}
+
+	if (colorequiv > 1) {
+		int a = lowbit(colorequiv) - 1;
+
+		if (a > 15)
+			a = 15;
+
+		for (i = 0; i < mmu_page_sizes; i++) {
+			if ((colors = hw_page_array[i].hp_colors) <= 1) {
+				continue;
+			}
+			while ((colors >> a) == 0)
+				a--;
+			colorequivszc[i] = (a << 4);
+		}
+	}
+}
--- a/usr/src/uts/sun4v/vm/mach_vm_dep.c	Mon Nov 27 13:17:04 2006 -0800
+++ b/usr/src/uts/sun4v/vm/mach_vm_dep.c	Mon Nov 27 13:18:12 2006 -0800
@@ -51,6 +51,8 @@
 #include <sys/error.h>
 #include <sys/machsystm.h>
 #include <vm/seg_kmem.h>
+#include <sys/stack.h>
+#include <sys/atomic.h>
 
 uint_t page_colors = 0;
 uint_t page_colors_mask = 0;
@@ -507,3 +509,15 @@
 	    contig_mem_slab_arena, 0, VM_SLEEP | VM_BESTFIT);
 
 }
+
+
+static uint_t sp_color_stride = 16;
+static uint_t sp_color_mask = 0x1f;
+static uint_t sp_current_color = (uint_t)-1;
+
+size_t
+exec_get_spslew(void)
+{
+	uint_t spcolor = atomic_inc_32_nv(&sp_current_color);
+	return ((size_t)((spcolor & sp_color_mask) * SA(sp_color_stride)));
+}