changeset 3732:c8e62d396494

6470504 Remove Niagara2 IDLE loop workaround 6481563 Add support for Niagara2 2.x SPARC performance counters 6481949 handle dynamic hpriv peformance counting using N2 2.0 PCR 6528668 move stick compare workaround to Niagara2 and generic CPU module
author ae112802
date Wed, 28 Feb 2007 16:33:41 -0800
parents 79e3159504fa
children f1b41f5144cc
files usr/src/cmd/cpc/common/cputrack.c usr/src/cmd/cpc/cputrack/Makefile.com usr/src/cmd/cpc/cputrack/i386/Makefile usr/src/lib/libcpc/common/libcpc.c usr/src/uts/common/os/kcpc.c usr/src/uts/common/sys/cpc_impl.h usr/src/uts/common/sys/kcpc.h usr/src/uts/sun4v/Makefile.workarounds usr/src/uts/sun4v/cpu/niagara2.c usr/src/uts/sun4v/cpu/niagara2_asm.s usr/src/uts/sun4v/generic/Makefile usr/src/uts/sun4v/niagara2/Makefile usr/src/uts/sun4v/os/mach_startup.c usr/src/uts/sun4v/pcbe/niagara2_pcbe.c usr/src/uts/sun4v/sys/niagara2regs.h
diffstat 15 files changed, 388 insertions(+), 134 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cpc/common/cputrack.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/cmd/cpc/common/cputrack.c	Wed Feb 28 16:33:41 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -80,7 +80,9 @@
 }
 
 static int cputrack(int argc, char *argv[], int optind);
+#if defined(__i386)
 static void p4_ht_error(void);
+#endif
 
 #if !defined(TEXT_DOMAIN)
 #define	TEXT_DOMAIN	"SYS_TEST"
@@ -343,9 +345,11 @@
 		errstr = strerror(errno);
 		if (errno == EAGAIN)
 			(void) cpc_unbind(cpc, set);
+#if defined(__i386)
 		if (errno == EACCES)
 			p4_ht_error();
 		else
+#endif
 			(void) fprintf(stderr, gettext(
 				"%6d: init_lwp: can't bind perf counters "
 				    "to lwp%d - %s\n"), (int)pid, (int)lwpid,
@@ -690,6 +694,8 @@
 	return (err != 0 ? 1 : 0);
 }
 
+#if defined(__i386)
+
 #define	OFFLINE_CMD	"/usr/sbin/psradm -f "
 #define	BUFSIZE		5	/* enough for "n " where n is a cpuid */
 
@@ -811,3 +817,5 @@
 
 	exit(1);
 }
+
+#endif /* defined(__i386) */
--- a/usr/src/cmd/cpc/cputrack/Makefile.com	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/cmd/cpc/cputrack/Makefile.com	Wed Feb 28 16:33:41 2007 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,7 +30,7 @@
 PROG =		cputrack
 OBJS =		$(PROG).o caps.o time.o setgrp.o strtoset.o
 SRCS =		$(OBJS:%.o=../../common/%.c)
-LDLIBS +=	-lcpc -lpctx -lkstat
+LDLIBS +=	-lcpc -lpctx
 
 CFLAGS +=	$(CCVERBOSE) $(CTF_FLAGS)
 CFLAGS64 +=	$(CCVERBOSE) $(CTF_FLAGS)
--- a/usr/src/cmd/cpc/cputrack/i386/Makefile	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/cmd/cpc/cputrack/i386/Makefile	Wed Feb 28 16:33:41 2007 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,11 +19,13 @@
 # CDDL HEADER END
 #
 #
-# Copyright (c) 1999 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 
 include ../Makefile.com
 
+LDLIBS +=	-lkstat
+
 install: all $(ROOTPROG32)
--- a/usr/src/lib/libcpc/common/libcpc.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/lib/libcpc/common/libcpc.c	Wed Feb 28 16:33:41 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -953,7 +953,8 @@
 "Invalid flags in a request\n",			/* CPC_REQ_INVALID_FLAGS */
 "Requests conflict with each other\n",		/* CPC_CONFLICTING_REQS */
 "Attribute requires the cpc_cpu privilege\n",  /* CPC_ATTR_REQUIRES_PRIVILEGE */
-"Couldn't bind LWP to requested processor\n"	/* CPC_PBIND_FAILED */
+"Couldn't bind LWP to requested processor\n",	/* CPC_PBIND_FAILED */
+"Hypervisor event access denied\n"		/* CPC_HV_NO_ACCESS */
 };
 
 /*VARARGS3*/
