diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c')
-rw-r--r-- | ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c b/ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c new file mode 100644 index 0000000..6a26231 --- /dev/null +++ b/ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c @@ -0,0 +1,333 @@ +/** @file + This is the SMM driver for saving and restoring the powermanagement related MSRs + +@copyright + Copyright (c) 2011 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and 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 + +**/ +#include "PowerMgmtS3.h" +#include "PowerMgmtDefinitions.h" +#include "CpuAccess.h" +#include "CpuPlatformLib.h" + +#include EFI_PROTOCOL_DEPENDENCY (CpuPlatformPolicy) +#include EFI_PROTOCOL_DEPENDENCY (SmmSwDispatch) +#include EFI_PROTOCOL_DEPENDENCY (SmmBase) + +/// +/// SMM system table pointer +/// +EFI_SMM_SYSTEM_TABLE *mSmst; +DXE_CPU_PLATFORM_POLICY_PROTOCOL *mCpuPlatformPolicy; +/// +/// MSR table for S3 resume +/// +STATIC EFI_MSR_VALUES mMsrValues[] = { + { MSR_IA32_PERF_CTRL, 0, B_IA32_PERF_CTRLP_STATE_TARGET, TRUE }, + { MSR_PMG_IO_CAPTURE_BASE, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PMG_CST_CONFIG, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_MISC_PWR_MGMT, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_IA32_MISC_ENABLE, 0, B_CPUID_POWER_MANAGEMENT_EAX_TURBO | B_MSR_IA32_MISC_DISABLE_TURBO | B_MSR_IA32_MISC_ENABLE_MONITOR | B_MSR_IA32_MISC_ENABLE_TME | B_MSR_IA32_MISC_ENABLE_EIST, TRUE }, + { MSR_POWER_CTL, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PACKAGE_POWER_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PLATFORM_POWER_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_C_STATE_LATENCY_CONTROL_0, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_C_STATE_LATENCY_CONTROL_1, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_C_STATE_LATENCY_CONTROL_2, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_C_STATE_LATENCY_CONTROL_3, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_C_STATE_LATENCY_CONTROL_4, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_C_STATE_LATENCY_CONTROL_5, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_FLEX_RATIO, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_IA32_ENERGY_PERFORMANCE_BIAS, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_CONFIG_TDP_CONTROL, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_RFI_TUNNING, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_TURBO_ACTIVATION_RATIO, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_DDR_RAPL_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_TURBO_RATIO_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE } +}; + +/** + Save processor MSR runtime settings for S3. + + @retval EFI_SUCCESS Processor MSR setting is saved. +**/ +STATIC +EFI_STATUS +S3SaveMsr ( + VOID + ) +{ + UINT32 Index; + EFI_CPUID_REGISTER Cpuid06 = { 0, 0, 0, 0 }; + UINT64 MsrValue; + + for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) { + DEBUG ((EFI_D_INFO, " MSR Number: %x\n", mMsrValues[Index].Index)); + if (mMsrValues[Index].Index == MSR_IA32_ENERGY_PERFORMANCE_BIAS) { + /// + /// MSR_IA32_ENERGY_PERFORMANCE_BIAS (1B0h) is accessible only if CPUID(6), ECX[3] = 1 to indicate feature availability. + /// + AsmCpuid (CPUID_FUNCTION_6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx); + if (!(Cpuid06.RegEcx & B_CPUID_POWER_MANAGEMENT_ECX_ENERGY_EFFICIENT_POLICY_SUPPORT)) { + mMsrValues[Index].RestoreFlag = FALSE; + continue; + } + } + /// + /// Check for HSW specific MSRs + /// + MsrValue = AsmReadMsr64 (MSR_PLATFORM_INFO); + /// + /// + /// Check PLATFORM_INFO MSR[34:33] > 0 before accessing the MSR_CONFIG_TDP_CONTROL + /// + if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && + ((RShiftU64 (MsrValue, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET) & 0x03)) + ) { + mMsrValues[Index].RestoreFlag = TRUE; + } + /// + /// MSR_TURBO_ACTIVATION_RATIO, MSR_DDR_RAPL_LIMIT, MSR_RFI_TUNNING are supported only on HSW A0 or above. + /// + if (mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) { + mMsrValues[Index].RestoreFlag = TRUE; + } + if (mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) { + mMsrValues[Index].RestoreFlag = TRUE; + } + /// + /// Check PLATFORM_INFO MSR[25] == 1 before accessing the MSR_RFI_TUNNING + /// + if (mMsrValues[Index].Index == MSR_RFI_TUNNING) { + if ((mCpuPlatformPolicy->PowerMgmtConfig->RfiFreqTunningOffset != AUTO) && (MsrValue & B_FIVR_RFI_TUNING_AVAIL)) { + mMsrValues[Index].RestoreFlag = TRUE; + } + } + + if(GetCpuSku()== EnumCpuUlt) { + if ((mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_3) || + (mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_4)|| + (mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_5)){ + mMsrValues[Index].RestoreFlag = TRUE; + } + } + + /// + /// PL3 is supported on HSW ULT C0 & HSW C0 and later + /// + if (mMsrValues[Index].Index == MSR_PLATFORM_POWER_LIMIT) { + if (((GetCpuFamily() == EnumCpuHsw) && (GetCpuStepping() >= EnumHswC0)) + || ((GetCpuFamily() == EnumCpuHswUlt) && (GetCpuStepping() >= EnumHswUltC0))) { + mMsrValues[Index].RestoreFlag = TRUE; + } + } + + if (mMsrValues[Index].RestoreFlag == TRUE) { + mMsrValues[Index].Value = AsmReadMsr64 (mMsrValues[Index].Index); + DEBUG ((EFI_D_INFO, " MSR Number %x read Done \n", mMsrValues[Index].Index)); + } + } + + return EFI_SUCCESS; +} + +/** + Restore processor MSR runtime settings for S3. + + @param[in] DispatchHandle - The handle of this callback, obtained when registering + @param[in] DispatchContex - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + + @retval EFI_SUCCESS Processor MSR setting is restored. +**/ +void +S3RestoreMsr ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContex + ) +{ + /// + /// Restore MSR's on all logical processors. + /// + RunOnAllLogicalProcessors (ApSafeRestoreMsr, NULL); +} + +/** + Runs the specified procedure on all logical processors, passing in the + parameter buffer to the procedure. + + @param[in] Procedure The function to be run. + @param[in] Buffer Pointer to a parameter buffer. + + @retval EFI_SUCCESS +**/ +STATIC +EFI_STATUS +RunOnAllLogicalProcessors ( + IN OUT EFI_AP_PROCEDURE Procedure, + IN OUT VOID *Buffer + ) +{ + UINTN Index; + EFI_STATUS Status; + /// + /// Run the procedure on all logical processors. + /// + (*Procedure)(Buffer); + for (Index = 1; Index < mSmst->NumberOfCpus; Index++) { + Status = EFI_NOT_READY; + while (Status != EFI_SUCCESS) { + Status = mSmst->SmmStartupThisAp (Procedure, Index, Buffer); + if (Status != EFI_SUCCESS) { + /// + /// SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again. + /// + PchPmTimerStall (PPM_WAIT_PERIOD); + } + } + } + + return EFI_SUCCESS; +} + +/** + This function will restore MSR settings. + + This function must be MP safe. + + @param[in] Buffer Unused + + @retval EFI_SUCCESS MSR restored +**/ +VOID +EFIAPI +ApSafeRestoreMsr ( + IN OUT VOID *Buffer + ) +{ + UINT32 Index; + UINT64 MsrValue; + + for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) { + /// + /// Check RestoreFlag and skip restoring the MSR if it is set to FALSE + /// + if (mMsrValues[Index].RestoreFlag == FALSE) { + DEBUG ((EFI_D_INFO, "Skipping MSR : %x as RestoreFalg is set to FALSE \n", mMsrValues[Index].Index)); + continue; + } + /// + /// Check for Lock bits before programming + /// + MsrValue = AsmReadMsr64 (mMsrValues[Index].Index); + if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && (MsrValue & CONFIG_TDP_CONTROL_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) && (MsrValue & MSR_TURBO_ACTIVATION_RATIO_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_PACKAGE_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_PLATFORM_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + MsrValue = AsmReadMsr64 (mMsrValues[Index].Index); + MsrValue &= ~mMsrValues[Index].BitMask; + MsrValue |= (mMsrValues[Index].Value & mMsrValues[Index].BitMask); + AsmWriteMsr64 (mMsrValues[Index].Index, MsrValue); + } + + return; +} + +/** + Initialize the S3 power management Handler. + + @param[in] ImageHandle - Pointer to the loaded image protocol for this driver + @param[in] SystemTable - Pointer to the EFI System Table + + @retval EFI_SUCCESS The driver installes/initialized correctly. +**/ +EFI_STATUS +PowerMgmtS3SmmEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH_CONTEXT SwContext; + EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch; + EFI_HANDLE SwHandle; + EFI_SMM_BASE_PROTOCOL *SmmBase; + + SwHandle = 0; + DEBUG ((EFI_D_INFO, " PpmS3SmmEntryPoint Started : \n")); + /// + /// Determine if we are in boot service or SMM. + /// + Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &SmmBase); + ASSERT_EFI_ERROR (Status); + + /// + /// Initialize global variables + /// + Status = SmmBase->GetSmstLocation (SmmBase, &mSmst); + ASSERT_EFI_ERROR (Status); + + /// + /// Locate platform configuration information + /// + Status = gBS->LocateProtocol (&gDxeCpuPlatformPolicyProtocolGuid, NULL, (VOID **) &mCpuPlatformPolicy); + ASSERT_EFI_ERROR (Status); + + /// + /// Locate the ICH SMM SW dispatch protocol + /// + Status = gBS->LocateProtocol (&gEfiSmmSwDispatchProtocolGuid, NULL, (VOID **) &SwDispatch); + ASSERT_EFI_ERROR (Status); + + /// + /// Register ACPI S3 MSR restore handler + /// + SwContext.SwSmiInputValue = mCpuPlatformPolicy->PowerMgmtConfig->S3RestoreMsrSwSmiNumber; + + Status = SwDispatch->Register ( + SwDispatch, + (EFI_SMM_SW_DISPATCH) S3RestoreMsr, + &SwContext, + &SwHandle + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Save MSRs for S3 Resume. + /// + DEBUG ((EFI_D_INFO, " Saving Processor MSR for S3 Resume \n")); + + S3SaveMsr (); + + return EFI_SUCCESS; +} |