changeset 13660:1905bad7dc63

2581 Observability for AMD Core Performance Boost Reviewed by: Milan Jurik <milan.jurik@xylab.cz> Reviewed by: Gordon Ross <gordon.w.ross@gmail.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
date Tue, 03 Apr 2012 15:45:02 -0500
parents 57451298f940
children 34a2ada0dd49
files usr/src/cmd/powertop/common/display.c usr/src/uts/i86pc/Makefile.files usr/src/uts/i86pc/os/cpupm/pwrnow.c usr/src/uts/i86pc/os/cpupm/speedstep.c usr/src/uts/i86pc/os/cpupm/turbo.c usr/src/uts/i86pc/sys/cpupm_mach.h
diffstat 6 files changed, 295 insertions(+), 197 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/powertop/common/display.c	Thu Apr 05 08:47:21 2012 -0500
+++ b/usr/src/cmd/powertop/common/display.c	Tue Apr 03 15:45:02 2012 -0500
@@ -454,14 +454,26 @@
 		 * mode is supported
 		 */
 		if (g_turbo_supported) {
+			int p_diff = 1;
+			p0_speed = g_pstate_info[g_npstates - 1].speed;
 			p1_speed = g_pstate_info[g_npstates - 2].speed;
 
 			/*
+			 * AMD systems don't have a visible extra Pstate
+			 * indicating turbo mode as Intel does. Use the
+			 * actual P0 frequency in that case.
+			 */
+			if (p0_speed != p1_speed + 1) {
+				p1_speed = p0_speed;
+				p_diff = 0;
+			}
+
+			/*
 			 * If g_turbo_ratio <= 1.0, it will be ignored.
-			 * we display P(0) as P(1) + 1.
+			 * we display P(0) as P(1) + p_diff.
 			 */
 			if (g_turbo_ratio <= 1.0) {
-				p0_speed = p1_speed + 1;
+				p0_speed = p1_speed + p_diff;
 			} else {
 				/*
 				 * If g_turbo_ratio > 1.0, that means
@@ -470,8 +482,8 @@
 				 */
 				p0_speed = (uint64_t)(p1_speed *
 				    g_turbo_ratio);
-				if (p0_speed < (p1_speed + 1))
-					p0_speed = p1_speed + 1;
+				if (p0_speed < (p1_speed + p_diff))
+					p0_speed = p1_speed + p_diff;
 			}
 			/*
 			 * Reset the ratio for the next round
--- a/usr/src/uts/i86pc/Makefile.files	Thu Apr 05 08:47:21 2012 -0500
+++ b/usr/src/uts/i86pc/Makefile.files	Tue Apr 03 15:45:02 2012 -0500
@@ -114,6 +114,7 @@
 	timestamp.o		\
 	todpc_subr.o		\
 	trap.o			\
+	turbo.o			\
 	vm_machdep.o		\
 	xpv_platform.o		\
 	x_call.o
--- a/usr/src/uts/i86pc/os/cpupm/pwrnow.c	Thu Apr 05 08:47:21 2012 -0500
+++ b/usr/src/uts/i86pc/os/cpupm/pwrnow.c	Tue Apr 03 15:45:02 2012 -0500
@@ -38,6 +38,8 @@
 static void pwrnow_power(cpuset_t, uint32_t);
 static void pwrnow_stop(cpu_t *);
 
+static boolean_t pwrnow_cpb_supported(void);
+
 /*
  * Interfaces for modules implementing AMD's PowerNow!.
  */
@@ -67,6 +69,7 @@
 
 #define	AMD_CPUID_PSTATE_HARDWARE	(1<<7)
 #define	AMD_CPUID_TSC_CONSTANT		(1<<8)
+#define	AMD_CPUID_CPB			(1<<9)
 
 /*
  * Debugging support
@@ -128,6 +131,10 @@
 	ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate);
 	write_ctrl(handle, ctrl);
 
+	if (mach_state->ms_turbo != NULL)
+		cpupm_record_turbo_info(mach_state->ms_turbo,
+		    mach_state->ms_pstate.cma_state.pstate, req_state);
+
 	mach_state->ms_pstate.cma_state.pstate = req_state;
 	cpu_set_curr_clock((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000);
 }
@@ -192,6 +199,12 @@
 
 	cpupm_alloc_domains(cp, CPUPM_P_STATES);
 
+	/*
+	 * Check for Core Performance Boost support
+	 */
+	if (pwrnow_cpb_supported())
+		mach_state->ms_turbo = cpupm_turbo_init(cp);
+
 	PWRNOW_DEBUG(("Processor %d succeeded.\n", cp->cpu_id))
 	return (PWRNOW_RET_SUCCESS);
 }
