/** @file This file contains power management C State configuration functions for processors. Acronyms: - PPM: Processor Power Management - TM: Thermal Monitor - IST: Intel(R) Speedstep technology - HT: Hyper-Threading Technology @copyright INTEL CONFIDENTIAL Copyright 2012 - 2020 Intel Corporation. The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material may contain trade secrets and proprietary and confidential information of Intel Corporation and its suppliers and licensors, and is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel's prior express written permission. No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing. Unless otherwise agreed by Intel in writing, you may not remove or alter this notice or any other notice embedded in Materials by Intel or Intel's suppliers or licensors in any way. This file contains an 'Intel Peripheral Driver' and is uniquely identified as "Intel Reference Module" and is licensed for Intel CPUs and chipsets under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to additional terms of the license agreement. @par Specification **/ #include "PowerMgmtCommon.h" /** Initializes C States Power management features **/ VOID InitCState ( VOID ) { /// /// Initialize C states, some are general, some are processor specific. /// /// AcpiIoBase + 0x14 (PM_CST_LVL2) register no longer exists in PCH. /// When the IO in this range is read, the CPU puts itself into a mwait /// and does not forward this IO to the PCH. MSR_PMG_IO_CAPTURE_BASE was created because /// the functionality was moved from the PCH to the CPU. /// EnableCStates (PmcGetAcpiBase () + PM_CST_LVL2); InitCstatePreWake (); } /** Disable/Enable the CState Pre-Wake Feature **/ VOID InitCstatePreWake ( VOID ) { MSR_POWER_CTL_REGISTER PowerCtl; PowerCtl.Uint64 = AsmReadMsr64 (MSR_POWER_CTL); PowerCtl.Bits.CstatePrewakeDisable = 0; if (gCpuPowerMgmtTestConfig->CStatePreWake == FALSE) { PowerCtl.Bits.CstatePrewakeDisable = 1; } AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Uint64); return; } /** Enables C-State support as specified by the input flags on all logical processors and sets associated timing requirements in the chipset. @param[in] C3IoAddress IO address to generate C3 states (PM base + 014 usually) **/ VOID EnableCStates ( IN UINT16 C3IoAddress ) { MSR_POWER_CTL_REGISTER PowerCtl; MSR_C_STATE_LATENCY_CONTROL_0_REGISTER CStateLatencyControl0; MSR_C_STATE_LATENCY_CONTROL_1_REGISTER CStateLatencyControl1; MSR_C_STATE_LATENCY_CONTROL_2_REGISTER CStateLatencyControl2; MSR_C_STATE_LATENCY_CONTROL_3_REGISTER CStateLatencyControl3; MSR_C_STATE_LATENCY_CONTROL_4_REGISTER CStateLatencyControl4; MSR_C_STATE_LATENCY_CONTROL_5_REGISTER CStateLatencyControl5; UINT16 EnableCStateParameters; /// /// Load the C-State parameters to pass to the core function. /// EnableCStateParameters = C3IoAddress; /// /// Enable C-States on all logical processors. /// ApSafeEnableCStates(&EnableCStateParameters); mMpServices2Ppi->StartupAllAPs ( mMpServices2Ppi, (EFI_AP_PROCEDURE) ApSafeEnableCStates, FALSE, 0, (VOID *) &EnableCStateParameters ); /// /// If C-states are disabled or not supported, Disable C1e and retrun /// if ((mPpmFlags & PPM_C_STATES) == 0) { PowerCtl.Uint64 = AsmReadMsr64 (MSR_POWER_CTL); PowerCtl.Bits.C1eEnable = 0; AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Uint64); DEBUG ((DEBUG_INFO, "Setup C state disabled.Disable C1e. MSR(1FC) : 0x%08x\n", PowerCtl.Uint64)); return; } /// /// Configure supported enhanced C-states /// /// Read Power Ctl MSR /// PowerCtl.Uint64 = AsmReadMsr64 (MSR_POWER_CTL); DEBUG ((DEBUG_INFO, "MSR(1FC) before configuring C1E: 0x%08x\n", PowerCtl.Uint64)); /// /// Enable supported states /// if (mPpmFlags & PPM_C1E) { PowerCtl.Bits.C1eEnable = 1; } else { PowerCtl.Bits.C1eEnable = 0; } /// /// Update Power Control MSR /// AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Uint64); DEBUG ((DEBUG_INFO, "MSR(1FC) after configuring C1E: 0x%08x\n", PowerCtl.Uint64)); /// /// Program Interrupt response time limits used by processor to decided when to get into /// package C3 /// DEBUG ((DEBUG_INFO, "Programming the C3 (MSR 0x60A) Latencies \n")); // // Package C3 Interrupt response time // if (gCpuPowerMgmtTestConfig->CstateLatencyControl0Irtl > 0) { CStateLatencyControl0.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_0); DEBUG ((DEBUG_INFO, "MSR(60A) before configuring Latency: 0x%08x\n", CStateLatencyControl0.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x60A /// CStateLatencyControl0.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl0Irtl; CStateLatencyControl0.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl0TimeUnit; CStateLatencyControl0.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_0, CStateLatencyControl0.Uint64); } /// /// Program Interrupt response time limits used by processor to decided when to get into /// package C6 and C7 /// DEBUG ((DEBUG_INFO, "Programming the C6/C7/C8/C9/C10 (MSR 0x60B, 0x60C ,0x633, 0x634, 0x635 IRTL if not auto.\n")); // // Package C6/C7 short Interrupt response time // if (gCpuPowerMgmtTestConfig->CstateLatencyControl1Irtl > 0) { CStateLatencyControl1.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_1); DEBUG ((DEBUG_INFO, "MSR(60B) before configuring Latency: 0x%08x\n", CStateLatencyControl1.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x60B /// CStateLatencyControl1.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl1Irtl; CStateLatencyControl1.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl1TimeUnit; CStateLatencyControl1.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_1, CStateLatencyControl1.Uint64); } // // Package C6/C7 long Interrupt response time // if (gCpuPowerMgmtTestConfig->CstateLatencyControl2Irtl > 0) { CStateLatencyControl2.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_2); DEBUG ((DEBUG_INFO, "MSR(60C) before configuring Latency: 0x%08x\n", CStateLatencyControl2.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x60C /// CStateLatencyControl2.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl2Irtl; CStateLatencyControl2.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl2TimeUnit; CStateLatencyControl2.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_2, CStateLatencyControl2.Uint64); } // // Package C8 Interrupt response time // if (gCpuPowerMgmtTestConfig->CstateLatencyControl3Irtl > 0) { CStateLatencyControl3.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_3); DEBUG ((DEBUG_INFO, "MSR(633) before configuring Latency: 0x%08x\n", CStateLatencyControl3.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x633 /// CStateLatencyControl3.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl3Irtl; CStateLatencyControl3.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl3TimeUnit; CStateLatencyControl3.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_3, CStateLatencyControl3.Uint64); } // // Package C9 Interrupt response time // if (gCpuPowerMgmtTestConfig->CstateLatencyControl4Irtl > 0) { CStateLatencyControl4.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_4); DEBUG ((DEBUG_INFO, "MSR(634) before configuring Latency: 0x%08x\n", CStateLatencyControl4.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x634 /// CStateLatencyControl4.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl4Irtl; CStateLatencyControl4.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl4TimeUnit; CStateLatencyControl4.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_4, CStateLatencyControl4.Uint64); } /// /// Package C10 Interrupt response time /// if (gCpuPowerMgmtTestConfig->CstateLatencyControl5Irtl > 0) { CStateLatencyControl5.Uint64 = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_5); DEBUG ((DEBUG_INFO, "MSR(635) before configuring Latency: 0x%08x\n", CStateLatencyControl5.Uint64)); /// /// Program Interrupt Response Time Unit and Latency for MSR 0x635 /// CStateLatencyControl5.Bits.Value = gCpuPowerMgmtTestConfig->CstateLatencyControl5Irtl; CStateLatencyControl5.Bits.Multiplier = gCpuPowerMgmtTestConfig->CstateLatencyControl5TimeUnit; CStateLatencyControl5.Bits.Valid = 1; AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_5, CStateLatencyControl5.Uint64); } } /** Enable C-State support as specified by the input flags on a logical processor. Configure BIOS C1 Coordination (SMI coordination) Enable IO redirection coordination Choose proper coordination method Configure extended C-States This function must be MP safe. @param[in out] Buffer Pointer to a ENABLE_CSTATE_PARAMS containing the necessary information to enable C-States @retval EFI_SUCCESS Processor C-State support configured successfully. **/ VOID EFIAPI ApSafeEnableCStates ( IN OUT VOID *Buffer ) { MSR_CLOCK_CST_CONFIG_CONTROL_REGISTER PmCfgCtrlMsr; MSR_PMG_IO_CAPTURE_BASE_REGISTER IoCaptAddr; MSR_IA32_MISC_ENABLE_REGISTER MiscEnable; UINT16 C3IoAddress; /// /// Extract parameters from the buffer /// C3IoAddress = *((UINT16 *) Buffer); /// /// If C-states are disabled in setup, disable C-states /// if (!(mPpmFlags & PPM_C_STATES)) { PmCfgCtrlMsr.Uint64 = AsmReadMsr64 (MSR_CLOCK_CST_CONFIG_CONTROL); PmCfgCtrlMsr.Bits.MaxPkgCState = 0; AsmWriteMsr64 (MSR_CLOCK_CST_CONFIG_CONTROL, PmCfgCtrlMsr.Uint64); return; } /// /// Set C-state package limit to the highest C-state enabled /// PmCfgCtrlMsr.Uint64 = AsmReadMsr64 (MSR_CLOCK_CST_CONFIG_CONTROL); /// /// mPpmFlags might be override by others. So update the MaxPkgCState based on mPpmFlags setting. /// if ((mPpmFlags & PPM_C10) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C10)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C10; } else if ((mPpmFlags & PPM_C9) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C9)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C9; } else if ((mPpmFlags & PPM_C8) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C8)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C8; } else if ((mPpmFlags & PPM_C7S) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C7S)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C7S; } else if ((mPpmFlags & PPM_C7) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C7)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C7; } else if ((mPpmFlags & PPM_C6) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C6)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C6; } else if ((mPpmFlags & PPM_C1) && (PmCfgCtrlMsr.Bits.MaxPkgCState >= V_CSTATE_LIMIT_C1)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C1; } if (gCpuPowerMgmtTestConfig->PkgCStateLimit != PkgCpuDefault) { PmCfgCtrlMsr.Bits.MaxPkgCState = 0; if (gCpuPowerMgmtTestConfig->PkgCStateLimit < PkgCMax) { PmCfgCtrlMsr.Bits.MaxPkgCState = gCpuPowerMgmtTestConfig->PkgCStateLimit; } else if ((mPpmFlags & PPM_C10) && (gCpuPowerMgmtTestConfig->PkgCStateLimit == PkgAuto)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C10; } else if ((mPpmFlags & PPM_C9) && (gCpuPowerMgmtTestConfig->PkgCStateLimit == PkgAuto)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C9; } else if ((mPpmFlags & PPM_C8) && (gCpuPowerMgmtTestConfig->PkgCStateLimit == PkgAuto)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C8; } else if ((mPpmFlags & PPM_C7S) && (gCpuPowerMgmtTestConfig->PkgCStateLimit == PkgAuto)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C7S; } else if ((mPpmFlags & PPM_C7) && (gCpuPowerMgmtTestConfig->PkgCStateLimit == PkgAuto)) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C7; } else if (mPpmFlags & PPM_C6) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C6; } else if (mPpmFlags & PPM_C1) { PmCfgCtrlMsr.Bits.MaxPkgCState = V_CSTATE_LIMIT_C1; } } /// /// Configure C State IO redirection /// if (gCpuPowerMgmtTestConfig->CstCfgCtrIoMwaitRedirection) { PmCfgCtrlMsr.Bits.IoMwaitRedirection = 1; } // // Enable TimedMwait // if (mPpmFlags & PPM_TIMED_MWAIT) { PmCfgCtrlMsr.Bits.TimedMwaitEnable = 1; } /// /// Configure C-state auto-demotion /// PmCfgCtrlMsr.Bits.C1StateAutoDemotionEnable = 0; if (gCpuPowerMgmtTestConfig->C1AutoDemotion) { /// /// Enable C6/C7 Auto-demotion to C1 /// PmCfgCtrlMsr.Bits.C1StateAutoDemotionEnable = 1; } /// /// Configure C-state un-demotion /// PmCfgCtrlMsr.Bits.Enc1undemotion = 0; if (gCpuPowerMgmtTestConfig->C1UnDemotion) { /// /// Enable un-demotion from demoted C1 /// PmCfgCtrlMsr.Bits.Enc1undemotion = 1; } /// /// Configure Package C-state Demotion / un-demotion /// PmCfgCtrlMsr.Bits.Enpkgcautodemotion = 0; PmCfgCtrlMsr.Bits.Enpkgcundemotion = 0; if (gCpuPowerMgmtTestConfig->PkgCStateDemotion) { /// /// Enable Package C-state Demotion /// PmCfgCtrlMsr.Bits.Enpkgcautodemotion = 1; } if (gCpuPowerMgmtTestConfig->PkgCStateUnDemotion) { /// /// Enable Package C-state un-demotion /// PmCfgCtrlMsr.Bits.Enpkgcundemotion = 1; } AsmWriteMsr64 (MSR_CLOCK_CST_CONFIG_CONTROL, PmCfgCtrlMsr.Uint64); /// /// Enable MONITOR/MWAIT support /// (already done on BSP, but must be done on all components.) /// MiscEnable.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); MiscEnable.Bits.MONITOR = 1; AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MiscEnable.Uint64); /// /// Configuration of I/O capture and I/O coordination SMI MSR. /// Configure the base port and range in the MSR to match LVL_X settings in ACPI tables /// Set I/O capture base port and range /// IoCaptAddr.Uint64 = AsmReadMsr64 (MSR_PMG_IO_CAPTURE_BASE); /// /// Mask off CST range and set the CST range /// IoCaptAddr.Bits.CstRange = 0; if (mPpmFlags & PPM_C10) { IoCaptAddr.Bits.CstRange |= V_IO_CAPT_LVL7; } else if (mPpmFlags & PPM_C9) { IoCaptAddr.Bits.CstRange |= V_IO_CAPT_LVL6; } else if (mPpmFlags & PPM_C8) { IoCaptAddr.Bits.CstRange |= V_IO_CAPT_LVL5; } else if (mPpmFlags & PPM_C7) { IoCaptAddr.Bits.CstRange |= V_IO_CAPT_LVL4; } else if (mPpmFlags & PPM_C6) { IoCaptAddr.Bits.CstRange |= V_IO_CAPT_LVL3; } /// /// Set the base CST address /// IoCaptAddr.Bits.Lvl2b = C3IoAddress; AsmWriteMsr64 (MSR_PMG_IO_CAPTURE_BASE, IoCaptAddr.Uint64); return; }