15cff782mh/* 25cff782mh * CDDL HEADER START 35cff782mh * 45cff782mh * The contents of this file are subject to the terms of the 55cff782mh * Common Development and Distribution License (the "License"). 65cff782mh * You may not use this file except in compliance with the License. 75cff782mh * 85cff782mh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95cff782mh * or http://www.opensolaris.org/os/licensing. 105cff782mh * See the License for the specific language governing permissions 115cff782mh * and limitations under the License. 125cff782mh * 135cff782mh * When distributing Covered Code, include this CDDL HEADER in each 145cff782mh * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155cff782mh * If applicable, add the following below this CDDL HEADER, with the 165cff782mh * fields enclosed by brackets "[]" replaced with your own identifying 175cff782mh * information: Portions Copyright [yyyy] [name of copyright owner] 185cff782mh * 195cff782mh * CDDL HEADER END 205cff782mh */ 215cff782mh/* 227417cfdKuriakose Kuruvilla * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 235cff782mh */ 24444f66eMark Haywood/* 25444f66eMark Haywood * Copyright (c) 2009, Intel Corporation. 26444f66eMark Haywood * All Rights Reserved. 27444f66eMark Haywood */ 285cff782mh 295cff782mh#include <sys/x86_archext.h> 305cff782mh#include <sys/machsystm.h> 31e5bbdc0Rafael Vanoni#include <sys/archsystm.h> 325cff782mh#include <sys/x_call.h> 335cff782mh#include <sys/acpi/acpi.h> 345cff782mh#include <sys/acpica.h> 355cff782mh#include <sys/speedstep.h> 365cff782mh#include <sys/cpu_acpi.h> 375cff782mh#include <sys/cpupm.h> 385cff782mh#include <sys/dtrace.h> 395cff782mh#include <sys/sdt.h> 405cff782mh 410e75152Eric Saxestatic int speedstep_init(cpu_t *); 420e75152Eric Saxestatic void speedstep_fini(cpu_t *); 430e75152Eric Saxestatic void speedstep_power(cpuset_t, uint32_t); 44444f66eMark Haywoodstatic void speedstep_stop(cpu_t *); 455951cedHans Rosenfeldstatic boolean_t speedstep_turbo_supported(void); 467f606acMark Haywood 477f606acMark Haywood/* 487f606acMark Haywood * Interfaces for modules implementing Intel's Enhanced SpeedStep. 497f606acMark Haywood */ 500e75152Eric Saxecpupm_state_ops_t speedstep_ops = { 517f606acMark Haywood "Enhanced SpeedStep Technology", 527f606acMark Haywood speedstep_init, 537f606acMark Haywood speedstep_fini, 54444f66eMark Haywood speedstep_power, 55444f66eMark Haywood speedstep_stop 567f606acMark Haywood}; 577f606acMark Haywood 585cff782mh/* 595cff782mh * Error returns 605cff782mh */ 615cff782mh#define ESS_RET_SUCCESS 0x00 625cff782mh#define ESS_RET_NO_PM 0x01 635cff782mh#define ESS_RET_UNSUP_STATE 0x02 645cff782mh 655cff782mh/* 665cff782mh * MSR registers for changing and reading processor power state. 675cff782mh */ 6862c4c2fmh#define IA32_PERF_STAT_MSR 0x198 695cff782mh#define IA32_PERF_CTL_MSR 0x199 705cff782mh 715cff782mh#define IA32_CPUID_TSC_CONSTANT 0xF30 725cff782mh#define IA32_MISC_ENABLE_MSR 0x1A0 735cff782mh#define IA32_MISC_ENABLE_EST (1<<16) 745cff782mh#define IA32_MISC_ENABLE_CXE (1<<25) 75e5bbdc0Rafael Vanoni 76e5bbdc0Rafael Vanoni#define CPUID_TURBO_SUPPORT (1 << 1) 77e5bbdc0Rafael Vanoni 785cff782mh/* 795cff782mh * Debugging support 805cff782mh */ 815cff782mh#ifdef DEBUG 825cff782mhvolatile int ess_debug = 0; 835cff782mh#define ESSDEBUG(arglist) if (ess_debug) printf arglist; 845cff782mh#else 855cff782mh#define ESSDEBUG(arglist) 865cff782mh#endif 875cff782mh 88bc5e875mh/* 895cff782mh * Write the ctrl register. How it is written, depends upon the _PCT 905cff782mh * APCI object value. 915cff782mh */ 920e75152Eric Saxestatic void 935cff782mhwrite_ctrl(cpu_acpi_handle_t handle, uint32_t ctrl) 945cff782mh{ 955cff782mh cpu_acpi_pct_t *pct_ctrl; 965cff782mh uint64_t reg; 975cff782mh 985cff782mh pct_ctrl = CPU_ACPI_PCT_CTRL(handle); 995cff782mh 1007f606acMark Haywood switch (pct_ctrl->cr_addrspace_id) { 1015cff782mh case ACPI_ADR_SPACE_FIXED_HARDWARE: 1025cff782mh /* 1035cff782mh * Read current power state because reserved bits must be 1045cff782mh * preserved, compose new value, and write it. 1055cff782mh */ 1065cff782mh reg = rdmsr(IA32_PERF_CTL_MSR); 1075cff782mh reg &= ~((uint64_t)0xFFFF); 1085cff782mh reg |= ctrl; 1095cff782mh wrmsr(IA32_PERF_CTL_MSR, reg); 1105cff782mh break; 1115cff782mh 1125cff782mh case ACPI_ADR_SPACE_SYSTEM_IO: 1130e75152Eric Saxe (void) cpu_acpi_write_port(pct_ctrl->cr_address, ctrl, 1147f606acMark Haywood pct_ctrl->cr_width); 1155cff782mh break; 1165cff782mh 1175cff782mh default: 1185cff782mh DTRACE_PROBE1(ess_ctrl_unsupported_type, uint8_t, 1197f606acMark Haywood pct_ctrl->cr_addrspace_id); 1200e75152Eric Saxe return; 1215cff782mh } 1225cff782mh 1235cff782mh DTRACE_PROBE1(ess_ctrl_write, uint32_t, ctrl); 1245cff782mh} 1255cff782mh 1265cff782mh/* 1275cff782mh * Transition the current processor to the requested state. 1285cff782mh */ 129027bcc9Toomas Soomeint 130027bcc9Toomas Soomespeedstep_pstate_transition(xc_arg_t arg1, xc_arg_t arg2 __unused, 131027bcc9Toomas Soome xc_arg_t arg3 __unused) 1325cff782mh{ 133027bcc9Toomas Soome uint32_t req_state = (uint32_t)arg1; 1340e75152Eric Saxe cpupm_mach_state_t *mach_state = 1350e75152Eric Saxe (cpupm_mach_state_t *)CPU->cpu_m.mcpu_pm_mach_state; 1360e75152Eric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 1375cff782mh cpu_acpi_pstate_t *req_pstate; 1385cff782mh uint32_t ctrl; 1395cff782mh 1407f606acMark Haywood req_pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle); 1417f606acMark Haywood req_pstate += req_state; 1420e75152Eric Saxe 1435cff782mh DTRACE_PROBE1(ess_transition, uint32_t, CPU_ACPI_FREQ(req_pstate)); 1445cff782mh 1455cff782mh /* 1465cff782mh * Initiate the processor p-state change. 1475cff782mh */ 1487f606acMark Haywood ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate); 1490e75152Eric Saxe write_ctrl(handle, ctrl); 1505cff782mh 1515951cedHans Rosenfeld if (mach_state->ms_turbo != NULL) 1525951cedHans Rosenfeld cpupm_record_turbo_info(mach_state->ms_turbo, 153e5bbdc0Rafael Vanoni mach_state->ms_pstate.cma_state.pstate, req_state); 154e5bbdc0Rafael Vanoni 1550e75152Eric Saxe mach_state->ms_pstate.cma_state.pstate = req_state; 1560e75152Eric Saxe cpu_set_curr_clock(((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000)); 157027bcc9Toomas Soome return (0); 1585cff782mh} 1595cff782mh 1600e75152Eric Saxestatic void 1610e75152Eric Saxespeedstep_power(cpuset_t set, uint32_t req_state) 1625cff782mh{ 163375e050Mark Haywood /* 164375e050Mark Haywood * If thread is already running on target CPU then just 165375e050Mark Haywood * make the transition request. Otherwise, we'll need to 166375e050Mark Haywood * make a cross-call. 167375e050Mark Haywood */ 1685cff782mh kpreempt_disable(); 1690e75152Eric Saxe if (CPU_IN_SET(set, CPU->cpu_id)) { 170027bcc9Toomas Soome (void) speedstep_pstate_transition(req_state, 0, 0); 1710e75152Eric Saxe CPUSET_DEL(set, CPU->cpu_id); 1720e75152Eric Saxe } 1730e75152Eric Saxe if (!CPUSET_ISNULL(set)) { 1744da9975Toomas Soome xc_call((xc_arg_t)req_state, 0, 0, CPUSET2BV(set), 175027bcc9Toomas Soome speedstep_pstate_transition); 176375e050Mark Haywood } 1775cff782mh kpreempt_enable(); 1785cff782mh} 1795cff782mh 1805cff782mh/* 1815cff782mh * Validate that this processor supports Speedstep and if so, 1825cff782mh * get the P-state data from ACPI and cache it. 1835cff782mh */ 1847f606acMark Haywoodstatic int 1850e75152Eric Saxespeedstep_init(cpu_t *cp) 1865cff782mh{ 1870e75152Eric Saxe cpupm_mach_state_t *mach_state = 1880e75152Eric Saxe (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 1890e75152Eric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 1905cff782mh cpu_acpi_pct_t *pct_stat; 191511588bYuri Pankov static int logged = 0; 1925cff782mh 1930e75152Eric Saxe ESSDEBUG(("speedstep_init: processor %d\n", cp->cpu_id)); 1945cff782mh 1955cff782mh /* 1967f606acMark Haywood * Cache the P-state specific ACPI data. 1975cff782mh */ 1987f606acMark Haywood if (cpu_acpi_cache_pstate_data(handle) != 0) { 199511588bYuri Pankov if (!logged) { 200511588bYuri Pankov cmn_err(CE_NOTE, "!SpeedStep support is being " 201511588bYuri Pankov "disabled due to errors parsing ACPI P-state " 202511588bYuri Pankov "objects exported by BIOS."); 203511588bYuri Pankov logged = 1; 204511588bYuri Pankov } 2050e75152Eric Saxe speedstep_fini(cp); 2065cff782mh return (ESS_RET_NO_PM); 2075cff782mh } 2085cff782mh 2095cff782mh pct_stat = CPU_ACPI_PCT_STATUS(handle); 2107f606acMark Haywood switch (pct_stat->cr_addrspace_id) { 2115cff782mh case ACPI_ADR_SPACE_FIXED_HARDWARE: 2125cff782mh ESSDEBUG(("Transitions will use fixed hardware\n")); 2135cff782mh break; 2145cff782mh case ACPI_ADR_SPACE_SYSTEM_IO: 2155cff782mh ESSDEBUG(("Transitions will use system IO\n")); 2165cff782mh break; 2175cff782mh default: 2185cff782mh cmn_err(CE_WARN, "!_PCT conifgured for unsupported " 2197f606acMark Haywood "addrspace = %d.", pct_stat->cr_addrspace_id); 2205cff782mh cmn_err(CE_NOTE, "!CPU power management will not function."); 2210e75152Eric Saxe speedstep_fini(cp); 2225cff782mh return (ESS_RET_NO_PM); 2235cff782mh } 2245cff782mh 2250e75152Eric Saxe cpupm_alloc_domains(cp, CPUPM_P_STATES); 2265cff782mh 2275951cedHans Rosenfeld if (speedstep_turbo_supported()) 2285951cedHans Rosenfeld mach_state->ms_turbo = cpupm_turbo_init(cp); 229e5bbdc0Rafael Vanoni 2300e75152Eric Saxe ESSDEBUG(("Processor %d succeeded.\n", cp->cpu_id)) 2315cff782mh return (ESS_RET_SUCCESS); 2325cff782mh} 2335cff782mh 2345cff782mh/* 2355cff782mh * Free resources allocated by speedstep_init(). 2365cff782mh */ 2377f606acMark Haywoodstatic void 2380e75152Eric Saxespeedstep_fini(cpu_t *cp) 2395cff782mh{ 2400e75152Eric Saxe cpupm_mach_state_t *mach_state = 2410e75152Eric Saxe (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state); 2420e75152Eric Saxe cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 2437f606acMark Haywood 2440e75152Eric Saxe cpupm_free_domains(&cpupm_pstate_domains); 2457f606acMark Haywood cpu_acpi_free_pstate_data(handle); 246e5bbdc0Rafael Vanoni 2475951cedHans Rosenfeld if (mach_state->ms_turbo != NULL) 2485951cedHans Rosenfeld cpupm_turbo_fini(mach_state->ms_turbo); 2495951cedHans Rosenfeld mach_state->ms_turbo = NULL; 250444f66eMark Haywood} 251444f66eMark Haywood 252444f66eMark Haywoodstatic void 253444f66eMark Haywoodspeedstep_stop(cpu_t *cp) 254444f66eMark Haywood{ 255444f66eMark Haywood cpupm_mach_state_t *mach_state = 256444f66eMark Haywood (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state); 257444f66eMark Haywood cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 258444f66eMark Haywood 259444f66eMark Haywood cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains); 260444f66eMark Haywood cpu_acpi_free_pstate_data(handle); 261444f66eMark Haywood 2625951cedHans Rosenfeld if (mach_state->ms_turbo != NULL) 2635951cedHans Rosenfeld cpupm_turbo_fini(mach_state->ms_turbo); 2645951cedHans Rosenfeld mach_state->ms_turbo = NULL; 2657f606acMark Haywood} 2667f606acMark Haywood 2677f606acMark Haywoodboolean_t 2687f606acMark Haywoodspeedstep_supported(uint_t family, uint_t model) 2697f606acMark Haywood{ 2707f606acMark Haywood struct cpuid_regs cpu_regs; 2717f606acMark Haywood 2727f606acMark Haywood /* Required features */ 2737417cfdKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 2747417cfdKuriakose Kuruvilla !is_x86_feature(x86_featureset, X86FSET_MSR)) { 2757f606acMark Haywood return (B_FALSE); 2767f606acMark Haywood } 2777f606acMark Haywood 2787f606acMark Haywood /* 2797f606acMark Haywood * We only support family/model combinations which 2807f606acMark Haywood * are P-state TSC invariant. 2817f606acMark Haywood */ 2827f606acMark Haywood if (!((family == 0xf && model >= 0x3) || 2837f606acMark Haywood (family == 0x6 && model >= 0xe))) { 2847f606acMark Haywood return (B_FALSE); 2857f606acMark Haywood } 2867f606acMark Haywood 2877f606acMark Haywood /* 2887f606acMark Haywood * Enhanced SpeedStep supported? 2897f606acMark Haywood */ 2907f606acMark Haywood cpu_regs.cp_eax = 0x1; 2917f606acMark Haywood (void) __cpuid_insn(&cpu_regs); 2927f606acMark Haywood if (!(cpu_regs.cp_ecx & CPUID_INTC_ECX_EST)) { 2937f606acMark Haywood return (B_FALSE); 2947f606acMark Haywood } 2957f606acMark Haywood 2967f606acMark Haywood return (B_TRUE); 2975cff782mh} 298e5bbdc0Rafael Vanoni 299e5bbdc0Rafael Vanoniboolean_t 3005951cedHans Rosenfeldspeedstep_turbo_supported(void) 301e5bbdc0Rafael Vanoni{ 302e5bbdc0Rafael Vanoni struct cpuid_regs cpu_regs; 303e5bbdc0Rafael Vanoni 304e5bbdc0Rafael Vanoni /* Required features */ 3057417cfdKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 3067417cfdKuriakose Kuruvilla !is_x86_feature(x86_featureset, X86FSET_MSR)) { 307e5bbdc0Rafael Vanoni return (B_FALSE); 308e5bbdc0Rafael Vanoni } 309e5bbdc0Rafael Vanoni 310e5bbdc0Rafael Vanoni /* 311e5bbdc0Rafael Vanoni * turbo mode supported? 312e5bbdc0Rafael Vanoni */ 313e5bbdc0Rafael Vanoni cpu_regs.cp_eax = 0x6; 314e5bbdc0Rafael Vanoni (void) __cpuid_insn(&cpu_regs); 315e5bbdc0Rafael Vanoni if (!(cpu_regs.cp_eax & CPUID_TURBO_SUPPORT)) { 316e5bbdc0Rafael Vanoni return (B_FALSE); 317e5bbdc0Rafael Vanoni } 318e5bbdc0Rafael Vanoni 319e5bbdc0Rafael Vanoni return (B_TRUE); 320e5bbdc0Rafael Vanoni} 321