@@ -208,6 +221,10 @@
 
 	cpupm_free_domains(&cpupm_pstate_domains);
 	cpu_acpi_free_pstate_data(handle);
+
+	if (mach_state->ms_turbo != NULL)
+		cpupm_turbo_fini(mach_state->ms_turbo);
+	mach_state->ms_turbo = NULL;
 }
 
 boolean_t
@@ -249,6 +266,30 @@
 	return (B_TRUE);
 }
 
+static boolean_t
+pwrnow_cpb_supported(void)
+{
+	struct cpuid_regs cpu_regs;
+
+	/* Required features */
+	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
+	    !is_x86_feature(x86_featureset, X86FSET_MSR)) {
+		PWRNOW_DEBUG(("No CPUID or MSR support."));
+		return (B_FALSE);
+	}
+
+	/*
+	 * Get the Advanced Power Management Information.
+	 */
+	cpu_regs.cp_eax = 0x80000007;
+	(void) __cpuid_insn(&cpu_regs);
+
+	if (!(cpu_regs.cp_edx & AMD_CPUID_CPB))
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
 static void
 pwrnow_stop(cpu_t *cp)
 {
@@ -258,4 +299,8 @@
 
 	cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains);
 	cpu_acpi_free_pstate_data(handle);
+
+	if (mach_state->ms_turbo != NULL)
+		cpupm_turbo_fini(mach_state->ms_turbo);
+	mach_state->ms_turbo = NULL;
 }
--- a/usr/src/uts/i86pc/os/cpupm/speedstep.c	Thu Apr 05 08:47:21 2012 -0500
+++ b/usr/src/uts/i86pc/os/cpupm/speedstep.c	Tue Apr 03 15:45:02 2012 -0500
@@ -38,33 +38,11 @@
 #include <sys/dtrace.h>
 #include <sys/sdt.h>
 
-/*
- * turbo related structure definitions
- */
-typedef struct cpupm_turbo_info {
-	kstat_t		*turbo_ksp;		/* turbo kstat */
-	int		in_turbo;		/* in turbo? */
-	int		turbo_supported;	/* turbo flag */
-	uint64_t	t_mcnt;			/* turbo mcnt */
-	uint64_t	t_acnt;			/* turbo acnt */
-} cpupm_turbo_info_t;
-
-typedef struct turbo_kstat_s {
-	struct kstat_named	turbo_supported;	/* turbo flag */
-	struct kstat_named	t_mcnt;			/* IA32_MPERF_MSR */
-	struct kstat_named	t_acnt;			/* IA32_APERF_MSR */
-} turbo_kstat_t;
-
 static int speedstep_init(cpu_t *);
 static void speedstep_fini(cpu_t *);
 static void speedstep_power(cpuset_t, uint32_t);
 static void speedstep_stop(cpu_t *);