--- a/usr/src/uts/common/os/kcpc.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/common/os/kcpc.c	Wed Feb 28 16:33:41 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -302,9 +302,13 @@
 		    &(rp->kr_config), (void *)ctx)) != 0) {
 			kcpc_free_configs(set);
 			*subcode = ret;
-			if (ret == CPC_ATTR_REQUIRES_PRIVILEGE)
+			switch (ret) {
+			case CPC_ATTR_REQUIRES_PRIVILEGE:
+			case CPC_HV_NO_ACCESS:
 				return (EACCES);
-			return (EINVAL);
+			default:
+				return (EINVAL);
+			}
 		}
 
 		ctx->kc_pics[n].kp_req = rp;
@@ -364,6 +368,13 @@
 		}
 
 		kpreempt_enable();
+
+		/*
+		 * The config may have been invalidated by
+		 * the pcbe_sample op.
+		 */
+		if (ctx->kc_flags & KCPC_CTX_INVALID)
+			return (EAGAIN);
 	}
 
 	if (copyout(set->ks_data, buf,
@@ -746,8 +757,7 @@
 		}
 	}
 	if (kcpc_configure_reqs(cctx, cks, &code) != 0)
-		panic("kcpc_ctx_clone: configure of context %p with "
-		    "set %p failed with subcode %d", cctx, cks, code);
+		kcpc_invalidate_config(cctx);
 }
 
 
@@ -890,7 +900,7 @@
 	if (pcbe_ops == NULL ||
 	    (bitmap = pcbe_ops->pcbe_overflow_bitmap()) == 0)
 		return (DDI_INTR_UNCLAIMED);
-#ifdef N2_ERRATUM_134
+#ifdef N2_1x_CPC_WORKAROUNDS
 	/*
 	 * Check if any of the supported counters overflowed. If
 	 * not, it's a spurious overflow trap (Niagara2 1.x silicon
@@ -1116,7 +1126,11 @@
 	kcpc_ctx_clone(ctx, cctx);
 	rw_exit(&kcpc_cpuctx_lock);
 
-	cctx->kc_flags = ctx->kc_flags;
+	/*
+	 * Copy the parent context's kc_flags field, but don't overwrite
+	 * the child's in case it was modified during kcpc_ctx_clone.
+	 */
+	cctx->kc_flags |= ctx->kc_flags;
 	cctx->kc_thread = ct;
 	cctx->kc_cpuid = -1;
 	ct->t_cpc_set = cctx->kc_set;
@@ -1298,6 +1312,20 @@
 }
 
 /*
+ * Interface for PCBEs to signal that an existing configuration has suddenly
+ * become invalid.
+ */
+void
+kcpc_invalidate_config(void *token)
+{
+	kcpc_ctx_t *ctx = token;
+
+	ASSERT(ctx != NULL);
+
+	atomic_or_uint(&ctx->kc_flags, KCPC_CTX_INVALID);
+}
+
+/*
  * Called from lwp_exit() and thread_exit()
  */
 void
--- a/usr/src/uts/common/sys/cpc_impl.h	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/common/sys/cpc_impl.h	Wed Feb 28 16:33:41 2007 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -58,8 +57,10 @@
 #define	CPC_OVF_NOTIFY_EMT	0x1
 #define	CPC_COUNT_USER		0x2
 #define	CPC_COUNT_SYSTEM	0x4
+#define	CPC_COUNT_HV		0x8
 
-#define	KCPC_REQ_ALL_FLAGS	0x7
+#define	KCPC_REQ_ALL_FLAGS	(CPC_OVF_NOTIFY_EMT | CPC_COUNT_USER | \
+		CPC_COUNT_SYSTEM | CPC_COUNT_HV)
 #define	KCPC_REQ_VALID_FLAGS(flags) \
 		(((flags) | KCPC_REQ_ALL_FLAGS) == KCPC_REQ_ALL_FLAGS)
 
@@ -216,6 +217,7 @@
 #define	CPC_CONFLICTING_REQS		8	/* Reqs in the set conflict */
 #define	CPC_ATTR_REQUIRES_PRIVILEGE	9	/* Insufficient privs for atr */
 #define	CPC_PBIND_FAILED		10	/* Couldn't bind to processor */
+#define	CPC_HV_NO_ACCESS		11	/* No perm for HV events */
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/kcpc.h	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/common/sys/kcpc.h	Wed Feb 28 16:33:41 2007 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -129,6 +128,7 @@
 
 extern void *kcpc_next_config(void *token, void *current,
     uint64_t **data);
