10e751525SEric Saxe /*
20e751525SEric Saxe * CDDL HEADER START
30e751525SEric Saxe *
40e751525SEric Saxe * The contents of this file are subject to the terms of the
50e751525SEric Saxe * Common Development and Distribution License (the "License").
60e751525SEric Saxe * You may not use this file except in compliance with the License.
70e751525SEric Saxe *
80e751525SEric Saxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90e751525SEric Saxe * or http://www.opensolaris.org/os/licensing.
100e751525SEric Saxe * See the License for the specific language governing permissions
110e751525SEric Saxe * and limitations under the License.
120e751525SEric Saxe *
130e751525SEric Saxe * When distributing Covered Code, include this CDDL HEADER in each
140e751525SEric Saxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150e751525SEric Saxe * If applicable, add the following below this CDDL HEADER, with the
160e751525SEric Saxe * fields enclosed by brackets "[]" replaced with your own identifying
170e751525SEric Saxe * information: Portions Copyright [yyyy] [name of copyright owner]
180e751525SEric Saxe *
190e751525SEric Saxe * CDDL HEADER END
200e751525SEric Saxe */
210e751525SEric Saxe /*
227417cfdeSKuriakose Kuruvilla * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
230e751525SEric Saxe */
24444f66e7SMark Haywood /*
25444f66e7SMark Haywood * Copyright (c) 2009, Intel Corporation.
26444f66e7SMark Haywood * All Rights Reserved.
27444f66e7SMark Haywood */
280e751525SEric Saxe
290e751525SEric Saxe #include <sys/x86_archext.h>
300e751525SEric Saxe #include <sys/machsystm.h>
31e5bbdc06SRafael Vanoni #include <sys/archsystm.h>
320e751525SEric Saxe #include <sys/x_call.h>
330e751525SEric Saxe #include <sys/acpi/acpi.h>
340e751525SEric Saxe #include <sys/acpica.h>
350e751525SEric Saxe #include <sys/speedstep.h>
360e751525SEric Saxe #include <sys/cpu_acpi.h>
370e751525SEric Saxe #include <sys/cpupm.h>
380e751525SEric Saxe #include <sys/dtrace.h>
390e751525SEric Saxe #include <sys/sdt.h>
400e751525SEric Saxe
410e751525SEric Saxe static int speedstep_init(cpu_t *);
420e751525SEric Saxe static void speedstep_fini(cpu_t *);
430e751525SEric Saxe static void speedstep_power(cpuset_t, uint32_t);
44444f66e7SMark Haywood static void speedstep_stop(cpu_t *);
455951ced0SHans Rosenfeld static boolean_t speedstep_turbo_supported(void);
460e751525SEric Saxe
470e751525SEric Saxe /*
480e751525SEric Saxe * Interfaces for modules implementing Intel's Enhanced SpeedStep.
490e751525SEric Saxe */
500e751525SEric Saxe cpupm_state_ops_t speedstep_ops = {
510e751525SEric Saxe "Enhanced SpeedStep Technology",
520e751525SEric Saxe speedstep_init,
530e751525SEric Saxe speedstep_fini,
54444f66e7SMark Haywood speedstep_power,
55444f66e7SMark Haywood speedstep_stop
560e751525SEric Saxe };
570e751525SEric Saxe
580e751525SEric Saxe /*
590e751525SEric Saxe * Error returns
600e751525SEric Saxe */
610e751525SEric Saxe #define ESS_RET_SUCCESS 0x00
620e751525SEric Saxe #define ESS_RET_NO_PM 0x01
630e751525SEric Saxe #define ESS_RET_UNSUP_STATE 0x02
640e751525SEric Saxe
650e751525SEric Saxe /*
660e751525SEric Saxe * MSR registers for changing and reading processor power state.
670e751525SEric Saxe */
680e751525SEric Saxe #define IA32_PERF_STAT_MSR 0x198
690e751525SEric Saxe #define IA32_PERF_CTL_MSR 0x199
700e751525SEric Saxe
710e751525SEric Saxe #define IA32_CPUID_TSC_CONSTANT 0xF30
720e751525SEric Saxe #define IA32_MISC_ENABLE_MSR 0x1A0
730e751525SEric Saxe #define IA32_MISC_ENABLE_EST (1<<16)
740e751525SEric Saxe #define IA32_MISC_ENABLE_CXE (1<<25)
75e5bbdc06SRafael Vanoni
76e5bbdc06SRafael Vanoni #define CPUID_TURBO_SUPPORT (1 << 1)
77e5bbdc06SRafael Vanoni
780e751525SEric Saxe /*
790e751525SEric Saxe * Debugging support
800e751525SEric Saxe */
810e751525SEric Saxe #ifdef DEBUG
820e751525SEric Saxe volatile int ess_debug = 0;
830e751525SEric Saxe #define ESSDEBUG(arglist) if (ess_debug) printf arglist;
840e751525SEric Saxe #else
850e751525SEric Saxe #define ESSDEBUG(arglist)
860e751525SEric Saxe #endif
870e751525SEric Saxe
880e751525SEric Saxe /*
890e751525SEric Saxe * Write the ctrl register. How it is written, depends upon the _PCT
900e751525SEric Saxe * APCI object value.
910e751525SEric Saxe */
920e751525SEric Saxe static void
write_ctrl(cpu_acpi_handle_t handle,uint32_t ctrl)930e751525SEric Saxe write_ctrl(cpu_acpi_handle_t handle, uint32_t ctrl)
940e751525SEric Saxe {
950e751525SEric Saxe cpu_acpi_pct_t *pct_ctrl;
960e751525SEric Saxe uint64_t reg;
970e751525SEric Saxe
980e751525SEric Saxe pct_ctrl = CPU_ACPI_PCT_CTRL(handle);
990e751525SEric Saxe
1000e751525SEric Saxe switch (pct_ctrl->cr_addrspace_id) {
1010e751525SEric Saxe case ACPI_ADR_SPACE_FIXED_HARDWARE:
1020e751525SEric Saxe /*
1030e751525SEric Saxe * Read current power state because reserved bits must be
1040e751525SEric Saxe * preserved, compose new value, and write it.
1050e751525SEric Saxe */
1060e751525SEric Saxe reg = rdmsr(IA32_PERF_CTL_MSR);
1070e751525SEric Saxe reg &= ~((uint64_t)0xFFFF);
1080e751525SEric Saxe reg |= ctrl;
1090e751525SEric Saxe wrmsr(IA32_PERF_CTL_MSR, reg);
1100e751525SEric Saxe break;
1110e751525SEric Saxe
1120e751525SEric Saxe case ACPI_ADR_SPACE_SYSTEM_IO:
1130e751525SEric Saxe (void) cpu_acpi_write_port(pct_ctrl->cr_address, ctrl,
1140e751525SEric Saxe pct_ctrl->cr_width);
1150e751525SEric Saxe break;
1160e751525SEric Saxe
1170e751525SEric Saxe default:
1180e751525SEric Saxe DTRACE_PROBE1(ess_ctrl_unsupported_type, uint8_t,
1190e751525SEric Saxe pct_ctrl->cr_addrspace_id);
1200e751525SEric Saxe return;
1210e751525SEric Saxe }
1220e751525SEric Saxe
1230e751525SEric Saxe DTRACE_PROBE1(ess_ctrl_write, uint32_t, ctrl);
1240e751525SEric Saxe }
1250e751525SEric Saxe
1260e751525SEric Saxe /*
1270e751525SEric Saxe * Transition the current processor to the requested state.
1280e751525SEric Saxe */
1290e751525SEric Saxe void
speedstep_pstate_transition(uint32_t req_state)1300e751525SEric Saxe speedstep_pstate_transition(uint32_t req_state)
1310e751525SEric Saxe {
1320e751525SEric Saxe cpupm_mach_state_t *mach_state =
1330e751525SEric Saxe (cpupm_mach_state_t *)CPU->cpu_m.mcpu_pm_mach_state;
1340e751525SEric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
1350e751525SEric Saxe cpu_acpi_pstate_t *req_pstate;
1360e751525SEric Saxe uint32_t ctrl;
1370e751525SEric Saxe
1380e751525SEric Saxe req_pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
1390e751525SEric Saxe req_pstate += req_state;
1400e751525SEric Saxe
1410e751525SEric Saxe DTRACE_PROBE1(ess_transition, uint32_t, CPU_ACPI_FREQ(req_pstate));
1420e751525SEric Saxe
1430e751525SEric Saxe /*
1440e751525SEric Saxe * Initiate the processor p-state change.
1450e751525SEric Saxe */
1460e751525SEric Saxe ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate);
1470e751525SEric Saxe write_ctrl(handle, ctrl);
1480e751525SEric Saxe
1495951ced0SHans Rosenfeld if (mach_state->ms_turbo != NULL)
1505951ced0SHans Rosenfeld cpupm_record_turbo_info(mach_state->ms_turbo,
151e5bbdc06SRafael Vanoni mach_state->ms_pstate.cma_state.pstate, req_state);
152e5bbdc06SRafael Vanoni
1530e751525SEric Saxe mach_state->ms_pstate.cma_state.pstate = req_state;
1540e751525SEric Saxe cpu_set_curr_clock(((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000));
1550e751525SEric Saxe }
1560e751525SEric Saxe
1570e751525SEric Saxe static void
speedstep_power(cpuset_t set,uint32_t req_state)1580e751525SEric Saxe speedstep_power(cpuset_t set, uint32_t req_state)
1590e751525SEric Saxe {
1600e751525SEric Saxe /*
1610e751525SEric Saxe * If thread is already running on target CPU then just
1620e751525SEric Saxe * make the transition request. Otherwise, we'll need to
1630e751525SEric Saxe * make a cross-call.
1640e751525SEric Saxe */
1650e751525SEric Saxe kpreempt_disable();
1660e751525SEric Saxe if (CPU_IN_SET(set, CPU->cpu_id)) {
1670e751525SEric Saxe speedstep_pstate_transition(req_state);
1680e751525SEric Saxe CPUSET_DEL(set, CPU->cpu_id);
1690e751525SEric Saxe }
1700e751525SEric Saxe if (!CPUSET_ISNULL(set)) {
171f34a7178SJoe Bonasera xc_call((xc_arg_t)req_state, NULL, NULL, CPUSET2BV(set),
1720e751525SEric Saxe (xc_func_t)speedstep_pstate_transition);
1730e751525SEric Saxe }
1740e751525SEric Saxe kpreempt_enable();
1750e751525SEric Saxe }
1760e751525SEric Saxe
1770e751525SEric Saxe /*
1780e751525SEric Saxe * Validate that this processor supports Speedstep and if so,
1790e751525SEric Saxe * get the P-state data from ACPI and cache it.
1800e751525SEric Saxe */
1810e751525SEric Saxe static int
speedstep_init(cpu_t * cp)1820e751525SEric Saxe speedstep_init(cpu_t *cp)
1830e751525SEric Saxe {
1840e751525SEric Saxe cpupm_mach_state_t *mach_state =
1850e751525SEric Saxe (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state;
1860e751525SEric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
1870e751525SEric Saxe cpu_acpi_pct_t *pct_stat;
188*511588bbSYuri Pankov static int logged = 0;
1890e751525SEric Saxe
1900e751525SEric Saxe ESSDEBUG(("speedstep_init: processor %d\n", cp->cpu_id));
1910e751525SEric Saxe
1920e751525SEric Saxe /*
1930e751525SEric Saxe * Cache the P-state specific ACPI data.
1940e751525SEric Saxe */
1950e751525SEric Saxe if (cpu_acpi_cache_pstate_data(handle) != 0) {
196*511588bbSYuri Pankov if (!logged) {
19700f97612SMark Haywood cmn_err(CE_NOTE, "!SpeedStep support is being "
198*511588bbSYuri Pankov "disabled due to errors parsing ACPI P-state "
199*511588bbSYuri Pankov "objects exported by BIOS.");
200*511588bbSYuri Pankov logged = 1;
201*511588bbSYuri Pankov }
2020e751525SEric Saxe speedstep_fini(cp);
2030e751525SEric Saxe return (ESS_RET_NO_PM);
2040e751525SEric Saxe }
2050e751525SEric Saxe
2060e751525SEric Saxe pct_stat = CPU_ACPI_PCT_STATUS(handle);
2070e751525SEric Saxe switch (pct_stat->cr_addrspace_id) {
2080e751525SEric Saxe case ACPI_ADR_SPACE_FIXED_HARDWARE:
2090e751525SEric Saxe ESSDEBUG(("Transitions will use fixed hardware\n"));
2100e751525SEric Saxe break;
2110e751525SEric Saxe case ACPI_ADR_SPACE_SYSTEM_IO:
2120e751525SEric Saxe ESSDEBUG(("Transitions will use system IO\n"));
2130e751525SEric Saxe break;
2140e751525SEric Saxe default:
2150e751525SEric Saxe cmn_err(CE_WARN, "!_PCT conifgured for unsupported "
2160e751525SEric Saxe "addrspace = %d.", pct_stat->cr_addrspace_id);
2170e751525SEric Saxe cmn_err(CE_NOTE, "!CPU power management will not function.");
2180e751525SEric Saxe speedstep_fini(cp);
2190e751525SEric Saxe return (ESS_RET_NO_PM);
2200e751525SEric Saxe }
2210e751525SEric Saxe
2220e751525SEric Saxe cpupm_alloc_domains(cp, CPUPM_P_STATES);
2230e751525SEric Saxe
2245951ced0SHans Rosenfeld if (speedstep_turbo_supported())
2255951ced0SHans Rosenfeld mach_state->ms_turbo = cpupm_turbo_init(cp);
226e5bbdc06SRafael Vanoni
2270e751525SEric Saxe ESSDEBUG(("Processor %d succeeded.\n", cp->cpu_id))
2280e751525SEric Saxe return (ESS_RET_SUCCESS);
2290e751525SEric Saxe }
2300e751525SEric Saxe
2310e751525SEric Saxe /*
2320e751525SEric Saxe * Free resources allocated by speedstep_init().
2330e751525SEric Saxe */
2340e751525SEric Saxe static void
speedstep_fini(cpu_t * cp)2350e751525SEric Saxe speedstep_fini(cpu_t *cp)
2360e751525SEric Saxe {
2370e751525SEric Saxe cpupm_mach_state_t *mach_state =
2380e751525SEric Saxe (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
2390e751525SEric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
2400e751525SEric Saxe
2410e751525SEric Saxe cpupm_free_domains(&cpupm_pstate_domains);
2420e751525SEric Saxe cpu_acpi_free_pstate_data(handle);
243e5bbdc06SRafael Vanoni
2445951ced0SHans Rosenfeld if (mach_state->ms_turbo != NULL)
2455951ced0SHans Rosenfeld cpupm_turbo_fini(mach_state->ms_turbo);
2465951ced0SHans Rosenfeld mach_state->ms_turbo = NULL;
2470e751525SEric Saxe }
2480e751525SEric Saxe
249444f66e7SMark Haywood static void
speedstep_stop(cpu_t * cp)250444f66e7SMark Haywood speedstep_stop(cpu_t *cp)
251444f66e7SMark Haywood {
252444f66e7SMark Haywood cpupm_mach_state_t *mach_state =
253444f66e7SMark Haywood (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
254444f66e7SMark Haywood cpu_acpi_handle_t handle = mach_state->ms_acpi_handle;
255444f66e7SMark Haywood
256444f66e7SMark Haywood cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains);
257444f66e7SMark Haywood cpu_acpi_free_pstate_data(handle);
258444f66e7SMark Haywood
2595951ced0SHans Rosenfeld if (mach_state->ms_turbo != NULL)
2605951ced0SHans Rosenfeld cpupm_turbo_fini(mach_state->ms_turbo);
2615951ced0SHans Rosenfeld mach_state->ms_turbo = NULL;
262444f66e7SMark Haywood }
263444f66e7SMark Haywood
2640e751525SEric Saxe boolean_t
speedstep_supported(uint_t family,uint_t model)2650e751525SEric Saxe speedstep_supported(uint_t family, uint_t model)
2660e751525SEric Saxe {
2670e751525SEric Saxe struct cpuid_regs cpu_regs;
2680e751525SEric Saxe
2690e751525SEric Saxe /* Required features */
2707417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
2717417cfdeSKuriakose Kuruvilla !is_x86_feature(x86_featureset, X86FSET_MSR)) {
2720e751525SEric Saxe return (B_FALSE);
2730e751525SEric Saxe }
2740e751525SEric Saxe
2750e751525SEric Saxe /*
2760e751525SEric Saxe * We only support family/model combinations which
2770e751525SEric Saxe * are P-state TSC invariant.
2780e751525SEric Saxe */
2790e751525SEric Saxe if (!((family == 0xf && model >= 0x3) ||
2800e751525SEric Saxe (family == 0x6 && model >= 0xe))) {
2810e751525SEric Saxe return (B_FALSE);
2820e751525SEric Saxe }
2830e751525SEric Saxe
2840e751525SEric Saxe /*
2850e751525SEric Saxe * Enhanced SpeedStep supported?
2860e751525SEric Saxe */
2870e751525SEric Saxe cpu_regs.cp_eax = 0x1;
2880e751525SEric Saxe (void) __cpuid_insn(&cpu_regs);
2890e751525SEric Saxe if (!(cpu_regs.cp_ecx & CPUID_INTC_ECX_EST)) {
2900e751525SEric Saxe return (B_FALSE);
2910e751525SEric Saxe }
2920e751525SEric Saxe
2930e751525SEric Saxe return (B_TRUE);
2940e751525SEric Saxe }
295e5bbdc06SRafael Vanoni
296e5bbdc06SRafael Vanoni boolean_t
speedstep_turbo_supported(void)2975951ced0SHans Rosenfeld speedstep_turbo_supported(void)
298e5bbdc06SRafael Vanoni {
299e5bbdc06SRafael Vanoni struct cpuid_regs cpu_regs;
300e5bbdc06SRafael Vanoni
301e5bbdc06SRafael Vanoni /* Required features */
3027417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
3037417cfdeSKuriakose Kuruvilla !is_x86_feature(x86_featureset, X86FSET_MSR)) {
304e5bbdc06SRafael Vanoni return (B_FALSE);
305e5bbdc06SRafael Vanoni }
306e5bbdc06SRafael Vanoni
307e5bbdc06SRafael Vanoni /*
308e5bbdc06SRafael Vanoni * turbo mode supported?
309e5bbdc06SRafael Vanoni */
310e5bbdc06SRafael Vanoni cpu_regs.cp_eax = 0x6;
311e5bbdc06SRafael Vanoni (void) __cpuid_insn(&cpu_regs);
312e5bbdc06SRafael Vanoni if (!(cpu_regs.cp_eax & CPUID_TURBO_SUPPORT)) {
313e5bbdc06SRafael Vanoni return (B_FALSE);
314e5bbdc06SRafael Vanoni }
315e5bbdc06SRafael Vanoni
316e5bbdc06SRafael Vanoni return (B_TRUE);
317e5bbdc06SRafael Vanoni }
318