-static boolean_t turbo_supported(void);
-static int turbo_kstat_update(kstat_t *, int);
-static void get_turbo_info(cpupm_turbo_info_t *);
-static void reset_turbo_info(void);
-static void record_turbo_info(cpupm_turbo_info_t *, uint32_t, uint32_t);
-static void update_turbo_info(cpupm_turbo_info_t *);
+static boolean_t speedstep_turbo_supported(void);
 
 /*
  * Interfaces for modules implementing Intel's Enhanced SpeedStep.
@@ -96,16 +74,6 @@
 #define	IA32_MISC_ENABLE_CXE		(1<<25)
 
 #define	CPUID_TURBO_SUPPORT		(1 << 1)
-#define	CPU_ACPI_P0			0
-#define	CPU_IN_TURBO			1
-
-/*
- * MSR for hardware coordination feedback mechanism
- *   - IA32_MPERF: increments in proportion to a fixed frequency
- *   - IA32_APERF: increments in proportion to actual performance
- */
-#define	IA32_MPERF_MSR			0xE7
-#define	IA32_APERF_MSR			0xE8
 
 /*
  * Debugging support
@@ -117,116 +85,6 @@
 #define	ESSDEBUG(arglist)
 #endif
 
-static kmutex_t turbo_mutex;
-
-turbo_kstat_t turbo_kstat = {
-	{ "turbo_supported",	KSTAT_DATA_UINT32 },
-	{ "turbo_mcnt",		KSTAT_DATA_UINT64 },
-	{ "turbo_acnt",		KSTAT_DATA_UINT64 },
-};
-
-/*
- * kstat update function of the turbo mode info
- */
-static int
-turbo_kstat_update(kstat_t *ksp, int flag)
-{
-	cpupm_turbo_info_t *turbo_info = ksp->ks_private;
-
-	if (flag == KSTAT_WRITE) {
-		return (EACCES);
-	}
-
-	/*
-	 * update the count in case CPU is in the turbo
-	 * mode for a long time
-	 */
-	if (turbo_info->in_turbo == CPU_IN_TURBO)
-		update_turbo_info(turbo_info);
-
-	turbo_kstat.turbo_supported.value.ui32 =
-	    turbo_info->turbo_supported;
-	turbo_kstat.t_mcnt.value.ui64 = turbo_info->t_mcnt;
-	turbo_kstat.t_acnt.value.ui64 = turbo_info->t_acnt;
-
-	return (0);
-}
-
-/*
- * Get count of MPERF/APERF MSR
- */
-static void
-get_turbo_info(cpupm_turbo_info_t *turbo_info)
-{
-	ulong_t		iflag;
-	uint64_t	mcnt, acnt;
-
-	iflag = intr_clear();
-	mcnt = rdmsr(IA32_MPERF_MSR);
-	acnt = rdmsr(IA32_APERF_MSR);
-	turbo_info->t_mcnt += mcnt;
-	turbo_info->t_acnt += acnt;
-	intr_restore(iflag);
-}
-
-/*
- * Clear MPERF/APERF MSR
- */
-static void
-reset_turbo_info(void)
-{
-	ulong_t		iflag;
-
-	iflag = intr_clear();
-	wrmsr(IA32_MPERF_MSR, 0);
-	wrmsr(IA32_APERF_MSR, 0);
-	intr_restore(iflag);
-}
-
-/*
- * sum up the count of one CPU_ACPI_P0 transition
- */
-static void
-record_turbo_info(cpupm_turbo_info_t *turbo_info,
-    uint32_t cur_state, uint32_t req_state)
-{
-	if (!turbo_info->turbo_supported)
-		return;
-	/*
-	 * enter P0 state
-	 */
-	if (req_state == CPU_ACPI_P0) {
-		reset_turbo_info();
-		turbo_info->in_turbo = CPU_IN_TURBO;
-	}
-	/*
-	 * Leave P0 state
-	 */
-	else if (cur_state == CPU_ACPI_P0) {
-		turbo_info->in_turbo = 0;
-		get_turbo_info(turbo_info);
-	}
-}
-
-/*
- * update the sum of counts and clear MSRs
- */
-static void
-update_turbo_info(cpupm_turbo_info_t *turbo_info)
-{
-	ulong_t		iflag;
-	uint64_t	mcnt, acnt;
-
-	iflag = intr_clear();
-	mcnt = rdmsr(IA32_MPERF_MSR);
-	acnt = rdmsr(IA32_APERF_MSR);
-	wrmsr(IA32_MPERF_MSR, 0);
-	wrmsr(IA32_APERF_MSR, 0);
-	turbo_info->t_mcnt += mcnt;
-	turbo_info->t_acnt += acnt;
-	intr_restore(iflag);
-}
-
 /*
  * Write the ctrl register. How it is written, depends upon the _PCT
  * APCI object value.
@@ -276,8 +134,6 @@
 	cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
 	cpu_acpi_pstate_t *req_pstate;
 	uint32_t ctrl;
-	cpupm_turbo_info_t *turbo_info =
-	    (cpupm_turbo_info_t *)(mach_state->ms_vendor);
 
 	req_pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
 	req_pstate += req_state;
@@ -290,11 +146,10 @@
 	ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate);
 	write_ctrl(handle, ctrl);
 
-	if (turbo_info)
-		record_turbo_info(turbo_info,
+	if (mach_state->ms_turbo != NULL)
+		cpupm_record_turbo_info(mach_state->ms_turbo,
 		    mach_state->ms_pstate.cma_state.pstate, req_state);
 
-
 	mach_state->ms_pstate.cma_state.pstate = req_state;
 	cpu_set_curr_clock(((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000));
 }
@@ -330,7 +185,6 @@
 	    (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state;
 	cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
 	cpu_acpi_pct_t *pct_stat;
-	cpupm_turbo_info_t *turbo_info;
 
 	ESSDEBUG(("speedstep_init: processor %d\n", cp->cpu_id));
 
@@ -363,34 +217,8 @@
 
 	cpupm_alloc_domains(cp, CPUPM_P_STATES);
 
-	if (!turbo_supported()) {
-		mach_state->ms_vendor = NULL;
-		goto ess_ret_success;
-	}
-	/*
-	 * turbo mode supported
-	 */
-	turbo_info = mach_state->ms_vendor =
-	    kmem_zalloc(sizeof (cpupm_turbo_info_t), KM_SLEEP);
-	turbo_info->turbo_supported = 1;
-	turbo_info->turbo_ksp = kstat_create("turbo", cp->cpu_id,
-	    "turbo", "misc", KSTAT_TYPE_NAMED,
-	    sizeof (turbo_kstat) / sizeof (kstat_named_t),
-	    KSTAT_FLAG_VIRTUAL);
-
-	if (turbo_info->turbo_ksp == NULL) {
-		cmn_err(CE_NOTE, "kstat_create(turbo) fail");
-	} else {
-		turbo_info->turbo_ksp->ks_data = &turbo_kstat;
-		turbo_info->turbo_ksp->ks_lock = &turbo_mutex;
-		turbo_info->turbo_ksp->ks_update = turbo_kstat_update;
-		turbo_info->turbo_ksp->ks_data_size += MAXNAMELEN;
-		turbo_info->turbo_ksp->ks_private = turbo_info;
-
-		kstat_install(turbo_info->turbo_ksp);
-	}
-
-ess_ret_success:
+	if (speedstep_turbo_supported())
+		mach_state->ms_turbo = cpupm_turbo_init(cp);
 
 	ESSDEBUG(("Processor %d succeeded.\n", cp->cpu_id))
 	return (ESS_RET_SUCCESS);