+extern void kcpc_invalidate_config(void *token);
 
 /*
  * Called by a PCBE to determine if nonprivileged access to counters should be
--- a/usr/src/uts/sun4v/Makefile.workarounds	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/Makefile.workarounds	Wed Feb 28 16:33:41 2007 -0800
@@ -21,7 +21,7 @@
 #
 # uts/sun4v/Makefile.workarounds
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -35,8 +35,5 @@
 WORKAROUND_DEFS	+= -DQCN_POLLING		# XXXQ
 WORKAROUND_DEFS += -DDO_CORELEVEL_LOADBAL
 
-# The following is required to support Niagara2 1.0
-WORKAROUND_DEFS	+= -DN2_ERRATUM_49	# %stick_compare{6:0} ignored
-WORKAROUND_DEFS	+= -DN2_IDLE_WORKAROUND
-WORKAROUND_DEFS += -DN2_ERRATUM_112	# multiple traps for 1 event
-WORKAROUND_DEFS += -DN2_ERRATUM_134	# PMU doesn't set OV bit
+# The following is required to support Niagara2 1.x
+WORKAROUND_DEFS += -DN2_1x_CPC_WORKAROUNDS	# Errata 94, 112, 132, & 134
--- a/usr/src/uts/sun4v/cpu/niagara2.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/cpu/niagara2.c	Wed Feb 28 16:33:41 2007 -0800
@@ -72,6 +72,19 @@
 	NIAGARA2_HSVC_MINOR, cpu_module_name
 };
 
+#ifdef N2_1x_CPC_WORKAROUNDS
+static uint64_t cpu_ver;		/* Niagara2 CPU version reg */
+uint64_t	ni2_1x_perf_workarounds = 0;
+
+/* Niagara2 CPU version register */
+#define	VER_MASK_MAJOR_SHIFT	28
+#define	VER_MASK_MAJOR_MASK	0xf
+
+extern uint64_t va_to_pa(void *);
+extern uint64_t ni2_getver();		/* HV code to get %hver */
+extern uint64_t niagara2_getver(uint64_t ni2_getver_ra, uint64_t *cpu_version);
+#endif
+
 void
 cpu_setup(void)
 {
@@ -79,6 +92,15 @@
 	extern int cpc_has_overflow_intr;
 	int status;
 
+#ifdef N2_1x_CPC_WORKAROUNDS
+	/*
+	 * Get CPU version for Niagara2 part.
+	 */
+	if (niagara2_getver(va_to_pa((void *)ni2_getver), &cpu_ver) == H_EOK &&
+	    ((cpu_ver >> VER_MASK_MAJOR_SHIFT) & VER_MASK_MAJOR_MASK) <= 1)
+		ni2_1x_perf_workarounds = 1;
+#endif
+
 	/*
 	 * Negotiate the API version for Niagara2 specific hypervisor
 	 * services.
--- a/usr/src/uts/sun4v/cpu/niagara2_asm.s	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/cpu/niagara2_asm.s	Wed Feb 28 16:33:41 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -142,3 +142,56 @@
 
 	SET_SIZE(cpu_inv_tsb)
 #endif /* lint */
+
+#ifdef N2_1x_CPC_WORKAROUNDS
+/*
+ * This workaround will be removed prior to the FCS release.
+ */
+
+#if defined(lint)
+
+/*ARGSUSED*/
+uint64_t
+niagara2_getver(uint64_t ni_getver_ra, uint64_t *cpu_version)
+{ return (0); }
+
+#else   /* lint */
+
+/*
+* The following hypervisor calls are used to get the CPU version register
+*/
+#define HV_DIAG_RA2PA           0x200
+#define HV_DIAG_HEXEC           0x201
+
+	/*
+	 * niagara2_getver(uint64_t ni_getver_ra, uint64_t *cpu_version)
+	 */
+	ENTRY(niagara2_getver)
+	mov     %o1, %o4                ! save cpu_version pointer
+	mov     HV_DIAG_RA2PA, %o5      ! get PA of ni_getver routine
+	ta      FAST_TRAP
+	brnz,pn %o0, 2f                 ! return error in not successful
+	nop
+
+	mov     %o1, %o0                ! move ni_getver PA to %o0
+	mov     HV_DIAG_HEXEC, %o5
+	ta      FAST_TRAP
+	brnz,pn %o0, 2f
+	nop
+	stx     %o1, [%o4]              ! copy version
+2:
+	retl
+	nop
+	SET_SIZE(niagara2_getver)
+	/*
+	 * Hypervisor code sequence to get chip version via HV_DIAG_HEXEC.
+	 * Returns E_HOK in %o0 and %hver register value in %o1.
+	 */
+	.global ni2_getver
+	.align  16
+ni2_getver:
+	mov     H_EOK, %o0
+	rdhpr   %hver, %o1
+	done
+#endif  /* lint */
+#endif
--- a/usr/src/uts/sun4v/generic/Makefile	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/generic/Makefile	Wed Feb 28 16:33:41 2007 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -72,6 +72,9 @@
 #
 CFLAGS += $(CCVERBOSE)
 
+# The following is required to support Niagara2 1.0
+WORKAROUND_DEFS	+= -DN2_ERRATUM_49	# %stick_compare{6:0} ignored
+
 #
 # cpu-module-specific flags
 #
--- a/usr/src/uts/sun4v/niagara2/Makefile	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/niagara2/Makefile	Wed Feb 28 16:33:41 2007 -0800
@@ -20,7 +20,7 @@
 #
 #
 # uts/sun4v/niagara2/Makefile
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -68,6 +68,9 @@
 #
 CFLAGS += $(CCVERBOSE) -DNIAGARA2_IMPL
 
+# The following is required to support Niagara2 1.0
+WORKAROUND_DEFS	+= -DN2_ERRATUM_49	# %stick_compare{6:0} ignored
+
 #
 # cpu-module-specific flags
 #
--- a/usr/src/uts/sun4v/os/mach_startup.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/os/mach_startup.c	Wed Feb 28 16:33:41 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -77,14 +77,6 @@
 
 }
 
