text: /*
   * 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.
   */
  
  /*
   * Copyright (c) 2009, Intel Corporation.
   * All rights reserved.
   */
  
  /*
   * Intel specific CPU power management support.
   */
  
  #include <sys/x86_archext.h>
  #include <sys/cpu_acpi.h>
  #include <sys/speedstep.h>
  #include <sys/cpupm_throttle.h>
  #include <sys/cpu_idle.h>
  #include <sys/archsystm.h>
  
  /*
   * The Intel Processor Driver Capabilities (_PDC).
   * See Intel Processor Vendor-Specific ACPI Interface Specification
   * for details.
   */
  #define	CPUPM_INTEL_PDC_REVISION	0x1
  #define	CPUPM_INTEL_PDC_PS_MSR		0x0001
  #define	CPUPM_INTEL_PDC_C1_HALT		0x0002
  #define	CPUPM_INTEL_PDC_TS_MSR		0x0004
  #define	CPUPM_INTEL_PDC_MP		0x0008
  #define	CPUPM_INTEL_PDC_C2C3_MP		0x0010
  #define	CPUPM_INTEL_PDC_SW_PSD		0x0020
  #define	CPUPM_INTEL_PDC_TSD		0x0080
  #define	CPUPM_INTEL_PDC_C1_FFH		0x0100
  #define	CPUPM_INTEL_PDC_HW_PSD		0x0800
  
  static uint32_t cpupm_intel_pdccap = 0;
  
  /*
   * MSR for Intel ENERGY_PERF_BIAS feature.
   * The default processor power operation policy is max performance.
   * Power control unit drives to max performance at any energy cost.
   * This MSR is designed to be a power master control knob,
   * it provides 4-bit OS input to the HW for the logical CPU, based on
   * user power-policy preference(scale of 0 to 15). 0 is highest
   * performance, 15 is minimal energy consumption.
   * 7 is a good balance between performance and energy consumption.
   */
  #define	IA32_ENERGY_PERF_BIAS_MSR	0x1B0
  #define	EPB_MSR_MASK			0xF
  #define	EPB_MAX_PERF			0
  #define	EPB_BALANCE			7
  #define	EPB_MAX_POWER_SAVE		15
  
  /*
   * The value is used to initialize the user power policy preference
   * in IA32_ENERGY_PERF_BIAS_MSR. Variable is used here to allow tuning
   * from the /etc/system file.
   */
  uint64_t cpupm_iepb_policy = EPB_MAX_PERF;
  
  static void cpupm_iepb_set_policy(uint64_t power_policy);
  
  boolean_t
  cpupm_intel_init(cpu_t *cp)
  {
  	cpupm_mach_state_t *mach_state =
  	    (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
  	uint_t family;
  	uint_t model;
  
  	if (x86_vendor != X86_VENDOR_Intel)
  		return (B_FALSE);
  
  	family = cpuid_getfamily(cp);
  	model = cpuid_getmodel(cp);
  
  	cpupm_intel_pdccap = CPUPM_INTEL_PDC_MP;
  
  	/*
  	 * If we support SpeedStep on this processor, then set the
  	 * correct cma_ops for the processor and enable appropriate
  	 * _PDC bits.
  	 */
  	if (speedstep_supported(family, model)) {
  		mach_state->ms_pstate.cma_ops = &speedstep_ops;
  		cpupm_intel_pdccap |= CPUPM_INTEL_PDC_PS_MSR |
  		    CPUPM_INTEL_PDC_C1_HALT | CPUPM_INTEL_PDC_SW_PSD |
  		    CPUPM_INTEL_PDC_HW_PSD;
  	} else {
  		mach_state->ms_pstate.cma_ops = NULL;
  	}
  
  	/*
  	 * Set the correct tstate_ops for the processor and
  	 * enable appropriate _PDC bits.
  	 */
  	mach_state->ms_tstate.cma_ops = &cpupm_throttle_ops;
  	cpupm_intel_pdccap |= CPUPM_INTEL_PDC_TS_MSR |
  	    CPUPM_INTEL_PDC_TSD;
  
  	/*
  	 * If we support deep cstates on this processor, then set the
  	 * correct cstate_ops for the processor and enable appropriate
  	 * _PDC bits.
  	 */
  	mach_state->ms_cstate.cma_ops = &cpu_idle_ops;
  	cpupm_intel_pdccap |= CPUPM_INTEL_PDC_C1_HALT |
  	    CPUPM_INTEL_PDC_C2C3_MP | CPUPM_INTEL_PDC_C1_FFH;
  
  	/*
  	 * _PDC support is optional and the driver should
  	 * function even if the _PDC write fails.
  	 */
  	(void) cpu_acpi_write_pdc(mach_state->ms_acpi_handle,
  	    CPUPM_INTEL_PDC_REVISION, 1, &cpupm_intel_pdccap);
  
  	/*
  	 * If Intel ENERGY PERFORMANCE BIAS feature is supported,
  	 * provides input to the HW, based on user power-policy.
  	 */
  	if (cpuid_iepb_supported(cp)) {
  		cpupm_iepb_set_policy(cpupm_iepb_policy);
  	}
  
  	return (B_TRUE);
  }
  
  /*
   * ENERGY_PERF_BIAS setting,
   * A hint to HW, based on user power-policy
   */
  static void
  cpupm_iepb_set_policy(uint64_t iepb_policy)
  {
  	ulong_t		iflag;
  	uint64_t	epb_value;
  
  	epb_value = iepb_policy & EPB_MSR_MASK;
  
  	iflag = intr_clear();
  	wrmsr(IA32_ENERGY_PERF_BIAS_MSR, epb_value);
  	intr_restore(iflag);
  }
  