@@ -405,17 +233,13 @@
 	cpupm_mach_state_t *mach_state =
 	    (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
 	cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
-	cpupm_turbo_info_t *turbo_info =
-	    (cpupm_turbo_info_t *)(mach_state->ms_vendor);
 
 	cpupm_free_domains(&cpupm_pstate_domains);
 	cpu_acpi_free_pstate_data(handle);
 
-	if (turbo_info) {
-		if (turbo_info->turbo_ksp != NULL)
-			kstat_delete(turbo_info->turbo_ksp);
-		kmem_free(turbo_info, sizeof (cpupm_turbo_info_t));
-	}
+	if (mach_state->ms_turbo != NULL)
+		cpupm_turbo_fini(mach_state->ms_turbo);
+	mach_state->ms_turbo = NULL;
 }
 
 static void
@@ -424,17 +248,13 @@
 	cpupm_mach_state_t *mach_state =
 	    (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
 	cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
-	cpupm_turbo_info_t *turbo_info =
-	    (cpupm_turbo_info_t *)(mach_state->ms_vendor);
 
 	cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains);
 	cpu_acpi_free_pstate_data(handle);
 
-	if (turbo_info) {
-		if (turbo_info->turbo_ksp != NULL)
-			kstat_delete(turbo_info->turbo_ksp);
-		kmem_free(turbo_info, sizeof (cpupm_turbo_info_t));
-	}
+	if (mach_state->ms_turbo != NULL)
+		cpupm_turbo_fini(mach_state->ms_turbo);
+	mach_state->ms_turbo = NULL;
 }
 
 boolean_t
@@ -470,7 +290,7 @@
 }
 
 boolean_t