-#ifdef N2_IDLE_WORKAROUND
-/*
- * Tuneable to control enabling of IDLE loop workaround on Niagara2 1.x parts.
- * This workaround will be removed before the RR.
- */
-int	n2_idle_workaround;
-#endif
-
 /*
  * Halt the present CPU until awoken via an interrupt
  */
@@ -138,19 +130,6 @@
 		return;
 	}
 
-#ifdef N2_IDLE_WORKAROUND
-	/*
-	 * The following workaround for Niagara2, when enabled, forces the
-	 * IDLE CPU to wait in a tight loop until something becomes runnable
-	 * locally, minimizing the overall CPU usage on an IDLE CPU.
-	 */
-	if (n2_idle_workaround) {
-		while (cpup->cpu_disp->disp_nrunnable == 0) {
-			(void) hv_cpu_yield();
-		}
-	}
-#endif
-
 	/*
 	 * We're on our way to being halted.  Wait until something becomes
 	 * runnable locally or we are awaken (i.e. removed from the halt set).
--- a/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c	Wed Feb 28 16:33:41 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,6 +40,8 @@
 #include <sys/sdt.h>
 #include <sys/niagara2regs.h>
 #include <sys/hsvc.h>
+#include <sys/hypervisor_api.h>
+#include <sys/disp.h>
 
 static int ni2_pcbe_init(void);
 static uint_t ni2_pcbe_ncounters(void);
@@ -64,6 +66,10 @@
 extern uint64_t ultra_gettick(void);
 extern char cpu_module_name[];
 
+#ifdef N2_1x_CPC_WORKAROUNDS
+extern uint64_t ni2_1x_perf_workarounds;
+#endif
+
 pcbe_ops_t ni2_pcbe_ops = {
 	PCBE_VER_1,
 	CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE,
@@ -94,12 +100,21 @@
 	const uint32_t	emask_valid;	/* Mask of unreserved MASK bits */
 } ni2_event_t;
 
-#define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_NIAGARA2_PCR_PRIVPIC_SHIFT)
+#define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_NIAGARA2_PCR_PRIV_SHIFT)
 #define	EV_END {NULL, 0, 0}
 
-static const uint64_t   allstopped = ULTRA_PCR_PRIVPIC;
+static const uint64_t	allstopped = (ULTRA_PCR_PRIVPIC |
+	CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1);
 
