summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/cpc/common/cputrack.c10
-rw-r--r--usr/src/cmd/cpc/cputrack/Makefile.com9
-rw-r--r--usr/src/cmd/cpc/cputrack/i386/Makefile11
-rw-r--r--usr/src/lib/libcpc/common/libcpc.c5
-rw-r--r--usr/src/uts/common/os/kcpc.c42
-rw-r--r--usr/src/uts/common/sys/cpc_impl.h12
-rw-r--r--usr/src/uts/common/sys/kcpc.h8
-rw-r--r--usr/src/uts/sun4v/Makefile.workarounds9
-rw-r--r--usr/src/uts/sun4v/cpu/niagara2.c22
-rw-r--r--usr/src/uts/sun4v/cpu/niagara2_asm.s55
-rw-r--r--usr/src/uts/sun4v/generic/Makefile5
-rw-r--r--usr/src/uts/sun4v/niagara2/Makefile5
-rw-r--r--usr/src/uts/sun4v/os/mach_startup.c23
-rw-r--r--usr/src/uts/sun4v/pcbe/niagara2_pcbe.c278
-rw-r--r--usr/src/uts/sun4v/sys/niagara2regs.h28
15 files changed, 388 insertions, 134 deletions
diff --git a/usr/src/cmd/cpc/common/cputrack.c b/usr/src/cmd/cpc/common/cputrack.c
index 37aaf9f600..9b334d0aeb 100644
--- a/usr/src/cmd/cpc/common/cputrack.c
+++ b/usr/src/cmd/cpc/common/cputrack.c
@@ -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 @@ cputrack_pctx_errfn(const char *fn, const char *fmt, va_list ap)
}
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 @@ pinit_lwp(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg)
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 @@ cputrack(int argc, char *argv[], int optind)
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 @@ p4_ht_error(void)
exit(1);
}
+
+#endif /* defined(__i386) */
diff --git a/usr/src/cmd/cpc/cputrack/Makefile.com b/usr/src/cmd/cpc/cputrack/Makefile.com
index a6b61171f1..d67fb933dd 100644
--- a/usr/src/cmd/cpc/cputrack/Makefile.com
+++ b/usr/src/cmd/cpc/cputrack/Makefile.com
@@ -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 @@ include ../../../Makefile.cmd
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)
diff --git a/usr/src/cmd/cpc/cputrack/i386/Makefile b/usr/src/cmd/cpc/cputrack/i386/Makefile
index c2eedd1f9c..139c8bd92a 100644
--- a/usr/src/cmd/cpc/cputrack/i386/Makefile
+++ b/usr/src/cmd/cpc/cputrack/i386/Makefile
@@ -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)
diff --git a/usr/src/lib/libcpc/common/libcpc.c b/usr/src/lib/libcpc/common/libcpc.c
index bb18b2f090..058e163ccd 100644
--- a/usr/src/lib/libcpc/common/libcpc.c
+++ b/usr/src/lib/libcpc/common/libcpc.c
@@ -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 @@ static const char *errstr[] = {
"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*/
diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c
index 4ed3b8b354..19867ff840 100644
--- a/usr/src/uts/common/os/kcpc.c
+++ b/usr/src/uts/common/os/kcpc.c
@@ -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 @@ kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode)
&(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 @@ kcpc_sample(kcpc_set_t *set, uint64_t *buf, hrtime_t *hrtime, uint64_t *tick)
}
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 @@ kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx)
}
}
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 @@ kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2)
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_lwp_create(kthread_t *t, kthread_t *ct)
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 @@ kcpc_invalidate_all(void)
}
/*
+ * 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
diff --git a/usr/src/uts/common/sys/cpc_impl.h b/usr/src/uts/common/sys/cpc_impl.h
index 8869dea4a3..f7bc7a5838 100644
--- a/usr/src/uts/common/sys/cpc_impl.h
+++ b/usr/src/uts/common/sys/cpc_impl.h
@@ -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 @@ typedef struct {
#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 @@ extern int kcpc_pcbe_tryload(const char *, uint_t, uint_t, uint_t);
#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
}
diff --git a/usr/src/uts/common/sys/kcpc.h b/usr/src/uts/common/sys/kcpc.h
index ffcd542fef..50bce17513 100644
--- a/usr/src/uts/common/sys/kcpc.h
+++ b/usr/src/uts/common/sys/kcpc.h
@@ -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_free_set(kcpc_set_t *set);
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
diff --git a/usr/src/uts/sun4v/Makefile.workarounds b/usr/src/uts/sun4v/Makefile.workarounds
index 632b91da9f..ec7246444e 100644
--- a/usr/src/uts/sun4v/Makefile.workarounds
+++ b/usr/src/uts/sun4v/Makefile.workarounds
@@ -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 =
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
diff --git a/usr/src/uts/sun4v/cpu/niagara2.c b/usr/src/uts/sun4v/cpu/niagara2.c
index 1503304a30..2735b47016 100644
--- a/usr/src/uts/sun4v/cpu/niagara2.c
+++ b/usr/src/uts/sun4v/cpu/niagara2.c
@@ -72,6 +72,19 @@ static hsvc_info_t niagara2_hsvc = {
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 @@ cpu_setup(void)
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.
diff --git a/usr/src/uts/sun4v/cpu/niagara2_asm.s b/usr/src/uts/sun4v/cpu/niagara2_asm.s
index 09dc06cd4b..467e7d9a0b 100644
--- a/usr/src/uts/sun4v/cpu/niagara2_asm.s
+++ b/usr/src/uts/sun4v/cpu/niagara2_asm.s
@@ -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 @@ cpu_inv_tsb(caddr_t tsb_base, uint_t tsb_bytes)
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
diff --git a/usr/src/uts/sun4v/generic/Makefile b/usr/src/uts/sun4v/generic/Makefile
index 0acc03e527..99650fa269 100644
--- a/usr/src/uts/sun4v/generic/Makefile
+++ b/usr/src/uts/sun4v/generic/Makefile
@@ -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 @@ INSTALL_TARGET = def $(BINARY) $(ROOTMODULE) $(ROOTSOFTLINKS)
#
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
#
diff --git a/usr/src/uts/sun4v/niagara2/Makefile b/usr/src/uts/sun4v/niagara2/Makefile
index f2b343e8ad..80d5f729a1 100644
--- a/usr/src/uts/sun4v/niagara2/Makefile
+++ b/usr/src/uts/sun4v/niagara2/Makefile
@@ -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 @@ INSTALL_TARGET = def $(BINARY) $(ROOTMODULE)
#
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
#
diff --git a/usr/src/uts/sun4v/os/mach_startup.c b/usr/src/uts/sun4v/os/mach_startup.c
index e9916773f4..100bfd90da 100644
--- a/usr/src/uts/sun4v/os/mach_startup.c
+++ b/usr/src/uts/sun4v/os/mach_startup.c
@@ -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 @@ phys_install_has_changed(void)
}
-#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 @@ cpu_halt(void)
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).
diff --git a/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c b/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c
index 1e34194fa0..972d20cd50 100644
--- a/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c
+++ b/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c
@@ -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_getpic(void);
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 @@ typedef struct _ni2_event {
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);
+
+/*
+ * 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];
-static ni2_event_t ni2_events[] = {
+#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 @@ static ni2_event_t ni2_events[] = {
{ "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 @@ ni2_pcbe_init(void)
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 @@ ni2_pcbe_event_coverage(char *event)
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 @@ ni2_pcbe_overflow_bitmap(void)
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 @@ ni2_pcbe_overflow_bitmap(void)
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 @@ ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
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 @@ ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
(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 @@ ni2_pcbe_program(void *token)
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 @@ ni2_pcbe_program(void *token)
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 @@ ni2_pcbe_program(void *token)
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 @@ ni2_pcbe_program(void *token)
*/
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 @@ ni2_pcbe_program(void *token)
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 @@ ni2_pcbe_program(void *token)
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 @@ ni2_pcbe_sample(void *token)
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 @@ ni2_pcbe_sample(void *token)
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);
diff --git a/usr/src/uts/sun4v/sys/niagara2regs.h b/usr/src/uts/sun4v/sys/niagara2regs.h
index 3113597e39..2f2bf3ea65 100644
--- a/usr/src/uts/sun4v/sys/niagara2regs.h
+++ b/usr/src/uts/sun4v/sys/niagara2regs.h
@@ -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 @@ extern "C" {
/*
* 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_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_OV0_MASK UINT64_C(0x40000)
+#define CPC_NIAGARA2_PCR_OV1_MASK UINT64_C(0x80000000)
+
+#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