-turbo_supported(void)
+speedstep_turbo_supported(void)
 {
 	struct cpuid_regs cpu_regs;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/os/cpupm/turbo.c	Tue Apr 03 15:45:02 2012 -0500
@@ -0,0 +1,208 @@
+/*
+ * 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * Copyright (c) 2009,  Intel Corporation.
+ * All Rights Reserved.
+ */
+
+#include <sys/x86_archext.h>
+#include <sys/machsystm.h>
+#include <sys/archsystm.h>
+#include <sys/x_call.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/speedstep.h>
+#include <sys/cpu_acpi.h>
+#include <sys/cpupm.h>
+#include <sys/dtrace.h>
+#include <sys/sdt.h>
+
+typedef struct turbo_kstat_s {
+	struct kstat_named	turbo_supported;	/* turbo flag */
+	struct kstat_named	t_mcnt;			/* IA32_MPERF_MSR */
+	struct kstat_named	t_acnt;			/* IA32_APERF_MSR */
+} turbo_kstat_t;
+
+static int turbo_kstat_update(kstat_t *, int);
+static void get_turbo_info(cpupm_mach_turbo_info_t *);
+static void reset_turbo_info(void);
+static void record_turbo_info(cpupm_mach_turbo_info_t *, uint32_t, uint32_t);
+static void update_turbo_info(cpupm_mach_turbo_info_t *);
+
+static kmutex_t turbo_mutex;
+
+turbo_kstat_t turbo_kstat = {
+	{ "turbo_supported",	KSTAT_DATA_UINT32 },
+	{ "turbo_mcnt",		KSTAT_DATA_UINT64 },
+	{ "turbo_acnt",		KSTAT_DATA_UINT64 },
+};
+
+#define	CPU_ACPI_P0			0
+#define	CPU_IN_TURBO			1
+
+/*
+ * MSR for hardware coordination feedback mechanism
+ *   - IA32_MPERF: increments in proportion to a fixed frequency
+ *   - IA32_APERF: increments in proportion to actual performance
+ */
+#define	IA32_MPERF_MSR			0xE7
+#define	IA32_APERF_MSR			0xE8
+
+/*
+ * kstat update function of the turbo mode info
+ */
+static int
+turbo_kstat_update(kstat_t *ksp, int flag)
+{
+	cpupm_mach_turbo_info_t *turbo_info = ksp->ks_private;
+
+	if (flag == KSTAT_WRITE) {
+		return (EACCES);
+	}
+
+	/*
+	 * update the count in case CPU is in the turbo
+	 * mode for a long time
+	 */
+	if (turbo_info->in_turbo == CPU_IN_TURBO)
+		update_turbo_info(turbo_info);
+
+	turbo_kstat.turbo_supported.value.ui32 =
+	    turbo_info->turbo_supported;
+	turbo_kstat.t_mcnt.value.ui64 = turbo_info->t_mcnt;
+	turbo_kstat.t_acnt.value.ui64 = turbo_info->t_acnt;
+
+	return (0);
+}
+
+/*
+ * update the sum of counts and clear MSRs
+ */
+static void
+update_turbo_info(cpupm_mach_turbo_info_t *turbo_info)
+{
+	ulong_t		iflag;
+	uint64_t	mcnt, acnt;
+
+	iflag = intr_clear();
+	mcnt = rdmsr(IA32_MPERF_MSR);
+	acnt = rdmsr(IA32_APERF_MSR);
+	wrmsr(IA32_MPERF_MSR, 0);
+	wrmsr(IA32_APERF_MSR, 0);
+	turbo_info->t_mcnt += mcnt;
+	turbo_info->t_acnt += acnt;
+	intr_restore(iflag);
+}
+
+/*
+ * Get count of MPERF/APERF MSR
+ */
+static void
+get_turbo_info(cpupm_mach_turbo_info_t *turbo_info)
+{
+	ulong_t		iflag;
+	uint64_t	mcnt, acnt;
+
+	iflag = intr_clear();
+	mcnt = rdmsr(IA32_MPERF_MSR);
+	acnt = rdmsr(IA32_APERF_MSR);
+	turbo_info->t_mcnt += mcnt;
+	turbo_info->t_acnt += acnt;
+	intr_restore(iflag);
+}
+
+/*
+ * Clear MPERF/APERF MSR
+ */
+static void
+reset_turbo_info(void)
+{
+	ulong_t		iflag;
+
+	iflag = intr_clear();
+	wrmsr(IA32_MPERF_MSR, 0);
+	wrmsr(IA32_APERF_MSR, 0);
+	intr_restore(iflag);
+}
+
+/*
+ * sum up the count of one CPU_ACPI_P0 transition
+ */
+void
+cpupm_record_turbo_info(cpupm_mach_turbo_info_t *turbo_info,
+    uint32_t cur_state, uint32_t req_state)
+{
+	if (!turbo_info->turbo_supported)
+		return;
+	/*
+	 * enter P0 state
+	 */
+	if (req_state == CPU_ACPI_P0) {
+		reset_turbo_info();
+		turbo_info->in_turbo = CPU_IN_TURBO;
+	}
+	/*
+	 * Leave P0 state
+	 */
+	else if (cur_state == CPU_ACPI_P0) {
+		turbo_info->in_turbo = 0;
+		get_turbo_info(turbo_info);
+	}
+}
+
+cpupm_mach_turbo_info_t *
+cpupm_turbo_init(cpu_t *cp)
+{
+	cpupm_mach_turbo_info_t *turbo_info;
+
+	turbo_info = kmem_zalloc(sizeof (cpupm_mach_turbo_info_t), KM_SLEEP);
+
+	turbo_info->turbo_supported = 1;
+	turbo_info->turbo_ksp = kstat_create("turbo", cp->cpu_id,
+	    "turbo", "misc", KSTAT_TYPE_NAMED,
+	    sizeof (turbo_kstat) / sizeof (kstat_named_t),
+	    KSTAT_FLAG_VIRTUAL);
+
+	if (turbo_info->turbo_ksp == NULL) {
+		cmn_err(CE_NOTE, "kstat_create(turbo) fail");
+	} else {
+		turbo_info->turbo_ksp->ks_data = &turbo_kstat;
+		turbo_info->turbo_ksp->ks_lock = &turbo_mutex;
+		turbo_info->turbo_ksp->ks_update = turbo_kstat_update;
+		turbo_info->turbo_ksp->ks_data_size += MAXNAMELEN;
+		turbo_info->turbo_ksp->ks_private = turbo_info;
+
+		kstat_install(turbo_info->turbo_ksp);
+	}
+
+	return (turbo_info);
+}
+
+void
+cpupm_turbo_fini(cpupm_mach_turbo_info_t *turbo_info)
+{
+	if (turbo_info->turbo_ksp != NULL)
+		kstat_delete(turbo_info->turbo_ksp);
+	kmem_free(turbo_info, sizeof (cpupm_mach_turbo_info_t));
+}
--- a/usr/src/uts/i86pc/sys/cpupm_mach.h	Thu Apr 05 08:47:21 2012 -0500
+++ b/usr/src/uts/i86pc/sys/cpupm_mach.h	Tue Apr 03 15:45:02 2012 -0500
@@ -107,6 +107,14 @@
 	cma_state_t		cma_state;
 } cpupm_mach_acpi_state_t;
 