-static ni2_event_t ni2_events[] = {
+/*
+ * We update this array in the program and allstop routine. The array
+ * is checked in the sample routine to allow us to only perform the
+ * PCR.ht bit check when counting is in progress.
+ */
+static boolean_t ni2_cpc_counting[NCPU];
+
+#ifdef N2_1x_CPC_WORKAROUNDS
+static ni2_event_t ni2_1x_events[] = {
 	{ "Idle_strands",			0x000, 0x00 },
 	{ "Br_completed",			0x201, 0x7f },
 	{ "Br_taken",				0x202, 0x7f },
@@ -139,7 +154,52 @@
 	{ "CRC_MPA_cksum",			0x720, 0x3f },
 	EV_END
 };
+#endif
 
+static ni2_event_t ni2_2x_events[] = {
+	{ "Idle_strands",			0x000, 0x00 },
+	{ "Br_completed",			0x201, 0xff },
+	{ "Br_taken",				0x202, 0xff },
+	{ "Instr_FGU_arithmetic",		0x204, 0xff },
+	{ "Instr_ld",				0x208, 0xff },
+	{ "Instr_st",				0x210, 0xff },
+	{ "Instr_sw",				0x220, 0xff },
+	{ "Instr_other",			0x240, 0xff },
+	{ "Atomics",				0x280, 0xff },
+	{ "Instr_cnt",				0x2fd, 0xff },
+	{ "IC_miss",				0x301, 0x33 },
+	{ "DC_miss",				0x302, 0x33 },
+	{ "L2_imiss",				0x310, 0x33 },
+	{ "L2_dmiss_ld",			0x320, 0x33 },
+	{ "ITLB_HWTW_ref_L2",			0x404, 0x3c },
+	{ "DTLB_HWTW_ref_L2",			0x408, 0x3c },
+	{ "ITLB_HWTW_miss_L2",			0x410, 0x3c },
+	{ "DTLB_HWTW_miss_L2",			0x420, 0x3c },
+	{ "Stream_ld_to_PCX",			0x501, 0x3f },
+	{ "Stream_st_to_PCX",			0x502, 0x3f },
+	{ "CPU_ld_to_PCX",			0x504, 0x3f },
+	{ "CPU_ifetch_to_PCX",			0x508, 0x3f },
+	{ "CPU_st_to_PCX",			0x510, 0x3f },
+	{ "MMU_ld_to_PCX",			0x520, 0x3f },
+	{ "DES_3DES_op",			0x601, 0x3f },
+	{ "AES_op",				0x602, 0x3f },
+	{ "RC4_op",				0x604, 0x3f },
+	{ "MD5_SHA-1_SHA-256_op",		0x608, 0x3f },
+	{ "MA_op",				0x610, 0x3f },
+	{ "CRC_TCPIP_cksum",			0x620, 0x3f },
+	{ "DES_3DES_busy_cycle",		0x701, 0x3f },
+	{ "AES_busy_cycle",			0x702, 0x3f },
+	{ "RC4_busy_cycle",			0x704, 0x3f },
+	{ "MD5_SHA-1_SHA-256_busy_cycle",	0x708, 0x3f },
+	{ "MA_busy_cycle",			0x710, 0x3f },
+	{ "CRC_MPA_cksum",			0x720, 0x3f },
+	{ "ITLB_miss",				0xb04, 0x0c },
+	{ "DTLB_miss",				0xb08, 0x0c },
+	{ "TLB_miss",				0xb0c, 0x0c },
+	EV_END
+};
+
+static ni2_event_t	*ni2_events = ni2_2x_events;
 static const char	*ni2_impl_name = "UltraSPARC T2";
 static char		*evlist;
 static size_t		evlist_sz;
@@ -177,6 +237,10 @@
 		    niagara2_hsvc_major, niagara2_hsvc_minor, status);
 		niagara2_hsvc_available = B_FALSE;
 	}
+#ifdef N2_1x_CPC_WORKAROUNDS
+	if (ni2_1x_perf_workarounds)
+		ni2_events = ni2_1x_events;
+#endif
 	/*
 	 * Construct event list.
 	 *
@@ -260,15 +324,11 @@
 	return (0x3);
 }
 
-#ifdef N2_ERRATUM_112
+#ifdef N2_1x_CPC_WORKAROUNDS
 uint64_t	ni2_ov_tstamp[NCPU];	/* last overflow time stamp */
 uint64_t	ni2_ov_spurious_range = 1000000; /* 1 msec at 1GHz */
 #endif
 
-/*
- * These processors cannot tell which counter overflowed. The PCBE interface
- * requires such processors to act as if _all_ counters had overflowed.
- */
 static uint64_t
 ni2_pcbe_overflow_bitmap(void)
 {
@@ -276,10 +336,6 @@
 	uint64_t	pic;
 	uint32_t	pic0, pic1;
 	boolean_t	update_pic = B_FALSE;
-#ifdef N2_ERRATUM_112
-	uint64_t	tstamp;
-	processorid_t	cpun;
-#endif
 
 	ASSERT(getpil() >= DISP_LEVEL);
 	pcr = ultra_getpcr();
@@ -288,51 +344,73 @@
 	    CPC_NIAGARA2_PCR_OV0_SHIFT;
 	overflow |=  (pcr & CPC_NIAGARA2_PCR_OV1_MASK) >>
 	    CPC_NIAGARA2_PCR_OV1_SHIFT;
-#ifdef N2_ERRATUM_112
-	/*
-	 * Niagara2 1.x silicon can generate a duplicate overflow trap per
-	 * event. If we take an overflow trap with no counters overflowing,
-	 * return a non-zero bitmask with no OV bit set for supported
-	 * counter so that the framework can ignore this trap.
-	 */
-	cpun = CPU->cpu_id;
-	tstamp = ultra_gettick();
-	if (overflow)
-		ni2_ov_tstamp[cpun] = tstamp;
-	else if (tstamp < (ni2_ov_tstamp[cpun] + ni2_ov_spurious_range))
-		overflow |= 1ULL << 63;
-#endif
+
 	pic = ultra_getpic();
 	pic0 = (uint32_t)(pic & PIC0_MASK);
 	pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK);
 
