summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/devfsadm/dtrace_link.c11
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d45
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d40
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d40
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh78
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh70
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh77
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh70
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d55
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh107
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d48
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh81
-rw-r--r--usr/src/lib/libdtrace/common/dt_error.c7
-rw-r--r--usr/src/lib/libdtrace/common/dt_impl.h7
-rw-r--r--usr/src/lib/libdtrace/common/dt_program.c7
-rw-r--r--usr/src/pkgdefs/SUNWdtrp/prototype_com10
-rw-r--r--usr/src/pkgdefs/SUNWdtrp/prototype_i38612
-rw-r--r--usr/src/pkgdefs/SUNWdtrp/prototype_sparc10
-rw-r--r--usr/src/pkgdefs/SUNWdtrt/prototype_com14
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/brand/lx/dtrace/lx_systrace.c5
-rw-r--r--usr/src/uts/common/dtrace/dcpc.c1096
-rw-r--r--usr/src/uts/common/dtrace/dcpc.conf33
-rw-r--r--usr/src/uts/common/dtrace/dtrace.c59
-rw-r--r--usr/src/uts/common/dtrace/fasttrap.c11
-rw-r--r--usr/src/uts/common/dtrace/lockstat.c5
-rw-r--r--usr/src/uts/common/dtrace/profile.c5
-rw-r--r--usr/src/uts/common/dtrace/systrace.c7
-rw-r--r--usr/src/uts/common/io/cpc.c14
-rw-r--r--usr/src/uts/common/os/dtrace_subr.c19
-rw-r--r--usr/src/uts/common/os/kcpc.c142
-rw-r--r--usr/src/uts/common/sys/cpc_impl.h33
-rw-r--r--usr/src/uts/common/sys/cpuvar.h13
-rw-r--r--usr/src/uts/common/sys/dtrace.h11
-rw-r--r--usr/src/uts/common/sys/kcpc.h17
-rw-r--r--usr/src/uts/common/xen/dtrace/xdt.c15
-rw-r--r--usr/src/uts/i86pc/os/intr.c8
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c6
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared1
-rw-r--r--usr/src/uts/intel/dcpc/Makefile67
-rw-r--r--usr/src/uts/intel/dtrace/fbt.c10
-rw-r--r--usr/src/uts/intel/dtrace/sdt.c6
-rw-r--r--usr/src/uts/intel/ia32/os/cpc_subr.c27
-rw-r--r--usr/src/uts/intel/os/name_to_major1
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/dcpc/Makefile65
-rw-r--r--usr/src/uts/sparc/dtrace/fbt.c12
-rw-r--r--usr/src/uts/sparc/dtrace/sdt.c6
-rw-r--r--usr/src/uts/sparc/os/name_to_major1
-rw-r--r--usr/src/uts/sun4/cpu/cpu_module.c8
-rw-r--r--usr/src/uts/sun4/ml/offsets.in6
-rw-r--r--usr/src/uts/sun4/os/mp_startup.c8
-rw-r--r--usr/src/uts/sun4/os/startup.c7
-rw-r--r--usr/src/uts/sun4u/cpu/common_asm.s32
-rw-r--r--usr/src/uts/sun4u/cpu/us3_cheetah.c6
-rw-r--r--usr/src/uts/sun4u/cpu/us3_cheetahplus.c6
-rw-r--r--usr/src/uts/sun4u/cpu/us3_jalapeno.c6
-rw-r--r--usr/src/uts/sun4u/ml/trap_table.s18
-rw-r--r--usr/src/uts/sun4u/os/cpc_subr.c26
-rw-r--r--usr/src/uts/sun4u/sys/us3_module.h5
-rw-r--r--usr/src/uts/sun4v/cpu/common_asm.s30
-rw-r--r--usr/src/uts/sun4v/ml/trap_table.s16
-rw-r--r--usr/src/uts/sun4v/os/cpc_subr.c26
63 files changed, 2503 insertions, 185 deletions
diff --git a/usr/src/cmd/devfsadm/dtrace_link.c b/usr/src/cmd/devfsadm/dtrace_link.c
index 5dcc2c8208..72a455c179 100644
--- a/usr/src/cmd/devfsadm/dtrace_link.c
+++ b/usr/src/cmd/devfsadm/dtrace_link.c
@@ -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,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <devfsadm.h>
#include <strings.h>
#include <stdio.h>
@@ -49,6 +46,8 @@ static devfsadm_create_t dtrace_create_cbt[] = {
TYPE_EXACT | DRV_EXACT, ILEVEL_0, dtrace_provider },
{ "pseudo", "ddi_pseudo", "systrace",
TYPE_EXACT | DRV_EXACT, ILEVEL_0, dtrace_provider },
+ { "pseudo", "ddi_pseudo", "dcpc",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, dtrace_provider },
};
DEVFSADM_CREATE_INIT_V0(dtrace_create_cbt);
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d
new file mode 100644
index 0000000000..1015a251cf
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test to check that attempting to enable a valid event with a frequency
+ * lower than the default platform limit will fail.
+ *
+ * This test will fail if:
+ * 1) The system under test does not define the 'PAPI_tot_ins' event.
+ * 2) The 'dcpc-min-overflow' variable in dcpc.conf has been modified.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-100
+{
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d
new file mode 100644
index 0000000000..f9b780942f
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d
@@ -0,0 +1,40 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Tests that specifying an overflow value containing extraneous characters
+ * (only digits are allowed) will fail.
+ */
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-10000bonehead
+{
+ @[probename] = count();
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d
new file mode 100644
index 0000000000..73f9575fbe
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d
@@ -0,0 +1,40 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Tests that attempting to enable a probe containing a non existent event
+ * will fail.
+ */
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_cpc_bad-all-10000
+{
+ @[probename] = count();
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh
new file mode 100644
index 0000000000..767d493a76
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart1.ksh
@@ -0,0 +1,78 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# This tests that cpustat(1) should fail to start if the cpc provider
+# is already calling the shots.
+#
+# This script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins'
+# generic event.
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script 2>/dev/null &
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+cpustat -c PAPI_tot_ins 1 5
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh
new file mode 100644
index 0000000000..584469c3fe
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cpcvscpustatpart2.ksh
@@ -0,0 +1,70 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# This tests that enablings from the cpc provider will fail if cpustat(1) is
+# already master of the universe.
+#
+# This script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins'
+# generic event.
+
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ BEGIN
+ {
+ exit(0);
+ }
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+
+cpustat -c PAPI_tot_ins 1 20 &
+pid=$!
+sleep 5
+script 2>/dev/null
+
+status=$?
+
+kill $pid
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh
new file mode 100644
index 0000000000..f62b83d571
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackfailtostart.ksh
@@ -0,0 +1,77 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+#
+# This script ensures that cputrack(1M) will fail to start when the cpc
+# provider has active enablings.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+EOF
+}
+
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+dtraceout=/tmp/dtrace.out.$$
+script 2>/dev/null &
+timeout=15
+
+#
+# Sleep while the above script fires into life. To guard against dtrace dying
+# and us sleeping forever we allow 15 secs for this to happen. This should be
+# enough for even the slowest systems.
+#
+while [ ! -f $dtraceout ]; do
+ sleep 1
+ timeout=$(($timeout-1))
+ if [ $timeout -eq 0 ]; then
+ echo "dtrace failed to start. Exiting."
+ exit 1
+ fi
+done
+
+cputrack -c PAPI_tot_ins sleep 10
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh
new file mode 100644
index 0000000000..58d1e798f1
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.cputrackterminates.ksh
@@ -0,0 +1,70 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+#
+# This script ensures that cputrack(1) will terminate when the cpc provider
+# kicks into life.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+script()
+{
+ $dtrace -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+
+ cpc:::PAPI_tot_ins-all-10000
+ {
+ @[probename] = count();
+ }
+
+ tick-1s
+ /n++ > 10/
+ {
+ exit(0);
+ }
+EOF
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+cputrack -c PAPI_tot_ins sleep 20 &
+cputrack_pid=$!
+sleep 5
+script 2>/dev/null &
+
+wait $cputrack_pid
+status=$?
+
+rm $dtraceout
+
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d b/usr/src/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d
new file mode 100644
index 0000000000..a50bd71ae6
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/err.toomanyenablings.d
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test to check that attempting to enable too many probes will fail.
+ *
+ * This test will fail if:
+ * 1) We ever execute on a platform which is capable of programming 10
+ * 'PAPI_tot_ins' events simultaneously (which no current platforms are
+ * capable of doing).
+ * 2) The system under test does not define the 'PAPI_tot_ins' event.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ exit(0);
+}
+
+cpc:::PAPI_tot_ins-all-10000,
+cpc:::PAPI_tot_ins-all-10001,
+cpc:::PAPI_tot_ins-all-10002,
+cpc:::PAPI_tot_ins-all-10003,
+cpc:::PAPI_tot_ins-all-10004,
+cpc:::PAPI_tot_ins-all-10005,
+cpc:::PAPI_tot_ins-all-10006,
+cpc:::PAPI_tot_ins-all-10007,
+cpc:::PAPI_tot_ins-all-10008,
+cpc:::PAPI_tot_ins-all-10009
+{
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh
new file mode 100644
index 0000000000..7f026c9ebc
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.allcpus.ksh
@@ -0,0 +1,107 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This script verifies that we can fire a probe on each CPU that is in
+# an online state.
+#
+# The script will fail if:
+# 1) The system under test does not define the 'PAPI_tot_ins' event.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+numproc=`psrinfo | tail -1 | cut -f1`
+cpu=0
+dtraceout=/var/tmp/dtrace.out.$$
+scriptout=/var/tmp/script.out.$$
+
+spin()
+{
+ while [ 1 ]; do
+ :
+ done
+}
+
+script()
+{
+ $dtrace -o $dtraceout -s /dev/stdin <<EOF
+ #pragma D option bufsize=128k
+ #pragma D option quiet
+
+ cpc:::PAPI_tot_ins-user-10000
+ /cpus[cpu] != 1/
+ {
+ cpus[cpu] = 1;
+ @a[cpu] = count();
+ }
+
+ tick-1s
+ /n++ > 10/
+ {
+ printa(@a);
+ exit(0);
+ }
+EOF
+}
+
+echo "" > $scriptout
+while [ $cpu -le $numproc ]
+do
+ if [ "`psrinfo -s $cpu 2> /dev/null`" -eq 1 ]; then
+ printf "%9d %16d\n" $cpu 1 >> $scriptout
+ spin &
+ allpids[$cpu]=$!
+ pbind -b $cpu $!
+ fi
+ cpu=$(($cpu+1))
+done
+echo "" >> $scriptout
+
+script
+
+diff $dtraceout $scriptout >/dev/null 2>&1
+status=$?
+
+# kill off the spinner processes
+cpu=0
+while [ $cpu -le $numproc ]
+do
+ if [ "`psrinfo -s $cpu 2> /dev/null`" -eq 1 ]; then
+ kill ${allpids[$cpu]}
+ fi
+ cpu=$(($cpu+1))
+done
+
+rm $dtraceout
+rm $scriptout
+
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d
new file mode 100644
index 0000000000..7ebf844e9c
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.genericevent.d
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Test that we can successfully enable a probe using a generic event.
+ * Currently, all platforms implement 'PAPI_tot_ins' so we'll use that.
+ * Note that this test will fail if the system under test does not
+ * implement that event.
+ *
+ * This test will fail if:
+ * 1) The system under test does not define the 'PAPI_tot_ins' event.
+ */
+
+#pragma D option quiet
+#pragma D option bufsize=128k
+
+cpc:::PAPI_tot_ins-all-10000
+{
+ @[probename] = count();
+}
+
+tick-1s
+/n++ > 10/
+{
+ exit(0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh
new file mode 100644
index 0000000000..96d1ab8c6a
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/cpc/tst.platformevent.ksh
@@ -0,0 +1,81 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This script ensures that we can enable a probe which specifies a platform
+# specific event.
+#
+
+if [ $# != 1 ]; then
+ print -u2 "expected one argument: <dtrace-path>"
+ exit 2
+fi
+
+dtrace=$1
+
+get_event()
+{
+ perl /dev/stdin /dev/stdout << EOF
+ open CPUSTAT, '/usr/sbin/cpustat -h |'
+ or die "Couldn't run cpustat: \$!\n";
+ while (<CPUSTAT>) {
+ if (/(\s+)event\[*[0-9]-*[0-9]*\]*:/ && !/PAPI/) {
+ @a = split(/ /, \$_);
+ \$event = \$a[\$#a-1];
+ }
+ }
+
+ close CPUSTAT;
+ print "\$event\n";
+EOF
+}
+
+script()
+{
+ $dtrace -s /dev/stdin << EOD
+ #pragma D option quiet
+ #pragma D option bufsize=128k
+
+ cpc:::$1-all-10000
+ {
+ @[probename] = count();
+ }
+
+ tick-1s
+ /n++ > 5/
+ {
+ exit(0);
+ }
+EOD
+}
+
+event=$(get_event)
+script $event
+
+status=$?
+
+exit $status
diff --git a/usr/src/lib/libdtrace/common/dt_error.c b/usr/src/lib/libdtrace/common/dt_error.c
index 5005f593a4..0bfabc919c 100644
--- a/usr/src/lib/libdtrace/common/dt_error.c
+++ b/usr/src/lib/libdtrace/common/dt_error.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <strings.h>
#include <dt_impl.h>
@@ -105,7 +103,8 @@ static const struct {
{ EDT_BADSETOPT, "Invalid setopt() library action" },
{ EDT_BADSTACKPC, "Invalid stack program counter size" },
{ EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
- { EDT_OVERSION, "Client requested deprecated version of library" }
+ { EDT_OVERSION, "Client requested deprecated version of library" },
+ { EDT_ENABLING_ERR, "Failed to enable probe" }
};
static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
diff --git a/usr/src/lib/libdtrace/common/dt_impl.h b/usr/src/lib/libdtrace/common/dt_impl.h
index 9b22dfbb64..adf0f74094 100644
--- a/usr/src/lib/libdtrace/common/dt_impl.h
+++ b/usr/src/lib/libdtrace/common/dt_impl.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_IMPL_H
#define _DT_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/objfs.h>
#include <setjmp.h>
@@ -498,7 +496,8 @@ enum {
EDT_BADSETOPT, /* invalid setopt library action */
EDT_BADSTACKPC, /* invalid stack program counter size */
EDT_BADAGGVAR, /* invalid aggregation variable identifier */
- EDT_OVERSION /* client is requesting deprecated version */
+ EDT_OVERSION, /* client is requesting deprecated version */
+ EDT_ENABLING_ERR /* failed to enable probe */
};
/*
diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c
index 29d883aca4..8105df0737 100644
--- a/usr/src/lib/libdtrace/common/dt_program.c
+++ b/usr/src/lib/libdtrace/common/dt_program.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <unistd.h>
#include <strings.h>
#include <stdlib.h>
@@ -173,6 +171,9 @@ dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
case E2BIG:
err = EDT_DIFSIZE;
break;
+ case EBUSY:
+ err = EDT_ENABLING_ERR;
+ break;
default:
err = errno;
}
diff --git a/usr/src/pkgdefs/SUNWdtrp/prototype_com b/usr/src/pkgdefs/SUNWdtrp/prototype_com
index 500f2e98e4..3c743a3110 100644
--- a/usr/src/pkgdefs/SUNWdtrp/prototype_com
+++ b/usr/src/pkgdefs/SUNWdtrp/prototype_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,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
i pkginfo
i copyright
i depend
@@ -40,4 +37,5 @@ f none kernel/drv/lockstat.conf 644 root sys
f none kernel/drv/profile.conf 644 root sys
f none kernel/drv/sdt.conf 644 root sys
f none kernel/drv/systrace.conf 644 root sys
+f none kernel/drv/dcpc.conf 644 root sys
d none kernel/dtrace 755 root sys
diff --git a/usr/src/pkgdefs/SUNWdtrp/prototype_i386 b/usr/src/pkgdefs/SUNWdtrp/prototype_i386
index e1734cf717..61adf49851 100644
--- a/usr/src/pkgdefs/SUNWdtrp/prototype_i386
+++ b/usr/src/pkgdefs/SUNWdtrp/prototype_i386
@@ -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,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
!include prototype_com
@@ -34,12 +32,14 @@ f none kernel/drv/lockstat 755 root sys
f none kernel/drv/profile 755 root sys
f none kernel/drv/sdt 755 root sys
f none kernel/drv/systrace 755 root sys
+f none kernel/drv/dcpc 755 root sys
l none kernel/dtrace/fasttrap=../../kernel/drv/fasttrap
l none kernel/dtrace/fbt=../../kernel/drv/fbt
l none kernel/dtrace/lockstat=../../kernel/drv/lockstat
l none kernel/dtrace/profile=../../kernel/drv/profile
l none kernel/dtrace/sdt=../../kernel/drv/sdt
l none kernel/dtrace/systrace=../../kernel/drv/systrace
+l none kernel/dtrace/dcpc=../../kernel/drv/dcpc
d none kernel/drv/amd64 755 root sys
f none kernel/drv/amd64/dtrace 755 root sys
f none kernel/drv/amd64/fasttrap 755 root sys
@@ -48,6 +48,7 @@ f none kernel/drv/amd64/lockstat 755 root sys
f none kernel/drv/amd64/profile 755 root sys
f none kernel/drv/amd64/sdt 755 root sys
f none kernel/drv/amd64/systrace 755 root sys
+f none kernel/drv/amd64/dcpc 755 root sys
d none kernel/dtrace/amd64 755 root sys
l none kernel/dtrace/amd64/fasttrap=../../../kernel/drv/amd64/fasttrap
l none kernel/dtrace/amd64/fbt=../../../kernel/drv/amd64/fbt
@@ -55,3 +56,4 @@ l none kernel/dtrace/amd64/lockstat=../../../kernel/drv/amd64/lockstat
l none kernel/dtrace/amd64/profile=../../../kernel/drv/amd64/profile
l none kernel/dtrace/amd64/sdt=../../../kernel/drv/amd64/sdt
l none kernel/dtrace/amd64/systrace=../../../kernel/drv/amd64/systrace
+l none kernel/dtrace/amd64/dcpc=../../../kernel/drv/amd64/dcpc
diff --git a/usr/src/pkgdefs/SUNWdtrp/prototype_sparc b/usr/src/pkgdefs/SUNWdtrp/prototype_sparc
index 735e74de8a..fb1026469e 100644
--- a/usr/src/pkgdefs/SUNWdtrp/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWdtrp/prototype_sparc
@@ -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,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
!include prototype_com
@@ -35,6 +33,7 @@ f none kernel/drv/sparcv9/lockstat 755 root sys
f none kernel/drv/sparcv9/profile 755 root sys
f none kernel/drv/sparcv9/sdt 755 root sys
f none kernel/drv/sparcv9/systrace 755 root sys
+f none kernel/drv/sparcv9/dcpc 755 root sys
d none kernel/dtrace/sparcv9 755 root sys
l none kernel/dtrace/sparcv9/fasttrap=../../../kernel/drv/sparcv9/fasttrap
l none kernel/dtrace/sparcv9/fbt=../../../kernel/drv/sparcv9/fbt
@@ -42,3 +41,4 @@ l none kernel/dtrace/sparcv9/lockstat=../../../kernel/drv/sparcv9/lockstat
l none kernel/dtrace/sparcv9/profile=../../../kernel/drv/sparcv9/profile
l none kernel/dtrace/sparcv9/sdt=../../../kernel/drv/sparcv9/sdt
l none kernel/dtrace/sparcv9/systrace=../../../kernel/drv/sparcv9/systrace
+l none kernel/dtrace/sparcv9/dcpc=../../../kernel/drv/sparcv9/dcpc
diff --git a/usr/src/pkgdefs/SUNWdtrt/prototype_com b/usr/src/pkgdefs/SUNWdtrt/prototype_com
index 30aaa3f86e..4c51d03349 100644
--- a/usr/src/pkgdefs/SUNWdtrt/prototype_com
+++ b/usr/src/pkgdefs/SUNWdtrt/prototype_com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
i pkginfo
@@ -320,6 +320,18 @@ f none SUNWdtrt/tst/common/clauses/tst.nopred.d 0444 root bin
f none SUNWdtrt/tst/common/clauses/tst.pred.d 0444 root bin
f none SUNWdtrt/tst/common/clauses/tst.predfirst.d 0444 root bin
f none SUNWdtrt/tst/common/clauses/tst.predlast.d 0444 root bin
+d none SUNWdtrt/tst/common/cpc 0755 root bin
+f none SUNWdtrt/tst/common/cpc/tst.platformevent.ksh 0444 root bin
+f none SUNWdtrt/tst/common/cpc/tst.genericevent.d 0444 root bin
+f none SUNWdtrt/tst/common/cpc/tst.allcpus.ksh 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.toomanyenablings.d 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.D_PDESC_ZERO.nonexistentevent.d 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.D_PDESC_ZERO.lowfrequency.d 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.D_PDESC_ZERO.malformedoverflow.d 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.cputrackfailtostart.ksh 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.cputrackterminates.ksh 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.cpcvscpustatpart1.ksh 0444 root bin
+f none SUNWdtrt/tst/common/cpc/err.cpcvscpustatpart2.ksh 0444 root bin
d none SUNWdtrt/tst/common/decls 0755 root bin
f none SUNWdtrt/tst/common/decls/err.D_DECL_PROTO_NAME.VoidName.d 0444 root bin
f none SUNWdtrt/tst/common/decls/err.D_DECL_PROTO_TYPE.Dyn.d 0444 root bin
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index ecefe16b9f..9da74d6444 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -406,6 +406,8 @@ LOCKSTAT_OBJS += lockstat.o
FASTTRAP_OBJS += fasttrap.o fasttrap_isa.o
+DCPC_OBJS += dcpc.o
+
#
# Driver (pseudo-driver) Modules
#
diff --git a/usr/src/uts/common/brand/lx/dtrace/lx_systrace.c b/usr/src/uts/common/brand/lx/dtrace/lx_systrace.c
index ab9828a589..bfeb78330a 100644
--- a/usr/src/uts/common/brand/lx/dtrace/lx_systrace.c
+++ b/usr/src/uts/common/brand/lx/dtrace/lx_systrace.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -121,7 +121,7 @@ lx_systrace_provide(void *arg, const dtrace_probedesc_t *desc)
}
/*ARGSUSED*/
-static void
+static int
lx_systrace_enable(void *arg, dtrace_id_t id, void *parg)
{
int sysnum = LX_SYSTRACE_SYSNUM((uintptr_t)parg);
@@ -138,6 +138,7 @@ lx_systrace_enable(void *arg, dtrace_id_t id, void *parg)
} else {
lx_systrace_sysent[sysnum].lss_return = id;
}
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/dtrace/dcpc.c b/usr/src/uts/common/dtrace/dcpc.c
new file mode 100644
index 0000000000..05f304fdd7
--- /dev/null
+++ b/usr/src/uts/common/dtrace/dcpc.c
@@ -0,0 +1,1096 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/errno.h>
+#include <sys/cpuvar.h>
+#include <sys/stat.h>
+#include <sys/modctl.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/kcpc.h>
+#include <sys/cpc_pcbe.h>
+#include <sys/cpc_impl.h>
+#include <sys/dtrace_impl.h>
+
+/*
+ * DTrace CPU Performance Counter Provider
+ * ---------------------------------------
+ *
+ * The DTrace cpc provider allows DTrace consumers to access the CPU
+ * performance counter overflow mechanism of a CPU. The configuration
+ * presented in a probe specification is programmed into the performance
+ * counter hardware of all available CPUs on a system. Programming the
+ * hardware causes a counter on each CPU to begin counting events of the
+ * given type. When the specified number of events have occurred, an overflow
+ * interrupt will be generated and the probe is fired.
+ *
+ * The required configuration for the performance counter is encoded into
+ * the probe specification and this includes the performance counter event
+ * name, processor mode, overflow rate and an optional unit mask.
+ *
+ * Most processors provide several counters (PICs) which can count all or a
+ * subset of the events available for a given CPU. However, when overflow
+ * profiling is being used, not all CPUs can detect which counter generated the
+ * overflow interrupt. In this case we cannot reliably determine which counter
+ * overflowed and we therefore only allow such CPUs to configure one event at
+ * a time. Processors that can determine the counter which overflowed are
+ * allowed to program as many events at one time as possible (in theory up to
+ * the number of instrumentation counters supported by that platform).
+ * Therefore, multiple consumers can enable multiple probes at the same time
+ * on such platforms. Platforms which cannot determine the source of an
+ * overflow interrupt are only allowed to program a single event at one time.
+ *
+ * The performance counter hardware is made available to consumers on a
+ * first-come, first-served basis. Only a finite amount of hardware resource
+ * is available and, while we make every attempt to accomodate requests from
+ * consumers, we must deny requests when hardware resources have been exhausted.
+ * A consumer will fail to enable probes when resources are currently in use.
+ *
+ * The cpc provider contends for shared hardware resources along with other
+ * consumers of the kernel CPU performance counter subsystem (e.g. cpustat(1M)).
+ * Only one such consumer can use the performance counters at any one time and
+ * counters are made available on a first-come, first-served basis. As with
+ * cpustat, the cpc provider has priority over per-LWP libcpc usage (e.g.
+ * cputrack(1)). Invoking the cpc provider will cause all existing per-LWP
+ * counter contexts to be invalidated.
+ */
+
+typedef struct dcpc_probe {
+ char dcpc_event_name[CPC_MAX_EVENT_LEN];
+ int dcpc_flag; /* flags (USER/SYS) */
+ uint32_t dcpc_ovfval; /* overflow value */
+ int64_t dcpc_umask; /* umask/emask for this event */
+ int dcpc_picno; /* pic this event is programmed in */
+ int dcpc_enabled; /* probe is actually enabled? */
+ int dcpc_disabling; /* probe is currently being disabled */
+ dtrace_id_t dcpc_id; /* probeid this request is enabling */
+ int dcpc_actv_req_idx; /* idx into dcpc_actv_reqs[] */
+} dcpc_probe_t;
+
+static dev_info_t *dcpc_devi;
+static dtrace_provider_id_t dcpc_pid;
+static dcpc_probe_t **dcpc_actv_reqs;
+static uint32_t dcpc_enablings = 0;
+static int dcpc_ovf_mask = 0;
+static int dcpc_mult_ovf_cap = 0;
+static int dcpc_mask_type = 0;
+
+/*
+ * When the dcpc provider is loaded, dcpc_min_overflow is set to either
+ * DCPC_MIN_OVF_DEFAULT or the value that dcpc-min-overflow is set to in
+ * the dcpc.conf file. Decrease this value to set probes with smaller
+ * overflow values. Remember that very small values could render a system
+ * unusable with frequently occurring events.
+ */
+#define DCPC_MIN_OVF_DEFAULT 5000
+static uint32_t dcpc_min_overflow;
+
+static int dcpc_aframes = 0; /* override for artificial frame setting */
+#if defined(__x86)
+#define DCPC_ARTIFICIAL_FRAMES 8
+#elif defined(__sparc)
+#define DCPC_ARTIFICIAL_FRAMES 2
+#endif
+
+/*
+ * Called from the platform overflow interrupt handler. 'bitmap' is a mask
+ * which contains the pic(s) that have overflowed.
+ */
+static void
+dcpc_fire(uint64_t bitmap)
+{
+ int i;
+
+ /*
+ * No counter was marked as overflowing. Shout about it and get out.
+ */
+ if ((bitmap & dcpc_ovf_mask) == 0) {
+ cmn_err(CE_NOTE, "dcpc_fire: no counter overflow found\n");
+ return;
+ }
+
+ /*
+ * This is the common case of a processor that doesn't support
+ * multiple overflow events. Such systems are only allowed a single
+ * enabling and therefore we just look for the first entry in
+ * the active request array.
+ */
+ if (!dcpc_mult_ovf_cap) {
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (dcpc_actv_reqs[i] != NULL) {
+ dtrace_probe(dcpc_actv_reqs[i]->dcpc_id,
+ CPU->cpu_cpcprofile_pc,
+ CPU->cpu_cpcprofile_upc, 0, 0, 0);
+ return;
+ }
+ }
+ return;
+ }
+
+ /*
+ * This is a processor capable of handling multiple overflow events.
+ * Iterate over the array of active requests and locate the counters
+ * that overflowed (note: it is possible for more than one counter to
+ * have overflowed at the same time).
+ */
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (dcpc_actv_reqs[i] != NULL &&
+ (bitmap & (1ULL << dcpc_actv_reqs[i]->dcpc_picno))) {
+ dtrace_probe(dcpc_actv_reqs[i]->dcpc_id,
+ CPU->cpu_cpcprofile_pc,
+ CPU->cpu_cpcprofile_upc, 0, 0, 0);
+ }
+ }
+}
+
+static void
+dcpc_create_probe(dtrace_provider_id_t id, const char *probename,
+ char *eventname, int64_t umask, uint32_t ovfval, char flag)
+{
+ dcpc_probe_t *pp;
+ int nr_frames = DCPC_ARTIFICIAL_FRAMES + dtrace_mach_aframes();
+
+ if (dcpc_aframes)
+ nr_frames = dcpc_aframes;
+
+ if (dtrace_probe_lookup(id, NULL, NULL, probename) != 0)
+ return;
+
+ pp = kmem_zalloc(sizeof (dcpc_probe_t), KM_SLEEP);
+ (void) strncpy(pp->dcpc_event_name, eventname,
+ sizeof (pp->dcpc_event_name) - 1);
+ pp->dcpc_event_name[sizeof (pp->dcpc_event_name) - 1] = '\0';
+ pp->dcpc_flag = flag | CPC_OVF_NOTIFY_EMT;
+ pp->dcpc_ovfval = ovfval;
+ pp->dcpc_umask = umask;
+ pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1;
+
+ pp->dcpc_id = dtrace_probe_create(id, NULL, NULL, probename,
+ nr_frames, pp);
+}
+
+/*ARGSUSED*/
+static void
+dcpc_provide(void *arg, const dtrace_probedesc_t *desc)
+{
+ /*
+ * The format of a probe is:
+ *
+ * event_name-mode-{optional_umask}-overflow_rate
+ * e.g.
+ * DC_refill_from_system-user-0x1e-50000, or,
+ * DC_refill_from_system-all-10000
+ *
+ */
+ char *str, *end, *p;
+ int i, flag = 0;
+ char event[CPC_MAX_EVENT_LEN];
+ long umask = -1, val = 0;
+ size_t evlen, len;
+
+ /*
+ * The 'cpc' provider offers no probes by default.
+ */
+ if (desc == NULL)
+ return;
+
+ len = strlen(desc->dtpd_name);
+ p = str = kmem_alloc(len + 1, KM_SLEEP);
+ (void) strcpy(str, desc->dtpd_name);
+
+ /*
+ * We have a poor man's strtok() going on here. Replace any hyphens
+ * in the the probe name with NULL characters in order to make it
+ * easy to parse the string with regular string functions.
+ */
+ for (i = 0; i < len; i++) {
+ if (str[i] == '-')
+ str[i] = '\0';
+ }
+
+ /*
+ * The first part of the string must be either a platform event
+ * name or a generic event name.
+ */
+ evlen = strlen(p);
+ (void) strncpy(event, p, CPC_MAX_EVENT_LEN - 1);
+ event[CPC_MAX_EVENT_LEN - 1] = '\0';
+
+ /*
+ * The next part of the name is the mode specification. Valid
+ * settings are "user", "kernel" or "all".
+ */
+ p += evlen + 1;
+
+ if (strcmp(p, "user") == 0)
+ flag |= CPC_COUNT_USER;
+ else if (strcmp(p, "kernel") == 0)
+ flag |= CPC_COUNT_SYSTEM;
+ else if (strcmp(p, "all") == 0)
+ flag |= CPC_COUNT_USER | CPC_COUNT_SYSTEM;
+ else
+ goto err;
+
+ /*
+ * Next we either have a mask specification followed by an overflow
+ * rate or just an overflow rate on its own.
+ */
+ p += strlen(p) + 1;
+ if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ /*
+ * A unit mask can only be specified if:
+ * 1) this performance counter back end supports masks.
+ * 2) the specified event is platform specific.
+ * 3) a valid hex number is converted.
+ * 4) no extraneous characters follow the mask specification.
+ */
+ if (dcpc_mask_type != 0 && strncmp(event, "PAPI", 4) != 0 &&
+ ddi_strtol(p, &end, 16, &umask) == 0 &&
+ end == p + strlen(p)) {
+ p += strlen(p) + 1;
+ } else {
+ goto err;
+ }
+ }
+
+ /*
+ * This final part must be an overflow value which has to be greater
+ * than the minimum permissible overflow rate.
+ */
+ if ((ddi_strtol(p, &end, 10, &val) != 0) || end != p + strlen(p) ||
+ val < dcpc_min_overflow)
+ goto err;
+
+ /*
+ * Validate the event and create the probe.
+ */
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (strstr(kcpc_list_events(i), event) != NULL)
+ dcpc_create_probe(dcpc_pid, desc->dtpd_name, event,
+ umask, (uint32_t)val, flag);
+ }
+
+err:
+ kmem_free(str, len + 1);
+}
+
+/*ARGSUSED*/
+static void
+dcpc_destroy(void *arg, dtrace_id_t id, void *parg)
+{
+ dcpc_probe_t *pp = parg;
+
+ ASSERT(pp->dcpc_enabled == 0);
+ kmem_free(pp, sizeof (dcpc_probe_t));
+}
+
+/*ARGSUSED*/
+static int
+dcpc_usermode(void *arg, dtrace_id_t id, void *parg)
+{
+ return (CPU->cpu_cpcprofile_pc == 0);
+}
+
+static void
+dcpc_populate_set(cpu_t *c, dcpc_probe_t *pp, kcpc_set_t *set, int reqno)
+{
+ kcpc_set_t *oset;
+ int i;
+
+ (void) strncpy(set->ks_req[reqno].kr_event, pp->dcpc_event_name,
+ CPC_MAX_EVENT_LEN);
+ set->ks_req[reqno].kr_config = NULL;
+ set->ks_req[reqno].kr_index = reqno;
+ set->ks_req[reqno].kr_picnum = -1;
+ set->ks_req[reqno].kr_flags = pp->dcpc_flag;
+
+ /*
+ * If a unit mask has been specified then detect which attribute
+ * the platform needs. For now, it's either "umask" or "emask".
+ */
+ if (pp->dcpc_umask >= 0) {
+ set->ks_req[reqno].kr_attr =
+ kmem_zalloc(sizeof (kcpc_attr_t), KM_SLEEP);
+ set->ks_req[reqno].kr_nattrs = 1;
+ if (dcpc_mask_type & DCPC_UMASK)
+ (void) strncpy(set->ks_req[reqno].kr_attr->ka_name,
+ "umask", 5);
+ else
+ (void) strncpy(set->ks_req[reqno].kr_attr->ka_name,
+ "emask", 5);
+ set->ks_req[reqno].kr_attr->ka_val = pp->dcpc_umask;
+ } else {
+ set->ks_req[reqno].kr_attr = NULL;
+ set->ks_req[reqno].kr_nattrs = 0;
+ }
+
+ /*
+ * If this probe is enabled, obtain its current countdown value
+ * and use that. The CPUs cpc context might not exist yet if we
+ * are dealing with a CPU that is just coming online.
+ */
+ if (pp->dcpc_enabled && (c->cpu_cpc_ctx != NULL)) {
+ oset = c->cpu_cpc_ctx->kc_set;
+
+ for (i = 0; i < oset->ks_nreqs; i++) {
+ if (strcmp(oset->ks_req[i].kr_event,
+ set->ks_req[reqno].kr_event) == 0) {
+ set->ks_req[reqno].kr_preset =
+ *(oset->ks_req[i].kr_data);
+ }
+ }
+ } else {
+ set->ks_req[reqno].kr_preset = UINT64_MAX - pp->dcpc_ovfval;
+ }
+
+ set->ks_nreqs++;
+}
+
+
+/*
+ * Create a fresh request set for the enablings represented in the
+ * 'dcpc_actv_reqs' array which contains the probes we want to be
+ * in the set. This can be called for several reasons:
+ *
+ * 1) We are on a single or multi overflow platform and we have no
+ * current events so we can just create the set and initialize it.
+ * 2) We are on a multi-overflow platform and we already have one or
+ * more existing events and we are adding a new enabling. Create a
+ * new set and copy old requests in and then add the new request.
+ * 3) We are on a multi-overflow platform and we have just removed an
+ * enabling but we still have enablings whch are valid. Create a new
+ * set and copy in still valid requests.
+ */
+static kcpc_set_t *
+dcpc_create_set(cpu_t *c)
+{
+ int i, reqno = 0;
+ int active_requests = 0;
+ kcpc_set_t *set;
+
+ /*
+ * First get a count of the number of currently active requests.
+ * Note that dcpc_actv_reqs[] should always reflect which requests
+ * we want to be in the set that is to be created. It is the
+ * responsibility of the caller of dcpc_create_set() to adjust that
+ * array accordingly beforehand.
+ */
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (dcpc_actv_reqs[i] != NULL)
+ active_requests++;
+ }
+
+ set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP);
+
+ set->ks_req =
+ kmem_zalloc(sizeof (kcpc_request_t) * active_requests, KM_SLEEP);
+
+ set->ks_data =
+ kmem_zalloc(active_requests * sizeof (uint64_t), KM_SLEEP);
+
+ /*
+ * Look for valid entries in the active requests array and populate
+ * the request set for any entries found.
+ */
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (dcpc_actv_reqs[i] != NULL) {
+ dcpc_populate_set(c, dcpc_actv_reqs[i], set, reqno);
+ reqno++;
+ }
+ }
+
+ return (set);
+}
+
+static int
+dcpc_program_cpu_event(cpu_t *c)
+{
+ int i, j, subcode;
+ kcpc_ctx_t *ctx, *octx;
+ kcpc_set_t *set;
+
+ set = dcpc_create_set(c);
+
+ octx = NULL;
+ set->ks_ctx = ctx = kcpc_ctx_alloc();
+ ctx->kc_set = set;
+ ctx->kc_cpuid = c->cpu_id;
+
+ if (kcpc_assign_reqs(set, ctx) != 0)
+ goto err;
+
+ if (kcpc_configure_reqs(ctx, set, &subcode) != 0)
+ goto err;
+
+ for (i = 0; i < set->ks_nreqs; i++) {
+ for (j = 0; j < cpc_ncounters; j++) {
+ if (dcpc_actv_reqs[j] != NULL &&
+ strcmp(set->ks_req[i].kr_event,
+ dcpc_actv_reqs[j]->dcpc_event_name) == 0) {
+ dcpc_actv_reqs[j]->dcpc_picno =
+ set->ks_req[i].kr_picnum;
+ }
+ }
+ }
+
+ /*
+ * If we already have an active enabling then save the current cpc
+ * context away.
+ */
+ if (c->cpu_cpc_ctx != NULL)
+ octx = c->cpu_cpc_ctx;
+
+ c->cpu_cpc_ctx = ctx;
+ kcpc_remote_program(c);
+
+ if (octx != NULL) {
+ kcpc_set_t *oset = octx->kc_set;
+ kmem_free(oset->ks_data, oset->ks_nreqs * sizeof (uint64_t));
+ kcpc_free_set(oset);
+ kcpc_ctx_free(octx);
+ }
+
+ return (0);
+
+err:
+ /*
+ * We failed to configure this request up so free things up and
+ * get out.
+ */
+ kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
+ kcpc_free_set(set);
+ kcpc_ctx_free(ctx);
+
+ return (-1);
+}
+
+static void
+dcpc_disable_cpu(cpu_t *c)
+{
+ kcpc_ctx_t *ctx;
+ kcpc_set_t *set;
+
+ /*
+ * Leave this CPU alone if it's already offline.
+ */
+ if (c->cpu_flags & CPU_OFFLINE)
+ return;
+
+ kcpc_remote_stop(c);
+
+ ctx = c->cpu_cpc_ctx;
+ set = ctx->kc_set;
+
+ kcpc_free_configs(set);
+
+ kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t));
+ kcpc_free_set(set);
+ kcpc_ctx_free(ctx);
+ c->cpu_cpc_ctx = NULL;
+}
+
+/*
+ * Stop overflow interrupts being actively processed so that per-CPU
+ * configuration state can be changed safely and correctly. Each CPU has a
+ * dcpc interrupt state byte which is transitioned from DCPC_INTR_FREE (the
+ * "free" state) to DCPC_INTR_CONFIG (the "configuration in process" state)
+ * before any configuration state is changed on any CPUs. The hardware overflow
+ * handler, kcpc_hw_overflow_intr(), will only process an interrupt when a
+ * configuration is not in process (i.e. the state is marked as free). During
+ * interrupt processing the state is set to DCPC_INTR_PROCESSING by the
+ * overflow handler.
+ */
+static void
+dcpc_block_interrupts(void)
+{
+ cpu_t *c;
+ uint8_t *state;
+
+ c = cpu_list;
+
+ do {
+ state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state;
+
+ while (atomic_cas_8(state, DCPC_INTR_FREE,
+ DCPC_INTR_CONFIG) != DCPC_INTR_FREE)
+ continue;
+
+ } while ((c = c->cpu_next) != cpu_list);
+}
+
+/*
+ * Set all CPUs dcpc interrupt state to DCPC_INTR_FREE to indicate that
+ * overflow interrupts can be processed safely.
+ */
+static void
+dcpc_release_interrupts(void)
+{
+ cpu_t *c = cpu_list;
+
+ do {
+ cpu_core[c->cpu_id].cpuc_dcpc_intr_state = DCPC_INTR_FREE;
+ membar_producer();
+ } while ((c = c->cpu_next) != cpu_list);
+}
+
+/*
+ * dcpc_program_event() can be called owing to a new enabling or if a multi
+ * overflow platform has disabled a request but needs to program the requests
+ * that are still valid.
+ *
+ * Every invocation of dcpc_program_event() will create a new kcpc_ctx_t
+ * and a new request set which contains the new enabling and any old enablings
+ * which are still valid (possible with multi-overflow platforms).
+ */
+static int
+dcpc_program_event(dcpc_probe_t *pp)
+{
+ cpu_t *c;
+ int ret = 0;
+
+ ASSERT(MUTEX_HELD(&cpu_lock));
+
+ kpreempt_disable();
+
+ dcpc_block_interrupts();
+
+ c = cpu_list;
+
+ do {
+ /*
+ * Skip CPUs that are currently offline.
+ */
+ if (c->cpu_flags & CPU_OFFLINE)
+ continue;
+
+ if (c->cpu_cpc_ctx != NULL)
+ kcpc_remote_stop(c);
+ } while ((c = c->cpu_next) != cpu_list);
+
+ dcpc_release_interrupts();
+
+ /*
+ * If this enabling is being removed (in the case of a multi event
+ * capable system with more than one active enabling), we can now
+ * update the active request array to reflect the enablings that need
+ * to be reprogrammed.
+ */
+ if (pp->dcpc_disabling == 1)
+ dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
+
+ do {
+ /*
+ * Skip CPUs that are currently offline.
+ */
+ if (c->cpu_flags & CPU_OFFLINE)
+ continue;
+
+ ret = dcpc_program_cpu_event(c);
+ } while ((c = c->cpu_next) != cpu_list && ret == 0);
+
+ /*
+ * If dcpc_program_cpu_event() fails then it is because we couldn't
+ * configure the requests in the set for the CPU and not because of
+ * an error programming the hardware. If we have a failure here then
+ * we assume no CPUs have been programmed in the above step as they
+ * are all configured identically.
+ */
+ if (ret != 0) {
+ pp->dcpc_enabled = 0;
+ kpreempt_enable();
+ return (-1);
+ }
+
+ if (pp->dcpc_disabling != 1)
+ pp->dcpc_enabled = 1;
+
+ kpreempt_enable();
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dcpc_enable(void *arg, dtrace_id_t id, void *parg)
+{
+ dcpc_probe_t *pp = parg;
+ int i, found = 0;
+ cpu_t *c;
+
+ ASSERT(MUTEX_HELD(&cpu_lock));
+
+ /*
+ * Bail out if the counters are being used by a libcpc consumer.
+ */
+ rw_enter(&kcpc_cpuctx_lock, RW_READER);
+ if (kcpc_cpuctx > 0) {
+ rw_exit(&kcpc_cpuctx_lock);
+ return (-1);
+ }
+
+ dtrace_cpc_in_use++;
+ rw_exit(&kcpc_cpuctx_lock);
+
+ /*
+ * Locate this enabling in the first free entry of the active
+ * request array.
+ */
+ for (i = 0; i < cpc_ncounters; i++) {
+ if (dcpc_actv_reqs[i] == NULL) {
+ dcpc_actv_reqs[i] = pp;
+ pp->dcpc_actv_req_idx = i;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If we couldn't find a slot for this probe then there is no
+ * room at the inn.
+ */
+ if (!found) {
+ dtrace_cpc_in_use--;
+ return (-1);
+ }
+
+ ASSERT(pp->dcpc_actv_req_idx >= 0);
+
+ /*
+ * The following must hold true if we are to (attempt to) enable
+ * this request:
+ *
+ * 1) No enablings currently exist. We allow all platforms to
+ * proceed if this is true.
+ *
+ * OR
+ *
+ * 2) If the platform is multi overflow capable and there are
+ * less valid enablings than there are counters. There is no
+ * guarantee that a platform can accommodate as many events as
+ * it has counters for but we will at least try to program
+ * up to that many requests.
+ *
+ * The 'dcpc_enablings' variable is implictly protected by locking
+ * provided by the DTrace framework and the cpu management framework.
+ */
+ if (dcpc_enablings == 0 || (dcpc_mult_ovf_cap &&
+ dcpc_enablings < cpc_ncounters)) {
+ /*
+ * Before attempting to program the first enabling we need to
+ * invalidate any lwp-based contexts.
+ */
+ if (dcpc_enablings == 0)
+ kcpc_invalidate_all();
+
+ if (dcpc_program_event(pp) == 0) {
+ dcpc_enablings++;
+ return (0);
+ }
+ }
+
+ /*
+ * If active enablings existed before we failed to enable this probe
+ * on a multi event capable platform then we need to restart counters
+ * as they will have been stopped in the attempted configuration. The
+ * context should now just contain the request prior to this failed
+ * enabling.
+ */
+ if (dcpc_enablings > 0 && dcpc_mult_ovf_cap) {
+ c = cpu_list;
+
+ ASSERT(dcpc_mult_ovf_cap == 1);
+ do {
+ /*
+ * Skip CPUs that are currently offline.
+ */
+ if (c->cpu_flags & CPU_OFFLINE)
+ continue;
+
+ kcpc_remote_program(c);
+ } while ((c = c->cpu_next) != cpu_list);
+ }
+
+ dtrace_cpc_in_use--;
+ dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
+ pp->dcpc_actv_req_idx = pp->dcpc_picno = -1;
+
+ return (-1);
+}
+
+/*
+ * If only one enabling is active then remove the context and free
+ * everything up. If there are multiple enablings active then remove this
+ * one, its associated meta-data and re-program the hardware.
+ */
+/*ARGSUSED*/
+static void
+dcpc_disable(void *arg, dtrace_id_t id, void *parg)
+{
+ cpu_t *c;
+ dcpc_probe_t *pp = parg;
+
+ ASSERT(MUTEX_HELD(&cpu_lock));
+
+ kpreempt_disable();
+
+ /*
+ * This probe didn't actually make it as far as being fully enabled
+ * so we needn't do anything with it.
+ */
+ if (pp->dcpc_enabled == 0) {
+ /*
+ * If we actually allocated this request a slot in the
+ * request array but failed to enabled it then remove the
+ * entry in the array.
+ */
+ if (pp->dcpc_actv_req_idx >= 0) {
+ dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
+ pp->dcpc_actv_req_idx = pp->dcpc_picno =
+ pp->dcpc_disabling = -1;
+ }
+
+ kpreempt_enable();
+ return;
+ }
+
+ /*
+ * If this is the only enabling then stop all the counters and
+ * free up the meta-data.
+ */
+ if (dcpc_enablings == 1) {
+ ASSERT(dtrace_cpc_in_use == 1);
+
+ dcpc_block_interrupts();
+
+ c = cpu_list;
+
+ do {
+ dcpc_disable_cpu(c);
+ } while ((c = c->cpu_next) != cpu_list);
+
+ dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL;
+ dcpc_release_interrupts();
+ } else {
+ /*
+ * This platform can support multiple overflow events and
+ * the enabling being disabled is not the last one. Remove this
+ * enabling and re-program the hardware with the new config.
+ */
+ ASSERT(dcpc_mult_ovf_cap);
+ ASSERT(dcpc_enablings > 1);
+
+ pp->dcpc_disabling = 1;
+ (void) dcpc_program_event(pp);
+ }
+
+ kpreempt_enable();
+
+ dcpc_enablings--;
+ dtrace_cpc_in_use--;
+ pp->dcpc_enabled = 0;
+ pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1;
+}
+
+/*ARGSUSED*/
+static int
+dcpc_cpu_setup(cpu_setup_t what, processorid_t cpu, void *arg)
+{
+ cpu_t *c;
+ uint8_t *state;
+
+ ASSERT(MUTEX_HELD(&cpu_lock));
+
+ switch (what) {
+ case CPU_OFF:
+ /*
+ * Offline CPUs are not allowed to take part so remove this
+ * CPU if we are actively tracing.
+ */
+ if (dtrace_cpc_in_use) {
+ c = cpu_get(cpu);
+ state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state;
+
+ /*
+ * Indicate that a configuration is in process in
+ * order to stop overflow interrupts being processed
+ * on this CPU while we disable it.
+ */
+ while (atomic_cas_8(state, DCPC_INTR_FREE,
+ DCPC_INTR_CONFIG) != DCPC_INTR_FREE)
+ continue;
+
+ dcpc_disable_cpu(c);
+
+ /*
+ * Reset this CPUs interrupt state as the configuration
+ * has ended.
+ */
+ cpu_core[c->cpu_id].cpuc_dcpc_intr_state =
+ DCPC_INTR_FREE;
+ membar_producer();
+ }
+ break;
+
+ case CPU_ON:
+ case CPU_SETUP:
+ /*
+ * This CPU is being initialized or brought online so program
+ * it with the current request set if we are actively tracing.
+ */
+ if (dtrace_cpc_in_use) {
+ c = cpu_get(cpu);
+
+ (void) dcpc_program_cpu_event(c);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static dtrace_pattr_t dcpc_attr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+};
+
+static dtrace_pops_t dcpc_pops = {
+ dcpc_provide,
+ NULL,
+ dcpc_enable,
+ dcpc_disable,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ dcpc_usermode,
+ dcpc_destroy
+};
+
+/*ARGSUSED*/
+static int
+dcpc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
+{
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dcpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+ int error;
+
+ switch (infocmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = (void *)dcpc_devi;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)0;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ error = DDI_FAILURE;
+ }
+ return (error);
+}
+
+static int
+dcpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+ switch (cmd) {
+ case DDI_DETACH:
+ break;
+ case DDI_SUSPEND:
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
+
+ if (dtrace_unregister(dcpc_pid) != 0)
+ return (DDI_FAILURE);
+
+ ddi_remove_minor_node(devi, NULL);
+
+ mutex_enter(&cpu_lock);
+ unregister_cpu_setup_func(dcpc_cpu_setup, NULL);
+ mutex_exit(&cpu_lock);
+
+ kmem_free(dcpc_actv_reqs, cpc_ncounters * sizeof (dcpc_probe_t *));
+
+ kcpc_unregister_dcpc();
+
+ return (DDI_SUCCESS);
+}
+
+static int
+dcpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
+{
+ uint_t caps;
+ char *attrs;
+
+ switch (cmd) {
+ case DDI_ATTACH:
+ break;
+ case DDI_RESUME:
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
+
+ if (kcpc_pcbe_loaded() == -1)
+ return (DDI_FAILURE);
+
+ caps = kcpc_pcbe_capabilities();
+
+ if (!(caps & CPC_CAP_OVERFLOW_INTERRUPT)) {
+ cmn_err(CE_WARN, "dcpc: Counter Overflow not supported"\
+ " on this processor\n");
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_create_minor_node(devi, "dcpc", S_IFCHR, 0,
+ DDI_PSEUDO, NULL) == DDI_FAILURE ||
+ dtrace_register("cpc", &dcpc_attr, DTRACE_PRIV_KERNEL,
+ NULL, &dcpc_pops, NULL, &dcpc_pid) != 0) {
+ ddi_remove_minor_node(devi, NULL);
+ return (DDI_FAILURE);
+ }
+
+ mutex_enter(&cpu_lock);
+ register_cpu_setup_func(dcpc_cpu_setup, NULL);
+ mutex_exit(&cpu_lock);
+
+ dcpc_ovf_mask = (1 << cpc_ncounters) - 1;
+ ASSERT(dcpc_ovf_mask != 0);
+
+ if (caps & CPC_CAP_OVERFLOW_PRECISE)
+ dcpc_mult_ovf_cap = 1;
+
+ /*
+ * Determine which, if any, mask attribute the back-end can use.
+ */
+ attrs = kcpc_list_attrs();
+ if (strstr(attrs, "umask") != NULL)
+ dcpc_mask_type |= DCPC_UMASK;
+ else if (strstr(attrs, "emask") != NULL)
+ dcpc_mask_type |= DCPC_EMASK;
+
+ /*
+ * The dcpc_actv_reqs array is used to store the requests that
+ * we currently have programmed. The order of requests in this
+ * array is not necessarily the order that the event appears in
+ * the kcpc_request_t array. Once entered into a slot in the array
+ * the entry is not moved until it's removed.
+ */
+ dcpc_actv_reqs =
+ kmem_zalloc(cpc_ncounters * sizeof (dcpc_probe_t *), KM_SLEEP);
+
+ dcpc_min_overflow = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
+ DDI_PROP_DONTPASS, "dcpc-min-overflow", DCPC_MIN_OVF_DEFAULT);
+
+ kcpc_register_dcpc(dcpc_fire);
+
+ ddi_report_dev(devi);
+ dcpc_devi = devi;
+
+ return (DDI_SUCCESS);
+}
+
+static struct cb_ops dcpc_cb_ops = {
+ dcpc_open, /* open */
+ nodev, /* close */
+ nulldev, /* strategy */
+ nulldev, /* print */
+ nodev, /* dump */
+ nodev, /* read */
+ nodev, /* write */
+ nodev, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ ddi_prop_op, /* cb_prop_op */
+ 0, /* streamtab */
+ D_NEW | D_MP /* Driver compatibility flag */
+};
+
+static struct dev_ops dcpc_ops = {
+ DEVO_REV, /* devo_rev, */
+ 0, /* refcnt */
+ dcpc_info, /* get_dev_info */
+ nulldev, /* identify */
+ nulldev, /* probe */
+ dcpc_attach, /* attach */
+ dcpc_detach, /* detach */
+ nodev, /* reset */
+ &dcpc_cb_ops, /* driver operations */
+ NULL, /* bus operations */
+ nodev, /* dev power */
+ ddi_quiesce_not_needed /* quiesce */
+};
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modldrv modldrv = {
+ &mod_driverops, /* module type */
+ "DTrace CPC Module", /* name of module */
+ &dcpc_ops, /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ return (mod_install(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ return (mod_remove(&modlinkage));
+}
diff --git a/usr/src/uts/common/dtrace/dcpc.conf b/usr/src/uts/common/dtrace/dcpc.conf
new file mode 100644
index 0000000000..3f18694062
--- /dev/null
+++ b/usr/src/uts/common/dtrace/dcpc.conf
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+name="dcpc" parent="pseudo" instance=0;
+
+#
+# dcpc-min-overflow is the lower limit on the rate of overflow that can be
+# set on a probe. The default value is 5000. Decrease this value to create
+# probes with lower overflow values. Setting this value too low on a rapidly
+# increasing event could render a system unusable.
+#
+#dcpc-min-overflow=5000;
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index 91e3230737..00e71888cd 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -239,10 +239,16 @@ static void
dtrace_nullop(void)
{}
+static int
+dtrace_enable_nullop(void)
+{
+ return (0);
+}
+
static dtrace_pops_t dtrace_provider_ops = {
(void (*)(void *, const dtrace_probedesc_t *))dtrace_nullop,
(void (*)(void *, struct modctl *))dtrace_nullop,
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop,
(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
@@ -426,6 +432,7 @@ dtrace_load##bits(uintptr_t addr) \
#define DTRACE_DYNHASH_SINK 1
#define DTRACE_DYNHASH_VALID 2
+#define DTRACE_MATCH_FAIL -1
#define DTRACE_MATCH_NEXT 0
#define DTRACE_MATCH_DONE 1
#define DTRACE_ANCHORED(probe) ((probe)->dtpr_func[0] != '\0')
@@ -6654,7 +6661,7 @@ dtrace_match(const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid,
{
dtrace_probe_t template, *probe;
dtrace_hash_t *hash = NULL;
- int len, best = INT_MAX, nmatched = 0;
+ int len, rc, best = INT_MAX, nmatched = 0;
dtrace_id_t i;
ASSERT(MUTEX_HELD(&dtrace_lock));
@@ -6666,7 +6673,8 @@ dtrace_match(const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid,
if (pkp->dtpk_id != DTRACE_IDNONE) {
if ((probe = dtrace_probe_lookup_id(pkp->dtpk_id)) != NULL &&
dtrace_match_probe(probe, pkp, priv, uid, zoneid) > 0) {
- (void) (*matched)(probe, arg);
+ if ((*matched)(probe, arg) == DTRACE_MATCH_FAIL)
+ return (DTRACE_MATCH_FAIL);
nmatched++;
}
return (nmatched);
@@ -6713,8 +6721,12 @@ dtrace_match(const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid,
nmatched++;
- if ((*matched)(probe, arg) != DTRACE_MATCH_NEXT)
+ if ((rc = (*matched)(probe, arg)) !=
+ DTRACE_MATCH_NEXT) {
+ if (rc == DTRACE_MATCH_FAIL)
+ return (DTRACE_MATCH_FAIL);
break;
+ }
}
return (nmatched);
@@ -6733,8 +6745,11 @@ dtrace_match(const dtrace_probekey_t *pkp, uint32_t priv, uid_t uid,
nmatched++;
- if ((*matched)(probe, arg) != DTRACE_MATCH_NEXT)
+ if ((rc = (*matched)(probe, arg)) != DTRACE_MATCH_NEXT) {
+ if (rc == DTRACE_MATCH_FAIL)
+ return (DTRACE_MATCH_FAIL);
break;
+ }
}
return (nmatched);
@@ -6954,7 +6969,7 @@ dtrace_unregister(dtrace_provider_id_t id)
dtrace_probe_t *probe, *first = NULL;
if (old->dtpv_pops.dtps_enable ==
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop) {
+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop) {
/*
* If DTrace itself is the provider, we're called with locks
* already held.
@@ -7100,7 +7115,7 @@ dtrace_invalidate(dtrace_provider_id_t id)
dtrace_provider_t *pvp = (dtrace_provider_t *)id;
ASSERT(pvp->dtpv_pops.dtps_enable !=
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop);
mutex_enter(&dtrace_provider_lock);
mutex_enter(&dtrace_lock);
@@ -7141,7 +7156,7 @@ dtrace_condense(dtrace_provider_id_t id)
* Make sure this isn't the dtrace provider itself.
*/
ASSERT(prov->dtpv_pops.dtps_enable !=
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop);
mutex_enter(&dtrace_provider_lock);
mutex_enter(&dtrace_lock);
@@ -9095,7 +9110,7 @@ dtrace_ecb_add(dtrace_state_t *state, dtrace_probe_t *probe)
return (ecb);
}
-static void
+static int
dtrace_ecb_enable(dtrace_ecb_t *ecb)
{
dtrace_probe_t *probe = ecb->dte_probe;
@@ -9108,7 +9123,7 @@ dtrace_ecb_enable(dtrace_ecb_t *ecb)
/*
* This is the NULL probe -- there's nothing to do.
*/
- return;
+ return (0);
}
if (probe->dtpr_ecb == NULL) {
@@ -9122,8 +9137,8 @@ dtrace_ecb_enable(dtrace_ecb_t *ecb)
if (ecb->dte_predicate != NULL)
probe->dtpr_predcache = ecb->dte_predicate->dtp_cacheid;
- prov->dtpv_pops.dtps_enable(prov->dtpv_arg,
- probe->dtpr_id, probe->dtpr_arg);
+ return (prov->dtpv_pops.dtps_enable(prov->dtpv_arg,
+ probe->dtpr_id, probe->dtpr_arg));
} else {
/*
* This probe is already active. Swing the last pointer to
@@ -9136,6 +9151,7 @@ dtrace_ecb_enable(dtrace_ecb_t *ecb)
probe->dtpr_predcache = 0;
dtrace_sync();
+ return (0);
}
}
@@ -9919,7 +9935,9 @@ dtrace_ecb_create_enable(dtrace_probe_t *probe, void *arg)
if ((ecb = dtrace_ecb_create(state, probe, enab)) == NULL)
return (DTRACE_MATCH_DONE);
- dtrace_ecb_enable(ecb);
+ if (dtrace_ecb_enable(ecb) < 0)
+ return (DTRACE_MATCH_FAIL);
+
return (DTRACE_MATCH_NEXT);
}
@@ -10714,7 +10732,7 @@ static int
dtrace_enabling_match(dtrace_enabling_t *enab, int *nmatched)
{
int i = 0;
- int matched = 0;
+ int total_matched = 0, matched = 0;
ASSERT(MUTEX_HELD(&cpu_lock));
ASSERT(MUTEX_HELD(&dtrace_lock));
@@ -10725,7 +10743,14 @@ dtrace_enabling_match(dtrace_enabling_t *enab, int *nmatched)
enab->dten_current = ep;
enab->dten_error = 0;
- matched += dtrace_probe_enable(&ep->dted_probe, enab);
+ /*
+ * If a provider failed to enable a probe then get out and
+ * let the consumer know we failed.
+ */
+ if ((matched = dtrace_probe_enable(&ep->dted_probe, enab)) < 0)
+ return (EBUSY);
+
+ total_matched += matched;
if (enab->dten_error != 0) {
/*
@@ -10753,7 +10778,7 @@ dtrace_enabling_match(dtrace_enabling_t *enab, int *nmatched)
enab->dten_probegen = dtrace_probegen;
if (nmatched != NULL)
- *nmatched = matched;
+ *nmatched = total_matched;
return (0);
}
diff --git a/usr/src/uts/common/dtrace/fasttrap.c b/usr/src/uts/common/dtrace/fasttrap.c
index fee6d60a57..d25e85e6b9 100644
--- a/usr/src/uts/common/dtrace/fasttrap.c
+++ b/usr/src/uts/common/dtrace/fasttrap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -875,7 +875,7 @@ fasttrap_disable_callbacks(void)
}
/*ARGSUSED*/
-static void
+static int
fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
{
fasttrap_probe_t *probe = parg;
@@ -903,7 +903,7 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
* provider can't go away while we're in this code path.
*/
if (probe->ftp_prov->ftp_retired)
- return;
+ return (0);
/*
* If we can't find the process, it may be that we're in the context of
@@ -912,7 +912,7 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
*/
if ((p = sprlock(probe->ftp_pid)) == NULL) {
if ((curproc->p_flag & SFORKING) == 0)
- return;
+ return (0);
mutex_enter(&pidlock);
p = prfind(probe->ftp_pid);
@@ -974,7 +974,7 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
* drop our reference on the trap table entry.
*/
fasttrap_disable_callbacks();
- return;
+ return (0);
}
}
@@ -982,6 +982,7 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
sprunlock(p);
probe->ftp_enabled = 1;
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/dtrace/lockstat.c b/usr/src/uts/common/dtrace/lockstat.c
index 55b3fcf8ff..69c8b72544 100644
--- a/usr/src/uts/common/dtrace/lockstat.c
+++ b/usr/src/uts/common/dtrace/lockstat.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -83,7 +83,7 @@ static kmutex_t lockstat_test; /* for testing purposes only */
static dtrace_provider_id_t lockstat_id;
/*ARGSUSED*/
-static void
+static int
lockstat_enable(void *arg, dtrace_id_t id, void *parg)
{
lockstat_probe_t *probe = parg;
@@ -102,6 +102,7 @@ lockstat_enable(void *arg, dtrace_id_t id, void *parg)
*/
mutex_enter(&lockstat_test);
mutex_exit(&lockstat_test);
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/dtrace/profile.c b/usr/src/uts/common/dtrace/profile.c
index da8f58a378..c1a2d1f1c1 100644
--- a/usr/src/uts/common/dtrace/profile.c
+++ b/usr/src/uts/common/dtrace/profile.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -360,7 +360,7 @@ profile_offline(void *arg, cpu_t *cpu, void *oarg)
}
/*ARGSUSED*/
-static void
+static int
profile_enable(void *arg, dtrace_id_t id, void *parg)
{
profile_probe_t *prof = parg;
@@ -390,6 +390,7 @@ profile_enable(void *arg, dtrace_id_t id, void *parg)
} else {
prof->prof_cyclic = cyclic_add_omni(&omni);
}
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/dtrace/systrace.c b/usr/src/uts/common/dtrace/systrace.c
index fe7bee1ac8..b864041c45 100644
--- a/usr/src/uts/common/dtrace/systrace.c
+++ b/usr/src/uts/common/dtrace/systrace.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -140,7 +140,7 @@ systrace_destroy(void *arg, dtrace_id_t id, void *parg)
}
/*ARGSUSED*/
-static void
+static int
systrace_enable(void *arg, dtrace_id_t id, void *parg)
{
int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg);
@@ -161,7 +161,7 @@ systrace_enable(void *arg, dtrace_id_t id, void *parg)
if (enabled) {
ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall);
- return;
+ return (0);
}
(void) casptr(&sysent[sysnum].sy_callc,
@@ -172,6 +172,7 @@ systrace_enable(void *arg, dtrace_id_t id, void *parg)
(void *)systrace_sysent32[sysnum].stsy_underlying,
(void *)dtrace_systrace_syscall32);
#endif
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/io/cpc.c b/usr/src/uts/common/io/cpc.c
index fbc0b77f92..6881380251 100644
--- a/usr/src/uts/common/io/cpc.c
+++ b/usr/src/uts/common/io/cpc.c
@@ -19,11 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
/*
* CPU Performance Counter system calls and device driver.
*
@@ -126,7 +125,7 @@ cpc(int cmd, id_t lwpid, void *udata1, void *udata2, void *udata3)
*/
rw_enter(&kcpc_cpuctx_lock, RW_READER);
- if (kcpc_cpuctx) {
+ if (kcpc_cpuctx || dtrace_cpc_in_use) {
rw_exit(&kcpc_cpuctx_lock);
return (set_errno(EAGAIN));
}
@@ -486,6 +485,15 @@ kcpc_open(dev_t *dev, int flags, int otyp, cred_t *cr)
rw_enter(&kcpc_cpuctx_lock, RW_WRITER);
if (++kcpc_cpuctx == 1) {
ASSERT(kcpc_cpumap == NULL);
+
+ /*
+ * Bail out if DTrace is already using the counters.
+ */
+ if (dtrace_cpc_in_use) {
+ kcpc_cpuctx--;
+ rw_exit(&kcpc_cpuctx_lock);
+ return (EAGAIN);
+ }
kcpc_cpumap = kmem_zalloc(BT_SIZEOFMAP(max_cpuid + 1),
KM_SLEEP);
/*
diff --git a/usr/src/uts/common/os/dtrace_subr.c b/usr/src/uts/common/os/dtrace_subr.c
index 6c0b7d3369..f2a9ac1b7d 100644
--- a/usr/src/uts/common/os/dtrace_subr.c
+++ b/usr/src/uts/common/os/dtrace_subr.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/dtrace.h>
#include <sys/cmn_err.h>
#include <sys/tnf.h>
@@ -45,6 +43,7 @@ void (*dtrace_helpers_cleanup)(void);
void (*dtrace_helpers_fork)(proc_t *, proc_t *);
void (*dtrace_cpustart_init)(void);
void (*dtrace_cpustart_fini)(void);
+void (*dtrace_cpc_fire)(uint64_t);
void (*dtrace_debugger_init)(void);
void (*dtrace_debugger_fini)(void);
@@ -52,6 +51,20 @@ void (*dtrace_debugger_fini)(void);
dtrace_vtime_state_t dtrace_vtime_active = 0;
dtrace_cacheid_t dtrace_predcache_id = DTRACE_CACHEIDNONE + 1;
+/*
+ * dtrace_cpc_in_use usage statement: this global variable is used by the cpc
+ * hardware overflow interrupt handler and the kernel cpc framework to check
+ * whether or not the DTrace cpc provider is currently in use. The variable is
+ * set before counters are enabled with the first enabling and cleared when
+ * the last enabling is disabled. Its value at any given time indicates the
+ * number of active dcpc based enablings. The global 'kcpc_cpuctx_lock' rwlock
+ * is held during initial setting to protect races between kcpc_open() and the
+ * first enabling. The locking provided by the DTrace subsystem, the kernel
+ * cpc framework and the cpu management framework protect consumers from race
+ * conditions on enabling and disabling probes.
+ */
+uint32_t dtrace_cpc_in_use = 0;
+
typedef struct dtrace_hrestime {
lock_t dthr_lock; /* lock for this element */
timestruc_t dthr_hrestime; /* hrestime value */
diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c
index 8c9a135243..e5cab151b8 100644
--- a/usr/src/uts/common/os/kcpc.c
+++ b/usr/src/uts/common/os/kcpc.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -65,24 +65,16 @@ static uint32_t kcpc_intrctx_count; /* # overflows in an interrupt handler */
static uint32_t kcpc_nullctx_count; /* # overflows in a thread with no ctx */
/*
- * Is misbehaviour (overflow in a thread with no context) fatal?
+ * By setting 'kcpc_nullctx_panic' to 1, any overflow interrupts in a thread
+ * with no valid context will result in a panic.
*/
-#ifdef DEBUG
-static int kcpc_nullctx_panic = 1;
-#else
static int kcpc_nullctx_panic = 0;
-#endif
static void kcpc_lwp_create(kthread_t *t, kthread_t *ct);
static void kcpc_restore(kcpc_ctx_t *ctx);
static void kcpc_save(kcpc_ctx_t *ctx);
static void kcpc_free(kcpc_ctx_t *ctx, int isexec);
-static int kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode);
-static void kcpc_free_configs(kcpc_set_t *set);
-static kcpc_ctx_t *kcpc_ctx_alloc(void);
static void kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx);
-static void kcpc_ctx_free(kcpc_ctx_t *ctx);
-static int kcpc_assign_reqs(kcpc_set_t *set, kcpc_ctx_t *ctx);
static int kcpc_tryassign(kcpc_set_t *set, int starting_req, int *scratch);
static kcpc_set_t *kcpc_dup_set(kcpc_set_t *set);
@@ -93,6 +85,18 @@ kcpc_register_pcbe(pcbe_ops_t *ops)
cpc_ncounters = pcbe_ops->pcbe_ncounters();
}
+void
+kcpc_register_dcpc(void (*func)(uint64_t))
+{
+ dtrace_cpc_fire = func;
+}
+
+void
+kcpc_unregister_dcpc(void)
+{
+ dtrace_cpc_fire = NULL;
+}
+
int
kcpc_bind_cpu(kcpc_set_t *set, processorid_t cpuid, int *subcode)
{
@@ -272,7 +276,7 @@ kcpc_bind_thread(kcpc_set_t *set, kthread_t *t, int *subcode)
* Walk through each request in the set and ask the PCBE to configure a
* corresponding counter.
*/
-static int
+int
kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode)
{
int i;
@@ -327,7 +331,7 @@ kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode)
return (0);
}
-static void
+void
kcpc_free_configs(kcpc_set_t *set)
{
int i;
@@ -710,7 +714,7 @@ kcpc_next_config(void *token, void *current, uint64_t **data)
}
-static kcpc_ctx_t *
+kcpc_ctx_t *
kcpc_ctx_alloc(void)
{
kcpc_ctx_t *ctx;
@@ -790,7 +794,7 @@ kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx)
}
-static void
+void
kcpc_ctx_free(kcpc_ctx_t *ctx)
{
kcpc_ctx_t **loc;
@@ -881,9 +885,33 @@ kcpc_overflow_intr(caddr_t arg, uint64_t bitmap)
* or something went terribly wrong i.e. we ended up
* running a passivated interrupt thread, a kernel
* thread or we interrupted idle, all of which are Very Bad.
+ *
+ * We also could end up here owing to an incredibly unlikely
+ * race condition that exists on x86 based architectures when
+ * the cpc provider is in use; overflow interrupts are directed
+ * to the cpc provider if the 'dtrace_cpc_in_use' variable is
+ * set when we enter the handler. This variable is unset after
+ * overflow interrupts have been disabled on all CPUs and all
+ * contexts have been torn down. To stop interrupts, the cpc
+ * provider issues a xcall to the remote CPU before it tears
+ * down that CPUs context. As high priority xcalls, on an x86
+ * architecture, execute at a higher PIL than this handler, it
+ * is possible (though extremely unlikely) that the xcall could
+ * interrupt the overflow handler before the handler has
+ * checked the 'dtrace_cpc_in_use' variable, stop the counters,
+ * return to the cpc provider which could then rip down
+ * contexts and unset 'dtrace_cpc_in_use' *before* the CPUs
+ * overflow handler has had a chance to check the variable. In
+ * that case, the handler would direct the overflow into this
+ * code and no valid context will be found. The default behavior
+ * when no valid context is found is now to shout a warning to
+ * the console and bump the 'kcpc_nullctx_count' variable.
*/
if (kcpc_nullctx_panic)
panic("null cpc context, thread %p", (void *)t);
+
+ cmn_err(CE_WARN,
+ "null cpc context found in overflow handler!\n");
atomic_add_32(&kcpc_nullctx_count, 1);
} else if ((ctx->kc_flags & KCPC_CTX_INVALID) == 0) {
/*
@@ -925,8 +953,9 @@ kcpc_overflow_intr(caddr_t arg, uint64_t bitmap)
uint_t
kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2)
{
- kcpc_ctx_t *ctx;
- uint64_t bitmap;
+ kcpc_ctx_t *ctx;
+ uint64_t bitmap;
+ uint8_t *state;
if (pcbe_ops == NULL ||
(bitmap = pcbe_ops->pcbe_overflow_bitmap()) == 0)
@@ -937,8 +966,53 @@ kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2)
*/
pcbe_ops->pcbe_allstop();
+ if (dtrace_cpc_in_use) {
+ state = &cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state;
+
+ /*
+ * Set the per-CPU state bit to indicate that we are currently
+ * processing an interrupt if it is currently free. Drop the
+ * interrupt if the state isn't free (i.e. a configuration
+ * event is taking place).
+ */
+ if (atomic_cas_8(state, DCPC_INTR_FREE,
+ DCPC_INTR_PROCESSING) == DCPC_INTR_FREE) {
+ int i;
+ kcpc_request_t req;
+
+ ASSERT(dtrace_cpc_fire != NULL);
+
+ (*dtrace_cpc_fire)(bitmap);
+
+ ctx = curthread->t_cpu->cpu_cpc_ctx;
+
+ /* Reset any counters that have overflowed */
+ for (i = 0; i < ctx->kc_set->ks_nreqs; i++) {
+ req = ctx->kc_set->ks_req[i];
+
+ if (bitmap & (1 << req.kr_picnum)) {
+ pcbe_ops->pcbe_configure(req.kr_picnum,
+ req.kr_event, req.kr_preset,
+ req.kr_flags, req.kr_nattrs,
+ req.kr_attr, &(req.kr_config),
+ (void *)ctx);
+ }
+ }
+ pcbe_ops->pcbe_program(ctx);
+
+ /*
+ * We've finished processing the interrupt so set
+ * the state back to free.
+ */
+ cpu_core[CPU->cpu_id].cpuc_dcpc_intr_state =
+ DCPC_INTR_FREE;
+ membar_producer();
+ }
+ return (DDI_INTR_CLAIMED);
+ }
+
/*
- * Invoke the "generic" handler.
+ * DTrace isn't involved so pass on accordingly.
*
* If the interrupt has occurred in the context of an lwp owning
* the counters, then the handler posts an AST to the lwp to
@@ -1441,7 +1515,7 @@ kcpc_passivate(void)
* Returns 0 if successful, -1 on failure.
*/
/*ARGSUSED*/
-static int
+int
kcpc_assign_reqs(kcpc_set_t *set, kcpc_ctx_t *ctx)
{
int i;
@@ -1616,3 +1690,33 @@ kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third)
return (modload_qualified("pcbe",
"pcbe", prefix, ".", s, 3, NULL) < 0 ? -1 : 0);
}
+
+char *
+kcpc_list_attrs(void)
+{
+ ASSERT(pcbe_ops != NULL);
+
+ return (pcbe_ops->pcbe_list_attrs());
+}
+
+char *
+kcpc_list_events(uint_t pic)
+{
+ ASSERT(pcbe_ops != NULL);
+
+ return (pcbe_ops->pcbe_list_events(pic));
+}
+
+uint_t
+kcpc_pcbe_capabilities(void)
+{
+ ASSERT(pcbe_ops != NULL);
+
+ return (pcbe_ops->pcbe_caps);
+}
+
+int
+kcpc_pcbe_loaded(void)
+{
+ return (pcbe_ops == NULL ? -1 : 0);
+}
diff --git a/usr/src/uts/common/sys/cpc_impl.h b/usr/src/uts/common/sys/cpc_impl.h
index bb9dc5e6e3..f9f6b4fdfc 100644
--- a/usr/src/uts/common/sys/cpc_impl.h
+++ b/usr/src/uts/common/sys/cpc_impl.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_CPC_IMPL_H
#define _SYS_CPC_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ksynch.h>
@@ -181,6 +179,27 @@ typedef struct __cpc_args32 {
*/
#define KCPC_PIC_OVERFLOWED 0x1 /* pic overflowed & requested notify */
+/*
+ * The following flags are used by the DTrace CPU performance counter provider
+ * and the overflow handler. The 'DCPC_INTR_*' flags are used to synchronize
+ * performance counter configuration events performed by the cpc provider and
+ * interrupt processing carried out by the overflow handler. The 'DCPC_?MASK'
+ * flags are used by the dcpc provider to indicate which type of mask attribute
+ * a platform supports.
+ */
+
+/* No configuration events or overflow interrupts are currently in process. */
+#define DCPC_INTR_FREE 0
+
+/* An overflow interrupt is currently being processed. */
+#define DCPC_INTR_PROCESSING 1
+
+/* The cpc subsystem is currently being configured by the dcpc provider. */
+#define DCPC_INTR_CONFIG 2
+
+#define DCPC_UMASK 1 /* The platform supports a "umask" attribute. */
+#define DCPC_EMASK 2 /* The platform supports an "emask" attribute. */
+
#ifdef __sparc
extern uint64_t ultra_gettick(void);
#define KCPC_GET_TICK ultra_gettick
@@ -204,6 +223,14 @@ extern void kcpc_invalidate_all(void);
extern void kcpc_passivate(void);
extern void kcpc_remote_stop(struct cpu *cp);
extern int kcpc_pcbe_tryload(const char *, uint_t, uint_t, uint_t);
+extern void kcpc_remote_program(struct cpu *cp);
+extern void kcpc_register_dcpc(void (*func)(uint64_t));
+extern void kcpc_unregister_dcpc(void);
+extern kcpc_ctx_t *kcpc_ctx_alloc(void);
+extern int kcpc_assign_reqs(struct _kcpc_set *, kcpc_ctx_t *);
+extern void kcpc_ctx_free(kcpc_ctx_t *);
+extern int kcpc_configure_reqs(kcpc_ctx_t *, struct _kcpc_set *, int *);
+extern void kcpc_free_configs(struct _kcpc_set *);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/cpuvar.h b/usr/src/uts/common/sys/cpuvar.h
index 69e324ffa6..2d056fa6ab 100644
--- a/usr/src/uts/common/sys/cpuvar.h
+++ b/usr/src/uts/common/sys/cpuvar.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -211,6 +211,9 @@ typedef struct cpu {
uint64_t cpu_curr_clock; /* current clock freq in Hz */
char *cpu_supp_freqs; /* supported freqs in Hz */
+ uintptr_t cpu_cpcprofile_pc; /* kernel PC in cpc interrupt */
+ uintptr_t cpu_cpcprofile_upc; /* user PC in cpc interrupt */
+
/*
* Interrupt load factor used by dispatcher & softcall
*/
@@ -240,12 +243,13 @@ typedef struct cpu {
* is up to the platform to assure that this is performed properly. Note that
* the structure is sized to avoid false sharing.
*/
-#define CPUC_SIZE (sizeof (uint16_t) + sizeof (uintptr_t) + \
- sizeof (kmutex_t))
+#define CPUC_SIZE (sizeof (uint16_t) + sizeof (uint8_t) + \
+ sizeof (uintptr_t) + sizeof (kmutex_t))
#define CPUC_PADSIZE CPU_CACHE_COHERENCE_SIZE - CPUC_SIZE
typedef struct cpu_core {
uint16_t cpuc_dtrace_flags; /* DTrace flags */
+ uint8_t cpuc_dcpc_intr_state; /* DCPC provider intr state */
uint8_t cpuc_pad[CPUC_PADSIZE]; /* padding */
uintptr_t cpuc_dtrace_illval; /* DTrace illegal value */
kmutex_t cpuc_pid_lock; /* DTrace pid provider lock */
@@ -715,7 +719,8 @@ typedef enum {
CPU_ON,
CPU_OFF,
CPU_CPUPART_IN,
- CPU_CPUPART_OUT
+ CPU_CPUPART_OUT,
+ CPU_SETUP
} cpu_setup_t;
typedef int cpu_setup_func_t(cpu_setup_t, int, void *);
diff --git a/usr/src/uts/common/sys/dtrace.h b/usr/src/uts/common/sys/dtrace.h
index b6e52ec1c4..046dd13dd4 100644
--- a/usr/src/uts/common/sys/dtrace.h
+++ b/usr/src/uts/common/sys/dtrace.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_DTRACE_H
#define _SYS_DTRACE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -1382,7 +1380,7 @@ typedef struct dof_helper {
* dtps_provide_module(); see "Arguments and Notes" for dtrace_register(),
* below.
*
- * 1.4 void dtps_enable(void *arg, dtrace_id_t id, void *parg)
+ * 1.4 int dtps_enable(void *arg, dtrace_id_t id, void *parg)
*
* 1.4.1 Overview
*
@@ -1403,7 +1401,8 @@ typedef struct dof_helper {
*
* 1.4.3 Return value
*
- * None.
+ * On success, dtps_enable() should return 0. On failure, -1 should be
+ * returned.
*
* 1.4.4 Caller's context
*
@@ -1957,7 +1956,7 @@ typedef struct dof_helper {
typedef struct dtrace_pops {
void (*dtps_provide)(void *arg, const dtrace_probedesc_t *spec);
void (*dtps_provide_module)(void *arg, struct modctl *mp);
- void (*dtps_enable)(void *arg, dtrace_id_t id, void *parg);
+ int (*dtps_enable)(void *arg, dtrace_id_t id, void *parg);
void (*dtps_disable)(void *arg, dtrace_id_t id, void *parg);
void (*dtps_suspend)(void *arg, dtrace_id_t id, void *parg);
void (*dtps_resume)(void *arg, dtrace_id_t id, void *parg);
diff --git a/usr/src/uts/common/sys/kcpc.h b/usr/src/uts/common/sys/kcpc.h
index 0763723bdf..f30e093f78 100644
--- a/usr/src/uts/common/sys/kcpc.h
+++ b/usr/src/uts/common/sys/kcpc.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_KCPC_H
#define _SYS_KCPC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/cpc_impl.h>
#include <sys/ksynch.h>
@@ -130,11 +128,24 @@ extern void kcpc_idle_restore(struct cpu *cp);
extern krwlock_t kcpc_cpuctx_lock; /* lock for 'kcpc_cpuctx' below */
extern int kcpc_cpuctx; /* number of cpu-specific contexts */
+/*
+ * 'dtrace_cpc_in_use' contains the number of currently active cpc provider
+ * based enablings. See the block comment in uts/common/os/dtrace_subr.c for
+ * details of its actual usage.
+ */
+extern uint32_t dtrace_cpc_in_use;
+extern void (*dtrace_cpc_fire)(uint64_t);
+
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);
+extern char *kcpc_list_attrs(void);
+extern char *kcpc_list_events(uint_t pic);
+extern void kcpc_free_configs(kcpc_set_t *set);
+extern uint_t kcpc_pcbe_capabilities(void);
+extern int kcpc_pcbe_loaded(void);
/*
* Called by a PCBE to determine if nonprivileged access to counters should be
diff --git a/usr/src/uts/common/xen/dtrace/xdt.c b/usr/src/uts/common/xen/dtrace/xdt.c
index bac7f100e9..85c876b479 100644
--- a/usr/src/uts/common/xen/dtrace/xdt.c
+++ b/usr/src/uts/common/xen/dtrace/xdt.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -782,7 +782,7 @@ xdt_set_trace_mask(uint32_t mask)
}
/*ARGSUSED*/
-static void
+static int
xdt_enable(void *arg, dtrace_id_t id, void *parg)
{
xdt_probe_t *p = parg;
@@ -801,22 +801,15 @@ xdt_enable(void *arg, dtrace_id_t id, void *parg)
}
if (xdt_cyclic == CYCLIC_NONE) {
- /*
- * DTrace doesn't have the notion of failing an enabling. It
- * works on the premise that, if you have advertised a probe
- * via the pops->dtps_provide() function, you can enable it.
- * Failure is not an option. In the case where we can't enable
- * Xen tracing the consumer will carry on regardless and
- * think all is OK except the probes will never fire.
- */
tbuf_op.cmd = XEN_SYSCTL_TBUFOP_enable;
if (xdt_sysctl_tbuf(&tbuf_op) != 0) {
cmn_err(CE_NOTE, "Couldn't enable hypervisor tracing.");
- return;
+ return (-1);
}
xdt_cyclic_enable();
}
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/i86pc/os/intr.c b/usr/src/uts/i86pc/os/intr.c
index 12d4304973..2f4b66ddf2 100644
--- a/usr/src/uts/i86pc/os/intr.c
+++ b/usr/src/uts/i86pc/os/intr.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/cpuvar.h>
#include <sys/regset.h>
#include <sys/psw.h>
@@ -121,9 +119,13 @@ hilevel_intr_prolog(struct cpu *cpu, uint_t pil, uint_t oldpil, struct regs *rp)
if (USERMODE(rp->r_cs)) {
cpu->cpu_profile_pc = 0;
cpu->cpu_profile_upc = rp->r_pc;
+ cpu->cpu_cpcprofile_pc = 0;
+ cpu->cpu_cpcprofile_upc = rp->r_pc;
} else {
cpu->cpu_profile_pc = rp->r_pc;
cpu->cpu_profile_upc = 0;
+ cpu->cpu_cpcprofile_pc = rp->r_pc;
+ cpu->cpu_cpcprofile_upc = 0;
}
}
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index 19a59af0d0..54eb2f4369 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1405,6 +1405,10 @@ start_other_cpus(int cprboot)
}
if (start_cpu(who) != 0)
CPUSET_DEL(mp_cpus, who);
+
+ mutex_enter(&cpu_lock);
+ cpu_state_change_notify(who, CPU_SETUP);
+ mutex_exit(&cpu_lock);
}
/* Free the space allocated to hold the microcode file */
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index 95c2dd9538..134a4030ad 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -387,6 +387,7 @@ DRV_KMODS += profile
DRV_KMODS += sdt
DRV_KMODS += systrace
DRV_KMODS += fasttrap
+DRV_KMODS += dcpc
#
# I/O framework test drivers
diff --git a/usr/src/uts/intel/dcpc/Makefile b/usr/src/uts/intel/dcpc/Makefile
new file mode 100644
index 0000000000..6378018a34
--- /dev/null
+++ b/usr/src/uts/intel/dcpc/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+UTSBASE = ../..
+
+MODULE = dcpc
+OBJECTS = $(DCPC_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(DCPC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+ROOTLINK = $(ROOT_DTRACE_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/dtrace
+
+ALL_TARGET = $(BINARY) $(SRC_CONFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+INC_PATH += -I$(UTSBASE)/i86pc
+
+include $(UTSBASE)/intel/Makefile.intel
+
+LDFLAGS += -dy -Ndrv/dtrace -Ndrv/cpc
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+$(ROOTLINK): $(ROOT_DTRACE_DIR) $(ROOTMODULE)
+ -$(RM) $@; ln $(ROOTMODULE) $@
+
+include $(UTSBASE)/intel/Makefile.targ
diff --git a/usr/src/uts/intel/dtrace/fbt.c b/usr/src/uts/intel/dtrace/fbt.c
index a5a4292a61..b9353bd30c 100644
--- a/usr/src/uts/intel/dtrace/fbt.c
+++ b/usr/src/uts/intel/dtrace/fbt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -486,7 +486,7 @@ fbt_destroy(void *arg, dtrace_id_t id, void *parg)
}
/*ARGSUSED*/
-static void
+static int
fbt_enable(void *arg, dtrace_id_t id, void *parg)
{
fbt_probe_t *fbt = parg;
@@ -501,7 +501,7 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg)
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ return (0);
}
/*
@@ -516,11 +516,13 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg)
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ return (0);
}
for (; fbt != NULL; fbt = fbt->fbtp_next)
*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/intel/dtrace/sdt.c b/usr/src/uts/intel/dtrace/sdt.c
index 5217ea6ae3..38be2233b1 100644
--- a/usr/src/uts/intel/dtrace/sdt.c
+++ b/usr/src/uts/intel/dtrace/sdt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -229,7 +229,7 @@ sdt_destroy(void *arg, dtrace_id_t id, void *parg)
}
/*ARGSUSED*/
-static void
+static int
sdt_enable(void *arg, dtrace_id_t id, void *parg)
{
sdt_probe_t *sdp = parg;
@@ -269,7 +269,7 @@ sdt_enable(void *arg, dtrace_id_t id, void *parg)
sdp = sdp->sdp_next;
}
err:
- ;
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/intel/ia32/os/cpc_subr.c b/usr/src/uts/intel/ia32/os/cpc_subr.c
index 62929f6414..466cf6ba9f 100644
--- a/usr/src/uts/intel/ia32/os/cpc_subr.c
+++ b/usr/src/uts/intel/ia32/os/cpc_subr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -292,3 +292,28 @@ kcpc_hw_lwp_hook(void)
mutex_exit(&cpu_lock);
return (0);
}
+
+static int
+kcpc_remoteprogram_func(void)
+{
+ ASSERT(CPU->cpu_cpc_ctx != NULL);
+
+ pcbe_ops->pcbe_program(CPU->cpu_cpc_ctx);
+
+ return (0);
+}
+
+/*
+ * Ensure counters are enabled on the given processor.
+ */
+void
+kcpc_remote_program(cpu_t *cp)
+{
+ cpuset_t set;
+
+ CPUSET_ZERO(set);
+
+ CPUSET_ADD(set, cp->cpu_id);
+
+ xc_sync(0, 0, 0, X_CALL_HIPRI, set, (xc_func_t)kcpc_remoteprogram_func);
+}
diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major
index eb70695abd..973020e4c9 100644
--- a/usr/src/uts/intel/os/name_to_major
+++ b/usr/src/uts/intel/os/name_to_major
@@ -130,6 +130,7 @@ domcaps 200
balloon 201
acpippm 202
srn 203
+dcpc 204
smbsrv 210
did 239
lx_ptm 240
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 39fba551aa..2dd7a8675c 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -203,7 +203,7 @@ ALL_DEFS = $(MACHINE_DEFS) $(DEBUG_DEFS) $(OPTION_DEFS)
#
DRV_KMODS += aggr arp bl bofi clone cn conskbd consms cpuid
DRV_KMODS += crypto cryptoadm devinfo dump
-DRV_KMODS += dtrace fasttrap fbt lockstat profile sdt systrace
+DRV_KMODS += dtrace fasttrap fbt lockstat profile sdt systrace dcpc
DRV_KMODS += fssnap icmp icmp6 ip ip6 ipnet ipsecah
DRV_KMODS += ipsecesp iwscn keysock kmdb kstat ksyms llc1
DRV_KMODS += lofi
diff --git a/usr/src/uts/sparc/dcpc/Makefile b/usr/src/uts/sparc/dcpc/Makefile
new file mode 100644
index 0000000000..1a8c50de78
--- /dev/null
+++ b/usr/src/uts/sparc/dcpc/Makefile
@@ -0,0 +1,65 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+UTSBASE = ../..
+
+MODULE = dcpc
+OBJECTS = $(DCPC_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(DCPC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+ROOTLINK = $(ROOT_DTRACE_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/dtrace
+
+ALL_TARGET = $(BINARY) $(SRC_CONFILE)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE)
+
+include $(UTSBASE)/sparc/Makefile.sparc
+
+LDFLAGS += -dy -Ndrv/dtrace -Ndrv/cpc
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+$(ROOTLINK): $(ROOT_DTRACE_DIR) $(ROOTMODULE)
+ -$(RM) $@; ln $(ROOTMODULE) $@
+
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sparc/dtrace/fbt.c b/usr/src/uts/sparc/dtrace/fbt.c
index a2eba46965..58169bac81 100644
--- a/usr/src/uts/sparc/dtrace/fbt.c
+++ b/usr/src/uts/sparc/dtrace/fbt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1483,7 +1483,7 @@ fbt_destroy(void *arg, dtrace_id_t id, void *parg)
}
/*ARGSUSED*/
-static void
+static int
fbt_enable(void *arg, dtrace_id_t id, void *parg)
{
fbt_probe_t *fbt = parg, *f;
@@ -1503,7 +1503,7 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg)
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ return (0);
}
}
@@ -1518,7 +1518,7 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg)
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ return (0);
}
/*
@@ -1533,11 +1533,13 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg)
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ return (0);
}
for (; fbt != NULL; fbt = fbt->fbtp_next)
*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/sparc/dtrace/sdt.c b/usr/src/uts/sparc/dtrace/sdt.c
index ce6656e8ee..af9ea8e155 100644
--- a/usr/src/uts/sparc/dtrace/sdt.c
+++ b/usr/src/uts/sparc/dtrace/sdt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -269,7 +269,7 @@ sdt_destroy(void *arg, dtrace_id_t id, void *parg)
}
/*ARGSUSED*/
-static void
+static int
sdt_enable(void *arg, dtrace_id_t id, void *parg)
{
sdt_probe_t *sdp = parg;
@@ -310,7 +310,7 @@ sdt_enable(void *arg, dtrace_id_t id, void *parg)
}
err:
- ;
+ return (0);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major
index 9702d00ad7..1346b28e45 100644
--- a/usr/src/uts/sparc/os/name_to_major
+++ b/usr/src/uts/sparc/os/name_to_major
@@ -227,3 +227,4 @@ bmc 278
fm 279
nulldriver 280
ipnet 281
+dcpc 282
diff --git a/usr/src/uts/sun4/cpu/cpu_module.c b/usr/src/uts/sun4/cpu/cpu_module.c
index 717cc26f90..f20d13276b 100644
--- a/usr/src/uts/sun4/cpu/cpu_module.c
+++ b/usr/src/uts/sun4/cpu/cpu_module.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/cpu_module.h>
#include <sys/lockstat.h>
@@ -328,6 +326,10 @@ void
pil14_interrupt(void)
{ }
+void
+pil15_interrupt(void)
+{ }
+
/* ARGSUSED */
void
cpu_init_private(struct cpu *cp)
diff --git a/usr/src/uts/sun4/ml/offsets.in b/usr/src/uts/sun4/ml/offsets.in
index d28b700fdd..c4ce99506e 100644
--- a/usr/src/uts/sun4/ml/offsets.in
+++ b/usr/src/uts/sun4/ml/offsets.in
@@ -1,5 +1,5 @@
\ offsets.in: input file to produce assym.h using the stabs program
-\ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
\ CDDL HEADER START
@@ -68,8 +68,6 @@
\ and all of the nested structures/unions together. See the many
\ examples already in this file.
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef _GENASSYM
#define _GENASSYM
#endif
@@ -365,6 +363,8 @@ cpu CPUSIZE
cpu_ftrace.ftd_state CPU_FTRACE_STATE
cpu_mstate
cpu_intracct
+ cpu_cpcprofile_pc
+ cpu_cpcprofile_upc
cpu_m CPU_MCPU
cpu_m.divisor CPU_DIVISOR
cpu_m.intrstat CPU_INTRSTAT
diff --git a/usr/src/uts/sun4/os/mp_startup.c b/usr/src/uts/sun4/os/mp_startup.c
index 6d51e89b6e..658495a382 100644
--- a/usr/src/uts/sun4/os/mp_startup.c
+++ b/usr/src/uts/sun4/os/mp_startup.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -753,10 +753,8 @@ start_other_cpus(int flag)
cmn_err(CE_CONT, "!cpu%d initialization complete - online\n",
cpuid);
- /*
- * XXX: register_cpu_setup() callbacks should be called here
- * with a new setup code, CPU_BOOT (or something).
- */
+ cpu_state_change_notify(cpuid, CPU_SETUP);
+
if (dtrace_cpu_init != NULL)
(*dtrace_cpu_init)(cpuid);
}
diff --git a/usr/src/uts/sun4/os/startup.c b/usr/src/uts/sun4/os/startup.c
index a8c2a585db..1459eb1ce4 100644
--- a/usr/src/uts/sun4/os/startup.c
+++ b/usr/src/uts/sun4/os/startup.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2107,6 +2107,11 @@ startup_end(void)
kern_setup1();
/*
+ * Perform CPC initialization for this CPU.
+ */
+ kcpc_hw_init();
+
+ /*
* Intialize the VM arenas for allocating physically
* contiguus memory chunk for interrupt queues snd
* allocate/register boot cpu's queues, if any and
diff --git a/usr/src/uts/sun4u/cpu/common_asm.s b/usr/src/uts/sun4u/cpu/common_asm.s
index b13ec0ef67..46c12c4775 100644
--- a/usr/src/uts/sun4u/cpu/common_asm.s
+++ b/usr/src/uts/sun4u/cpu/common_asm.s
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#if !defined(lint)
#include "assym.h"
#endif /* !lint */
@@ -1056,6 +1054,34 @@ pil14_interrupt(int level)
#endif /* lint */
+#if defined(lint)
+
+/* ARGSUSED */
+void
+pil15_interrupt(int level)
+{}
+
+#else /* lint */
+
+/*
+ * Level-15 interrupt prologue.
+ */
+ ENTRY_NP(pil15_interrupt)
+ CPU_ADDR(%g1, %g2)
+ rdpr %tstate, %g6
+ rdpr %tpc, %g5
+ btst TSTATE_PRIV, %g6 ! trap from supervisor mode?
+ bnz,a,pt %xcc, 1f
+ stn %g5, [%g1 + CPU_CPCPROFILE_PC] ! if so, record kernel PC
+ stn %g5, [%g1 + CPU_CPCPROFILE_UPC] ! if not, record user PC
+ ba pil15_epilogue ! must be large-disp branch
+ stn %g0, [%g1 + CPU_CPCPROFILE_PC] ! zero kernel PC
+1: ba pil15_epilogue ! must be large-disp branch
+ stn %g0, [%g1 + CPU_CPCPROFILE_UPC] ! zero user PC
+ SET_SIZE(pil15_interrupt)
+
+#endif /* lint */
+
#if defined(lint) || defined(__lint)
/* ARGSUSED */
diff --git a/usr/src/uts/sun4u/cpu/us3_cheetah.c b/usr/src/uts/sun4u/cpu/us3_cheetah.c
index 44fefd1ecf..eadaebc099 100644
--- a/usr/src/uts/sun4u/cpu/us3_cheetah.c
+++ b/usr/src/uts/sun4u/cpu/us3_cheetah.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/ddi.h>
@@ -79,7 +77,7 @@
void
cpu_init_trap(void)
{
- CH_SET_TRAP(tt_pil15, ch_pil15_interrupt_instr);
+ CH_SET_TRAP(pil15_epilogue, ch_pil15_interrupt_instr);
CH_SET_TRAP(tt0_fecc, fecc_err_instr);
CH_SET_TRAP(tt1_fecc, fecc_err_tl1_instr);
diff --git a/usr/src/uts/sun4u/cpu/us3_cheetahplus.c b/usr/src/uts/sun4u/cpu/us3_cheetahplus.c
index 52a664c3eb..7cda4df713 100644
--- a/usr/src/uts/sun4u/cpu/us3_cheetahplus.c
+++ b/usr/src/uts/sun4u/cpu/us3_cheetahplus.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/ddi.h>
@@ -89,7 +87,7 @@ static cpu_t *cpu_get_sibling_core(cpu_t *cpup);
void
cpu_init_trap(void)
{
- CH_SET_TRAP(tt_pil15, ch_pil15_interrupt_instr);
+ CH_SET_TRAP(pil15_epilogue, ch_pil15_interrupt_instr);
CH_SET_TRAP(tt0_fecc, fecc_err_instr);
CH_SET_TRAP(tt1_fecc, fecc_err_tl1_instr);
diff --git a/usr/src/uts/sun4u/cpu/us3_jalapeno.c b/usr/src/uts/sun4u/cpu/us3_jalapeno.c
index 6bbd1a3d4a..bb0cb0c961 100644
--- a/usr/src/uts/sun4u/cpu/us3_jalapeno.c
+++ b/usr/src/uts/sun4u/cpu/us3_jalapeno.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/ddi.h>
@@ -102,7 +100,7 @@ uint64_t jp_estar_tl1_data[8];
void
cpu_init_trap(void)
{
- CH_SET_TRAP(tt_pil15, ch_pil15_interrupt_instr);
+ CH_SET_TRAP(pil15_epilogue, ch_pil15_interrupt_instr);
CH_SET_TRAP(tt0_fecc, fecc_err_instr);
CH_SET_TRAP(tt1_fecc, fecc_err_tl1_instr);
diff --git a/usr/src/uts/sun4u/ml/trap_table.s b/usr/src/uts/sun4u/ml/trap_table.s
index 8b8e15d926..e8219e3017 100644
--- a/usr/src/uts/sun4u/ml/trap_table.s
+++ b/usr/src/uts/sun4u/ml/trap_table.s
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#if !defined(lint)
#include "assym.h"
#endif /* !lint */
@@ -940,6 +938,11 @@ tt_pil/**/level: ;\
mov PIL_14, %g4 ;\
.align 32
+#define LEVEL15_INTERRUPT \
+ ba pil15_interrupt ;\
+ mov PIL_15, %g4 ;\
+ .align 32
+
#define VECTOR_INTERRUPT \
ldxa [%g0]ASI_INTR_RECEIVE_STATUS, %g1 ;\
btst IRSR_BUSY, %g1 ;\
@@ -1405,7 +1408,7 @@ trap_table0:
LEVEL_INTERRUPT(12); /* 04C interrupt level 12 */
LEVEL_INTERRUPT(13); /* 04D interrupt level 13 */
LEVEL14_INTERRUPT; /* 04E interrupt level 14 */
- LEVEL_INTERRUPT(15); /* 04F interrupt level 15 */
+ LEVEL15_INTERRUPT; /* 04F interrupt level 15 */
NOT4; NOT4; NOT4; NOT4; /* 050 - 05F reserved */
VECTOR_INTERRUPT; /* 060 interrupt vector */
GOTO(kmdb_trap); /* 061 PA watchpoint */
@@ -2927,6 +2930,13 @@ trace_dataprot:
#endif /* TRAPTRACE */
+ .align 32
+ .global pil15_epilogue
+pil15_epilogue:
+ ba pil_interrupt_common
+ nop
+ .align 32
+
/*
* fast_trap_done, fast_trap_done_chk_intr:
*
diff --git a/usr/src/uts/sun4u/os/cpc_subr.c b/usr/src/uts/sun4u/os/cpc_subr.c
index 5a814e0aa7..a9c64681fd 100644
--- a/usr/src/uts/sun4u/os/cpc_subr.c
+++ b/usr/src/uts/sun4u/os/cpc_subr.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* sun4u common CPC subroutines.
*/
@@ -48,8 +46,8 @@
#include <sys/modctl.h>
#include <sys/sdt.h>
-uint64_t cpc_level15_inum; /* used in interrupt.s */
-int cpc_has_overflow_intr; /* set in cheetah.c */
+uint64_t cpc_level15_inum; /* used in interrupt.s */
+int cpc_has_overflow_intr; /* set in cheetah.c */
extern kcpc_ctx_t *kcpc_overflow_intr(caddr_t arg, uint64_t bitmap);
extern int kcpc_counts_include_idle;
@@ -144,3 +142,21 @@ kcpc_hw_lwp_hook(void)
{
return (0);
}
+
+/*ARGSUSED*/
+static void
+kcpc_remoteprogram_func(uint64_t arg1, uint64_t arg2)
+{
+ ASSERT(CPU->cpu_cpc_ctx != NULL);
+
+ pcbe_ops->pcbe_program(CPU->cpu_cpc_ctx);
+}
+
+/*
+ * Ensure counters are enabled on the given processor.
+ */
+void
+kcpc_remote_program(cpu_t *cp)
+{
+ xc_one(cp->cpu_id, kcpc_remoteprogram_func, 0, 0);
+}
diff --git a/usr/src/uts/sun4u/sys/us3_module.h b/usr/src/uts/sun4u/sys/us3_module.h
index 2244915ab3..77ee9fceb7 100644
--- a/usr/src/uts/sun4u/sys/us3_module.h
+++ b/usr/src/uts/sun4u/sys/us3_module.h
@@ -19,14 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_US3_MODULE_H
#define _SYS_US3_MODULE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/async.h>
#ifdef __cplusplus
@@ -661,7 +660,7 @@ extern void *tt1_swtrap0;
/*
* Address of trap table level 15 interrupt handler in the trap table.
*/
-extern void *tt_pil15;
+extern void *pil15_epilogue;
/*
* D$ and I$ global parameters.
*/
diff --git a/usr/src/uts/sun4v/cpu/common_asm.s b/usr/src/uts/sun4v/cpu/common_asm.s
index d0d017824e..cf30c07365 100644
--- a/usr/src/uts/sun4v/cpu/common_asm.s
+++ b/usr/src/uts/sun4v/cpu/common_asm.s
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -870,6 +870,34 @@ pil14_interrupt(int level)
#endif /* lint */
#if defined(lint)
+
+/* ARGSUSED */
+void
+pil15_interrupt(int level)
+{}
+
+#else /* lint */
+
+/*
+ * Level-15 interrupt prologue.
+ */
+ ENTRY_NP(pil15_interrupt)
+ CPU_ADDR(%g1, %g2)
+ rdpr %tstate, %g6
+ rdpr %tpc, %g5
+ btst TSTATE_PRIV, %g6 ! trap from supervisor mode?
+ bnz,a,pt %xcc, 1f
+ stn %g5, [%g1 + CPU_CPCPROFILE_PC] ! if so, record kernel PC
+ stn %g5, [%g1 + CPU_CPCPROFILE_UPC] ! if not, record user PC
+ ba pil15_epilogue ! must be large-disp branch
+ stn %g0, [%g1 + CPU_CPCPROFILE_PC] ! zero kernel PC
+1: ba pil15_epilogue ! must be large-disp branch
+ stn %g0, [%g1 + CPU_CPCPROFILE_UPC] ! zero user PC
+ SET_SIZE(pil15_interrupt)
+
+#endif /* lint */
+
+#if defined(lint)
/*
* Prefetch a page_t for write or read, this assumes a linear
* scan of sequential page_t's.
diff --git a/usr/src/uts/sun4v/ml/trap_table.s b/usr/src/uts/sun4v/ml/trap_table.s
index 0d3876f79a..cbe2eccd8d 100644
--- a/usr/src/uts/sun4v/ml/trap_table.s
+++ b/usr/src/uts/sun4v/ml/trap_table.s
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -807,6 +807,11 @@ tt_pil/**/level: ;\
mov PIL_14, %g4 ;\
.align 32
+#define LEVEL15_INTERRUPT \
+ ba pil15_interrupt ;\
+ mov PIL_15, %g4 ;\
+ .align 32
+
#define CPU_MONDO \
ba,a,pt %xcc, cpu_mondo ;\
.align 32
@@ -1171,7 +1176,7 @@ trap_table0:
LEVEL_INTERRUPT(12); /* 04C interrupt level 12 */
LEVEL_INTERRUPT(13); /* 04D interrupt level 13 */
LEVEL14_INTERRUPT; /* 04E interrupt level 14 */
- LEVEL_INTERRUPT(15); /* 04F interrupt level 15 */
+ LEVEL15_INTERRUPT; /* 04F interrupt level 15 */
NOT4; NOT4; NOT4; NOT4; /* 050 - 05F reserved */
NOT; /* 060 interrupt vector */
GOTO(kmdb_trap); /* 061 PA watchpoint */
@@ -2766,6 +2771,13 @@ trace_dataprot:
mov T_DATA_EXCEPTION, %g1
SET_SIZE(.dmmu_exception)
+ .align 32
+ .global pil15_epilogue
+pil15_epilogue:
+ ba pil_interrupt_common
+ nop
+ .align 32
+
/*
* fast_trap_done, fast_trap_done_chk_intr:
*
diff --git a/usr/src/uts/sun4v/os/cpc_subr.c b/usr/src/uts/sun4v/os/cpc_subr.c
index 7944fb9e02..8e58d85513 100644
--- a/usr/src/uts/sun4v/os/cpc_subr.c
+++ b/usr/src/uts/sun4v/os/cpc_subr.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* sun4u common CPC subroutines.
*/
@@ -48,8 +46,8 @@
#include <sys/modctl.h>
#include <sys/sdt.h>
-uint64_t cpc_level15_inum; /* used in interrupt.s */
-int cpc_has_overflow_intr; /* set in cheetah.c */
+uint64_t cpc_level15_inum; /* used in interrupt.s */
+int cpc_has_overflow_intr; /* set in cheetah.c */
extern kcpc_ctx_t *kcpc_overflow_intr(caddr_t arg, uint64_t bitmap);
extern int kcpc_counts_include_idle;
@@ -163,3 +161,21 @@ kcpc_hw_lwp_hook(void)
{
return (0);
}
+
+/*ARGSUSED*/
+static void
+kcpc_remoteprogram_func(uint64_t arg1, uint64_t arg2)
+{
+ ASSERT(CPU->cpu_cpc_ctx != NULL);
+
+ pcbe_ops->pcbe_program(CPU->cpu_cpc_ctx);
+}
+
+/*
+ * Ensure counters are enabled on the given processor.
+ */
+void
+kcpc_remote_program(cpu_t *cp)
+{
+ xc_one(cp->cpu_id, kcpc_remoteprogram_func, 0, 0);
+}