+typedef struct cpupm_mach_turbo_info {
+	kstat_t		*turbo_ksp;		/* turbo kstat */
+	int		in_turbo;		/* in turbo? */
+	int		turbo_supported;	/* turbo flag */
+	uint64_t	t_mcnt;			/* turbo mcnt */
+	uint64_t	t_acnt;			/* turbo acnt */
+} cpupm_mach_turbo_info_t;
+
 typedef struct cpupm_mach_state {
 	void			*ms_acpi_handle;
 	cpupm_mach_acpi_state_t	ms_pstate;
@@ -115,7 +123,7 @@
 	uint32_t		ms_caps;
 	dev_info_t		*ms_dip;
 	kmutex_t		ms_lock;
-	void			*ms_vendor;
+	cpupm_mach_turbo_info_t	*ms_turbo;
 	struct cpupm_notification *ms_handlers;
 } cpupm_mach_state_t;
 
@@ -191,6 +199,10 @@
 extern int cpupm_get_top_speed(cpu_t *);
 extern void cpupm_idle_cstate_data(cma_c_state_t *, int);
 extern void cpupm_wakeup_cstate_data(cma_c_state_t *, hrtime_t);
+extern void cpupm_record_turbo_info(cpupm_mach_turbo_info_t *, uint32_t,
+    uint32_t);
+extern cpupm_mach_turbo_info_t *cpupm_turbo_init(cpu_t *);
+extern void cpupm_turbo_fini(cpupm_mach_turbo_info_t *);
 
 #ifdef __cplusplus
 }