-#ifdef N2_ERRATUM_134
-	/*
-	 * In Niagara2 1.x silicon, PMU doesn't set OV bit for precise events.
-	 * So, if we take a trap with the counter within the overflow range
-	 * and the OV bit is not set, we assume OV bit should have been set.
-	 */
+#ifdef N2_1x_CPC_WORKAROUNDS
+	if (ni2_1x_perf_workarounds) {
+		uint64_t	tstamp;
+		processorid_t	cpun;
+
+		/*
+		 * Niagara2 1.x silicon can generate a duplicate overflow
+		 * trap per event. If we take an overflow trap with no
+		 * counters overflowing, return a non-zero bitmask with no
+		 * OV bit set for supported counter so that the framework
+		 * can ignore this trap.
+		 */
+		cpun = CPU->cpu_id;
+		tstamp = ultra_gettick();
+		if (overflow)
+			ni2_ov_tstamp[cpun] = tstamp;
+		else if (tstamp < (ni2_ov_tstamp[cpun] + ni2_ov_spurious_range))
+			overflow |= 1ULL << 63;
 
-	if (PIC_IN_OV_RANGE(pic0))
-		overflow |= 0x1;
-	if (PIC_IN_OV_RANGE(pic1))
-		overflow |= 0x2;
+		/*
+		 * In Niagara2 1.x silicon, PMU doesn't set OV bit for
+		 * precise events. So, if we take a trap with the counter
+		 * within the overflow range and the OV bit is not set, we
+		 * assume OV bit should have been set.
+		 */
+		if (PIC_IN_OV_RANGE(pic0))
+			overflow |= 0x1;
+		if (PIC_IN_OV_RANGE(pic1))
+			overflow |= 0x2;
+	}
 #endif
-	/*
-	 * Reset the pic, if it is within the overflow range.
-	 */
-	if ((overflow & 0x1) && (PIC_IN_OV_RANGE(pic0))) {
-		pic0 = 0;
-		update_pic = B_TRUE;
+
+	pcr |= (CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1);
+
+	if (overflow & 0x1) {
+		pcr &= ~(CPC_NIAGARA2_PCR_OV0_MASK |
+		    CPC_NIAGARA2_PCR_HOLDOV0);
+		if (PIC_IN_OV_RANGE(pic0)) {
+			pic0 = 0;
+			update_pic = B_TRUE;
+		}
 	}
-	if ((overflow & 0x2) && (PIC_IN_OV_RANGE(pic1))) {
-		pic1 = 0;
-		update_pic = B_TRUE;
+
+	if (overflow & 0x2) {
+		pcr &= ~(CPC_NIAGARA2_PCR_OV1_MASK |
+		    CPC_NIAGARA2_PCR_HOLDOV1);
+		if (PIC_IN_OV_RANGE(pic1)) {
+			pic1 = 0;
+			update_pic = B_TRUE;
+		}
 	}
 
 	if (update_pic)
 		ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0);
 
+	/*
+	 * The HV interface does not need to be used here because we are
+	 * only resetting the OV bits and do not need to set the HT bit.
+	 */
+	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
+	ultra_setpcr(pcr);
+
 	return (overflow);
 }
 
@@ -368,7 +446,7 @@
 	for (i = 0; i < nattrs; i++) {
 		if (strcmp(attrs[i].ka_name, "hpriv") == 0) {
 			if (attrs[i].ka_val != 0)
-				flags |= CPC_COUNT_HPRIV;
+				flags |= CPC_COUNT_HV;
 		} else if (strcmp(attrs[i].ka_name, "emask") == 0) {
 			if ((attrs[i].ka_val | evp->emask_valid) !=
 			    evp->emask_valid)
@@ -386,6 +464,36 @@
 	    (other_config->pcbe_flags != flags))
 		return (CPC_CONFLICTING_REQS);
 
+	/*
+	 * If the hpriv attribute is present, make sure we have
+	 * access to hyperprivileged events before continuing with
+	 * this configuration. If we can set the ht bit in the PCR
+	 * successfully, we must have access to hyperprivileged
+	 * events.
+	 *
+	 * If this is a static per-CPU configuration, the CPC
+	 * driver ensures there can not be more than one for this
+	 * CPU. If this is a per-LWP configuration, the driver
+	 * ensures no static per-CPU counting is ongoing and that
+	 * the target LWP is not already being monitored.
+	 */
+	if (flags & CPC_COUNT_HV) {
+		kpreempt_disable();
+
+		DTRACE_PROBE1(niagara2__setpcr, uint64_t,
+		    allstopped | CPC_NIAGARA2_PCR_HT);
+		if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL,
+		    allstopped | CPC_NIAGARA2_PCR_HT) != H_EOK) {
+			kpreempt_enable();
+			return (CPC_HV_NO_ACCESS);
+		}
+
+		DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped);
+		(void) hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped);
+
+		kpreempt_enable();
+	}
+
 	cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP);
 
 	cfg->pcbe_picno = picnum;
@@ -409,7 +517,7 @@
 	uint64_t		toe;
 
 	/* enable trap-on-event for pic0 and pic1 */
-	toe = (CPC_COUNT_TOE0 | CPC_COUNT_TOE1);
+	toe = (CPC_NIAGARA2_PCR_TOE0 | CPC_NIAGARA2_PCR_TOE1);
 
 	if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
 	    NULL)
@@ -418,7 +526,7 @@
 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
 		pic1 = &nullcfg;
 		nullcfg.pcbe_flags = pic0->pcbe_flags;
-		toe = CPC_COUNT_TOE0; /* enable trap-on-event for pic0 */
+		toe = CPC_NIAGARA2_PCR_TOE0; /* enable trap-on-event for pic0 */
 	}
 
 	if (pic0->pcbe_picno != 0) {
@@ -430,7 +538,7 @@
 		tmp = pic0;
 		pic0 = pic1;
 		pic1 = tmp;
-		toe = CPC_COUNT_TOE1; /* enable trap-on-event for pic1 */
+		toe = CPC_NIAGARA2_PCR_TOE1; /* enable trap-on-event for pic1 */
 	}
 
 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
@@ -444,7 +552,8 @@
 	 */
 	ASSERT(pic0->pcbe_flags == pic1->pcbe_flags);
 
-	ultra_setpcr(allstopped);
+	ni2_pcbe_allstop();
+
 	ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) |
 	    (uint64_t)pic0->pcbe_pic);
 
@@ -453,25 +562,34 @@
 	    CPC_NIAGARA2_PCR_PIC1_SHIFT;
 
 	if (pic0->pcbe_flags & CPC_COUNT_USER)
-		pcr |= (1ull << CPC_NIAGARA2_PCR_USR_SHIFT);
+		pcr |= (1ull << CPC_NIAGARA2_PCR_UT_SHIFT);
 	if (pic0->pcbe_flags & CPC_COUNT_SYSTEM)
-		pcr |= (1ull << CPC_NIAGARA2_PCR_SYS_SHIFT);
-	if (pic0->pcbe_flags & CPC_COUNT_HPRIV)
-		pcr |= (1ull << CPC_NIAGARA2_PCR_HPRIV_SHIFT);
+		pcr |= (1ull << CPC_NIAGARA2_PCR_ST_SHIFT);
+	if (pic0->pcbe_flags & CPC_COUNT_HV)
+		pcr |= (1ull << CPC_NIAGARA2_PCR_HT_SHIFT);
 	pcr |= toe;
 
 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
 
-	/*
-	 * PCR is set by HV using API call hv_niagara_setperf().
-	 * Silently ignore hvpriv events if access is denied.
-	 */
-	if (pic0->pcbe_flags & CPC_COUNT_HPRIV) {
-		if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != 0)
-			ultra_setpcr(pcr);
+	if (pic0->pcbe_flags & CPC_COUNT_HV) {
+		/*
+		 * The ht bit in the PCR is only writable in
+		 * hyperprivileged mode. So if we are counting
+		 * hpriv events, we must use the HV interface
+		 * hv_niagara_setperf to set the PCR. If this
+		 * fails, assume we no longer have access to
+		 * hpriv events.
+		 */
+		if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != H_EOK) {
+			kcpc_invalidate_config(token);
+			return;
+		}
 	} else
+		/* Set the PCR with no hpriv event counting enabled. */
 		ultra_setpcr(pcr);
 
+	ni2_cpc_counting[CPU->cpu_id] = B_TRUE;
+
 	/*
 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
 	 * expect the value we wrote into the PIC, above, to be there after
@@ -488,7 +606,17 @@
 static void
 ni2_pcbe_allstop(void)
 {
-	ultra_setpcr(allstopped);
+	/*
+	 * We use the HV interface here because if we were counting
+	 * hyperprivileged events, we must reset the PCR.ht bit to stop
+	 * the counting. In the event that this HV call fails, we fall
+	 * back on ultra_setpcr which does not have write access to the
+	 * ht bit.
+	 */
+	if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped) != H_EOK)
+		ultra_setpcr(allstopped);
+
+	ni2_cpc_counting[CPU->cpu_id] = B_FALSE;
 }
 
 static void
@@ -500,6 +628,7 @@
 	uint64_t		*pic1_data;
 	uint64_t		*dtmp;
 	uint64_t		tmp;
+	uint64_t		pcr;
 	ni2_pcbe_config_t	*pic0;
 	ni2_pcbe_config_t	*pic1;
 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
@@ -529,6 +658,29 @@
 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
 		panic("%s: bad config on token %p\n", ni2_impl_name, token);
 
+
+	if (pic0->pcbe_flags & CPC_COUNT_HV) {
+		/*
+		 * If the hpriv attribute is present, but the HT bit
+		 * is not set in the PCR, access to hyperprivileged
+		 * events must have been revoked. Only perform this
+		 * check if counting is not stopped.
+		 */
+#ifdef N2_1x_CPC_WORKAROUNDS
+		if (!ni2_1x_perf_workarounds) {
+#endif
+			pcr = ultra_getpcr();
+			DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
+			if (ni2_cpc_counting[CPU->cpu_id] &&
+			    !(pcr & CPC_NIAGARA2_PCR_HT)) {
+				kcpc_invalidate_config(token);
+				return;
+			}
+#ifdef N2_1x_CPC_WORKAROUNDS
+		}
+#endif
+	}
+
 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic;
 	if (diff < 0)
 		diff += (1ll << 32);
--- a/usr/src/uts/sun4v/sys/niagara2regs.h	Wed Feb 28 16:31:04 2007 -0800
+++ b/usr/src/uts/sun4v/sys/niagara2regs.h	Wed Feb 28 16:33:41 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -53,26 +53,32 @@
 /*
  * Niagara2 SPARC Performance Control Register
  */
-#define	CPC_NIAGARA2_PCR_PRIVPIC_SHIFT	0
-#define	CPC_NIAGARA2_PCR_SYS_SHIFT	1
-#define	CPC_NIAGARA2_PCR_USR_SHIFT	2
-#define	CPC_NIAGARA2_PCR_HPRIV_SHIFT	3
+#define	CPC_NIAGARA2_PCR_PRIV_SHIFT	0
+#define	CPC_NIAGARA2_PCR_ST_SHIFT	1
+#define	CPC_NIAGARA2_PCR_UT_SHIFT	2
+
+#define	CPC_NIAGARA2_PCR_HT_SHIFT	3
+#define	CPC_NIAGARA2_PCR_HT		(1ull << CPC_NIAGARA2_PCR_HT_SHIFT)
+
 #define	CPC_NIAGARA2_PCR_TOE0_SHIFT	4
 #define	CPC_NIAGARA2_PCR_TOE1_SHIFT	5
-
-#define	CPC_COUNT_HPRIV			(1ull << CPC_NIAGARA2_PCR_HPRIV_SHIFT)
-#define	CPC_COUNT_TOE0			(1ull << CPC_NIAGARA2_PCR_TOE0_SHIFT)
-#define	CPC_COUNT_TOE1			(1ull << CPC_NIAGARA2_PCR_TOE1_SHIFT)
+#define	CPC_NIAGARA2_PCR_TOE0		(1ull << CPC_NIAGARA2_PCR_TOE0_SHIFT)
+#define	CPC_NIAGARA2_PCR_TOE1		(1ull << CPC_NIAGARA2_PCR_TOE1_SHIFT)
 
 #define	CPC_NIAGARA2_PCR_PIC0_SHIFT	6
 #define	CPC_NIAGARA2_PCR_PIC1_SHIFT	19
 #define	CPC_NIAGARA2_PCR_PIC0_MASK	UINT64_C(0xfff)
 #define	CPC_NIAGARA2_PCR_PIC1_MASK	UINT64_C(0xfff)
 
+#define	CPC_NIAGARA2_PCR_OV0_SHIFT	18
+#define	CPC_NIAGARA2_PCR_OV1_SHIFT	30
 #define	CPC_NIAGARA2_PCR_OV0_MASK	UINT64_C(0x40000)
 #define	CPC_NIAGARA2_PCR_OV1_MASK	UINT64_C(0x80000000)
-#define	CPC_NIAGARA2_PCR_OV0_SHIFT	18
-#define	CPC_NIAGARA2_PCR_OV1_SHIFT	30
+
+#define	CPC_NIAGARA2_PCR_HOLDOV0_SHIFT  62
+#define	CPC_NIAGARA2_PCR_HOLDOV1_SHIFT  63
+#define	CPC_NIAGARA2_PCR_HOLDOV0	(1ull << CPC_NIAGARA2_PCR_HOLDOV0_SHIFT)
+#define	CPC_NIAGARA2_PCR_HOLDOV1	(1ull << CPC_NIAGARA2_PCR_HOLDOV1_SHIFT)
 
 /*
  * Hypervisor FAST_TRAP API function numbers to get/set DRAM