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/Dxe/PowerMgmtInit.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c')
-rw-r--r-- | ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c new file mode 100644 index 0000000..414167d --- /dev/null +++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c @@ -0,0 +1,840 @@ +/** @file + Processor Power Management initialization code. This code determines current + user configuration and modifies and loads ASL as well as initializing chipset + and processor features to enable the proper power management. + + Acronyms: + PPM - Processor Power Management + TM - Thermal Monitor + IST - Intel(R) Speedstep technology + HT - Hyper-Threading Technology + +@copyright + Copyright (c) 1999 - 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 "PowerMgmtInit.h" + +// +// Global variables +// +#include <Protocol\GlobalNvsArea\GlobalNvsArea.h> // <<<< +/// +/// Power Managment policy configurations +/// +POWER_MGMT_CONFIG *mCpuPmConfig = NULL; +EFI_CPUID_REGISTER mCpuid01 = { 0, 0, 0, 0 }; // CPUID 01 values +// +// Values for FVID table calculate. +// +UINT16 mTurboBusRatio = 0; +UINT16 mMaxBusRatio = 0; +UINT16 mMinBusRatio = 0; +UINT16 mProcessorFlavor = 0; +UINT16 mBspBootRatio = 0; +UINT16 mPackageTdp = 0; ///< Processor TDP value in MSR_PACKAGE_POWER_SKU. +UINT16 mPackageTdpWatt = 0; ///< Processor TDP value in Watts. +UINT16 mCpuConfigTdpBootRatio = 0; ///< Config TDP Boot settings +UINT16 mCustomPowerUnit = 1; +UINT16 mCpuCacheSize = 0; ///< Cache Size in KB +UINT8 mCpuPolicyRevision = 0; +DXE_CPU_PLATFORM_POLICY_PROTOCOL *mCpuPlatformPolicy = NULL; + +/// +/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit) +/// +UINT8 mProcessorPowerUnit = 0; +/// +/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +UINT16 mPackageMaxPower = 0; +/// +/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +UINT16 mPackageMinPower = 0; + +UINT8 mControllableTdpEnable = 0; ///< Controllable TDP enable/Disable +UINT8 mRatioLimitProgrammble = 0; ///< Programmable Ratio Limit +UINT8 mTdpLimitProgrammble = 0; ///< Porgrammable TDP Limit +PPM_GLOBAL_NVS_AREA_PROTOCOL *mPpmGlobalNvsAreaProtocol = NULL; ///< Ppm GlobalNvs Protocol +EFI_MP_SERVICES_PROTOCOL *mMpService = NULL; ///< Mp Services Protocol + +// +// FVID Table Information +// Default FVID table +// One header field plus states +// +UINT16 mNumberOfStates = 0; +FVID_TABLE mEmptyFvidTable[FVID_MAX_STATES + 1]; +FVID_TABLE *mFvidPointer = &mEmptyFvidTable[0]; + +// +// Globals to support updating ACPI Tables +// +EFI_ACPI_SUPPORT_PROTOCOL *mAcpiSupport = NULL; +EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mApIstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mApCstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mCpuPmTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mApTstTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mLakeTinyTable = NULL; +EFI_ACPI_DESCRIPTION_HEADER *mCtdpTable = NULL; + +/** + Initialize the power management support. + This function will do boot time configuration: + Detect HW capabilities and SW configuration + Initialize HW and software state (primarily MSR and ACPI tables) + + @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. + @retval Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems. +**/ +EFI_STATUS +InitializePowerManagement ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + PPM_GLOBAL_NVS_AREA_PROTOCOL PpmGlobalNvsAreaProtocol; + EFI_GUID EfiPpmGlobalNvsAreaProtocolGuid = EFI_PPM_GLOBAL_NVS_AREA_PROTOCOL_GUID; + + Handle = NULL; + + /// + /// Locate platform configuration information + /// + Status = gBS->LocateProtocol (&gDxeCpuPlatformPolicyProtocolGuid, NULL, (VOID **) &mCpuPlatformPolicy); + ASSERT_EFI_ERROR (Status); + + /// + /// Initialize the Global pointer for Power Managment Platform policy + /// + mCpuPmConfig = mCpuPlatformPolicy->PowerMgmtConfig; + + Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (PPM_GLOBAL_NVS_AREA), (VOID **) &PpmGlobalNvsAreaProtocol.Area); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *) PpmGlobalNvsAreaProtocol.Area, sizeof (PPM_GLOBAL_NVS_AREA)); + + PpmGlobalNvsAreaProtocol.Area->Revision = PPM_GLOBAL_NVS_AREA_REVISION_1; + PpmGlobalNvsAreaProtocol.Area->MiscPowerManagementFlags |= mCpuPmConfig->pFunctionEnables->LakeTiny; + + /// + /// Install Cpu Power management GlobalNVS Area protocol + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &EfiPpmGlobalNvsAreaProtocolGuid, + &PpmGlobalNvsAreaProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + + DumpCpuPmConfig (); + + /// + /// Locate the S3 resume scripting protocol + /// + INITIALIZE_SCRIPT (ImageHandle, SystemTable); + + /// + /// Initialize Power management Global variables + /// + InitializePowerManagementGlobalVariables (); + + /// + /// Initialize CPU Power management code (determine HW and configured state, configure hardware and software accordingly) + /// + Status = InitializePpm (); + ASSERT_EFI_ERROR (Status); + + /// + /// Install the PowerMgmtInitDone Protocol so that PowerMgmtS3 driver can load to save the MSRs for S3 resume + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiPowerMgmtInitDoneProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + + return EFI_SUCCESS; +} + +/** + Initializes the platform power management global variable. + This must be called prior to any of the functions being used. + + @retval EFI_SUCCESS Library was initialized successfully + @retval EFI_DEVICE_ERROR If CPU is not supported by this library +**/ +VOID +InitializePowerManagementGlobalVariables ( + VOID + ) +{ + EFI_STATUS Status; + MSR_REGISTER TempMsr; + MSR_REGISTER PackagePowerSKUUnitMsr; + MSR_REGISTER PlatformInfoMsr; + EFI_GUID EfiMpServiceProtocolGuid = EFI_MP_SERVICES_PROTOCOL_GUID; + UINT16 Associativity; + UINT16 CachePartitions; + UINT16 CacheLineSize; + UINT16 CacheNumberofSets; + EFI_CPUID_REGISTER Cpuid04; +// >>>> + EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea; + EFI_GUID gEfiGlobalNvsAreaProtocolGuid = EFI_GLOBAL_NVS_AREA_PROTOCOL_GUID; +// <<<< + // + // Read the CPUID information + // + AsmCpuid (CPUID_VERSION_INFO, &mCpuid01.RegEax, &mCpuid01.RegEbx, &mCpuid01.RegEcx, &mCpuid01.RegEdx); + + /// + /// Locate Ppm GlobalNvs Protocol. + /// + Status = gBS->LocateProtocol ( + &gPpmGlobalNvsAreaProtocolGuid, + NULL, + (VOID **) &mPpmGlobalNvsAreaProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Ppm GloableNvs protocol not found")); + } + ASSERT_EFI_ERROR (Status); + if (mPpmGlobalNvsAreaProtocol != NULL) { + mPpmGlobalNvsAreaProtocol->Area->Cpuid = GetCpuFamily() | GetCpuStepping(); + } + + /// + /// Locate MP service protocol + /// + Status = gBS->LocateProtocol ( + &EfiMpServiceProtocolGuid, + NULL, + (VOID **) &mMpService + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Get Platform ID by reading System Agent's Device ID (B0:D0:F0:R02) + /// + mProcessorFlavor = McD0PciCfg16 (R_SA_MC_DEVICE_ID); + + // + // Read the CPUID4 information for LLC size + // + AsmCpuidEx (CPUID_FUNCTION_4, 0x3, &Cpuid04.RegEax, &Cpuid04.RegEbx, &Cpuid04.RegEcx, &Cpuid04.RegEdx); + // + // Determine Cache Size in Kilo Bytes + // This Cache Size in Bytes = (Associativity) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1) + // = (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1) + // + Associativity = (UINT16) (((Cpuid04.RegEbx >> 22) & CPU_CACHE_ASSOCIATIVITY_MASK) + 1); + CachePartitions = (UINT16) (((Cpuid04.RegEbx >> 12) & CPU_CACHE_PARTITION_MASK) + 1); + CacheLineSize = (UINT16) (((UINT16) Cpuid04.RegEbx & CPU_CACHE_LINE_SIZE_MASK) + 1); + CacheNumberofSets = (UINT16) (Cpuid04.RegEcx + 1); + mCpuCacheSize = (UINT16) ((Associativity * CachePartitions * CacheLineSize * CacheNumberofSets) / 1024); + /// + /// Get Maximum Non-Turbo bus ratio (HFM) from Platform Info MSR Bits[15:8] + /// + PlatformInfoMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO); + mMaxBusRatio = PlatformInfoMsr.Bytes.SecondByte; + /// + /// Get Maximum Efficiency bus ratio (LFM) from Platform Info MSR Bits[47:40] + /// + mMinBusRatio = PlatformInfoMsr.Bytes.SixthByte; + /// + /// Get Max Turbo Ratio from Turbo Ratio Limit MSR Bits [7:0] + /// + TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_RATIO_LIMIT); + mTurboBusRatio = (UINT16) (TempMsr.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_1C); + /// + /// Check if Turbo Ratio Limit is programmable + /// Platform Info MSR (0xCE) [28] + /// + mRatioLimitProgrammble = (UINT8) RShiftU64 ((PlatformInfoMsr.Qword & B_PLATFORM_INFO_RATIO_LIMIT), 28); + /// + /// Check if TDP Limit is programmable + /// Platform Info MSR (0xCE) [29] + /// + mTdpLimitProgrammble = (UINT8) RShiftU64 ((PlatformInfoMsr.Qword & B_PLATFORM_INFO_TDC_TDP_LIMIT), 29); + + /// + /// Get Processor TDP + /// Get Maximum Power from Turbo Power Limit MSR Bits[14:0] + /// and convert it to units specified by Package Power SKU + /// Unit MSR [3:0] + /// + TempMsr.Qword = EfiReadMsr (MSR_PACKAGE_POWER_SKU); + PackagePowerSKUUnitMsr.Qword = EfiReadMsr (MSR_PACKAGE_POWER_SKU_UNIT); + mProcessorPowerUnit = (PackagePowerSKUUnitMsr.Bytes.FirstByte & PACKAGE_POWER_UNIT_MASK); + if (mProcessorPowerUnit == 0) { + mProcessorPowerUnit = 1; + } else { + mProcessorPowerUnit = (UINT8) LShiftU64 (2, (mProcessorPowerUnit - 1)); + } + mPackageTdp = (TempMsr.Dwords.Low & PACKAGE_TDP_POWER_MASK); + mPackageTdpWatt = (UINT16) DivU64x32 (mPackageTdp , mProcessorPowerUnit); + mPackageMaxPower = (UINT16) (TempMsr.Dwords.High & PACKAGE_MAX_POWER_MASK); + mPackageMinPower = (UINT16) RShiftU64 ((TempMsr.Dwords.Low & PACKAGE_MIN_POWER_MASK), 16); + mCpuPolicyRevision = mCpuPlatformPolicy->Revision; + + /// + /// Set mCustomPowerUnit to user selected Power unit + /// + mCustomPowerUnit = 1; + if ((mCpuPlatformPolicy->Revision >= DXE_PLATFORM_CPU_POLICY_PROTOCOL_REVISION_6 ) + && (mCpuPmConfig->CustomPowerUnit == PowerUnit125MilliWatts)) { + mCustomPowerUnit = 8; ///< Unit is 125 milli watt + } + + /// + /// If specified, create a custom the FVID table. + /// (The settings populating the FVID table may not be correct for the + /// specific processor, and it is up to the user to specify settings + /// applicable to the processor being used.) + /// + ZeroMem (mFvidPointer, sizeof (mEmptyFvidTable)); + if (mCpuPmConfig->pCustomRatioTable->NumberOfEntries >= 2) { + CreateCustomFvidTable (mFvidPointer); + } + + /// + /// Initialize flags based on processor capablities + /// + SetPpmFlags (); + + /// + /// Determine current user configuration + /// + SetUserConfigurationPpmFlags (); + +// >>>> + // + // Locate the Global NVS Protocol. + // + Status = gBS->LocateProtocol (&gEfiGlobalNvsAreaProtocolGuid, + NULL, &GlobalNvsArea ); + DEBUG((EFI_D_ERROR, "Status=gBS->LocateProtocol (&gEfiGlobalNvsAreaProtocolGuid) ===> %r !!!\n", Status)); + + if(!EFI_ERROR(Status)) { + GlobalNvsArea->Area->PpmFlags = mPpmGlobalNvsAreaProtocol->Area->PpmFlags; + } +// <<<< + /// + /// Locate ACPI support protocol + /// + Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, (VOID **) &mAcpiSupport); + ASSERT_EFI_ERROR (Status); + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable); + ASSERT_EFI_ERROR (Status); + return; +} + +/** + Create a custom FVID table based on setup options. + Caller is responsible for providing a large enough table. + + @param[in] FvidPointer Table to update, must be initialized. +**/ +VOID +CreateCustomFvidTable ( + IN OUT FVID_TABLE *FvidPointer + ) +{ + UINT16 Index; + + /// + /// BWG Section 14.6.2 Determining Number of Operating Points + /// It is recommended that system BIOS limit the number of P states to 16 + /// + if (mCpuPmConfig->pCustomRatioTable->NumberOfEntries > FVID_MAX_STATES) { + DEBUG ( + (EFI_D_WARN, + "VidNumber(%d) is greater than maximum(%d) supported.", + mCpuPmConfig->pCustomRatioTable->NumberOfEntries, + FVID_MAX_STATES) + ); + mCpuPmConfig->pCustomRatioTable->NumberOfEntries = FVID_MAX_STATES; + } + /// + /// Fill in the table header + /// + FvidPointer[0].FvidHeader.Stepping = mCpuPmConfig->pCustomRatioTable->Cpuid; + FvidPointer[0].FvidHeader.MaxBusRatio = mCpuPmConfig->pCustomRatioTable->MaxRatio; + FvidPointer[0].FvidHeader.Gv3States = mCpuPmConfig->pCustomRatioTable->NumberOfEntries; + /// + /// Fill in the state data + /// + for (Index = 0; Index < mCpuPmConfig->pCustomRatioTable->NumberOfEntries; Index++) { + FvidPointer[Index + 1].FvidState.State = Index; + FvidPointer[Index + 1].FvidState.BusRatio = mCpuPmConfig->pCustomRatioTable->StateRatio[Index]; + } +} + +/** + Set the PPM flags specific to Haswell processors + + @retval EFI_SUCCESS PpmFlags updated with the features supported by the processor +**/ +VOID +SetPpmFlags ( + VOID + ) +{ + MSR_REGISTER CoreThreadCount; + MSR_REGISTER Ia32MiscEnable; + EFI_CPUID_REGISTER Cpuid01; + EFI_CPUID_REGISTER Cpuid05; + EFI_CPUID_REGISTER Cpuid06; + UINTN States; + BOOLEAN CpuidLimitingEnabled; + UINT32 PpmFlags; + + ZeroMem (&Cpuid01, sizeof (Cpuid01)); + ZeroMem (&Cpuid05, sizeof (Cpuid05)); + ZeroMem (&Cpuid06, sizeof (Cpuid06)); + PpmFlags = 0; + + /// + /// Check if the processor has multiple cores + /// + CoreThreadCount.Qword = AsmReadMsr64 (MSR_CORE_THREAD_COUNT); + if ((CoreThreadCount.Dwords.Low & B_THREAD_COUNT_MASK) > 1) { + PpmFlags |= PPM_CMP; + } + if (mCpuid01.RegEdx & B_CPUID_VERSION_INFO_EDX_TM1) { ///< Check TM capable and update the flag + PpmFlags |= PPM_TM; + } + /// + /// Check EIST capable. If EIST capable, also set the boot P-state to HFM flag. + /// + if (mCpuid01.RegEcx & B_CPUID_VERSION_INFO_ECX_EIST) { + PpmFlags |= (PPM_EIST); + DEBUG ((EFI_D_INFO, "GV3 capable\n")); + } + /// + /// Disable CPUID limiting (and save current setting) if enabled + /// and enable MONITOR/MWAIT support + /// + Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + CpuidLimitingEnabled = (BOOLEAN) (Ia32MiscEnable.Qword & B_MSR_IA32_MISC_ENABLE_CPUID_MAX); + if (CpuidLimitingEnabled) { + Ia32MiscEnable.Qword &= ~B_MSR_IA32_MISC_ENABLE_CPUID_MAX; + } + AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword); + /// + /// Read the CPUID values we care about. We cannot use the stored + /// values because they may have changes since we disabled limiting + /// and enabled MONITOR/MWAIT + /// + AsmCpuid (1, &Cpuid01.RegEax, &Cpuid01.RegEbx, &Cpuid01.RegEcx, &Cpuid01.RegEdx); + AsmCpuid (5, &Cpuid05.RegEax, &Cpuid05.RegEbx, &Cpuid05.RegEcx, &Cpuid05.RegEdx); + AsmCpuid (6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx); + /// + /// Determine if the MONITOR/MWAIT instructions are supported. + /// + if ((Cpuid01.RegEcx & B_CPUID_VERSION_INFO_ECX_MWAIT && Cpuid05.RegEcx & B_CPUID_MONITOR_MWAIT_ECX_EXTENSIONS)) { + PpmFlags |= PPM_MWAIT_EXT; + } + /// + /// Determine the C-State and Enhanced C-State support present. + /// Monitor/MWAIT parameters function describes the numbers supported. + /// + States = RShiftU64 (Cpuid05.RegEdx, 4) & 0xF; + if (States >= ENHANCED_CSTATE_SUPPORTED) { + PpmFlags |= PPM_C1 + PPM_C1E; + } else if (States == CSTATE_SUPPORTED) { + PpmFlags |= PPM_C1; + } + States = RShiftU64 (Cpuid05.RegEdx, 8) & 0xF; + if ((States >= CSTATE_SUPPORTED) && (PpmFlags & PPM_C1)) { + PpmFlags |= PPM_C3; + } + States = RShiftU64 (Cpuid05.RegEdx, 12) & 0xF; + if (States >= C6_C7_LONG_LATENCY_SUPPORTED) { // Both Long and Short Latency C6 supported + PpmFlags |= (PPM_C6 | C6_LONG_LATENCY_ENABLE); + } else if (States >= C6_C7_SHORT_LATENCY_SUPPORTED) { // Only Short Latency C6 supported. + PpmFlags |= PPM_C6; + } + + States = RShiftU64 (Cpuid05.RegEdx, 16) & 0xF; + switch (States) { + case C7s_LONG_LATENCY_SUPPORTED: + // + // C7 & C7s Long and Short supported + // + PpmFlags |= (PPM_C7S | C7s_LONG_LATENCY_ENABLE | PPM_C7 | C7_LONG_LATENCY_ENABLE); + break; + case C7s_SHORT_LATENCY_SUPPORTED: + // + // C7s Long Latency is not supported. + // + PpmFlags |= (PPM_C7S | PPM_C7 | C7_LONG_LATENCY_ENABLE); + break; + case C6_C7_LONG_LATENCY_SUPPORTED: + // + // C7 Long and Short supported + // + PpmFlags |= (PPM_C7 | C7_LONG_LATENCY_ENABLE); + break; + case C6_C7_SHORT_LATENCY_SUPPORTED: + // + // C7 Long Latency is not supported. + // + PpmFlags |= PPM_C7; + break; + } + + States = RShiftU64 (Cpuid05.RegEdx, 20) & 0xF; + if (States >= CSTATE_SUPPORTED) { + PpmFlags |= PPM_C8; + } + States = RShiftU64 (Cpuid05.RegEdx, 24) & 0xF; + if (States >= CSTATE_SUPPORTED) { + PpmFlags |= PPM_C9; + } + States = RShiftU64 (Cpuid05.RegEdx, 28) & 0xF; + if (States >= CSTATE_SUPPORTED) { + PpmFlags |= PPM_C10; + } + /// + /// Check TimedMwait is supported and update the flag + /// + if (AsmReadMsr64 (MSR_PLATFORM_INFO) & B_PLATFORM_INFO_TIMED_MWAIT_SUPPORTED) { + PpmFlags |= PPM_TIMED_MWAIT; + } + if (PpmFlags & (PPM_C8 |PPM_C9 | PPM_C10)) { + PpmFlags |= PPM_CD; + } + /// + /// Check if turbo mode is supported and update the flag + /// + Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + if (((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == 0) && + ((Ia32MiscEnable.Qword & B_MSR_IA32_MISC_DISABLE_TURBO) == 0) + ) { + /// + /// Turbo Mode is not available in this physical processor package. + /// BIOS should not attempt to enable Turbo Mode via IA32_MISC_ENABLE MSR. + /// BIOS should show Turbo Mode as Disabled and Not Configurable. + /// + } else if ((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == 0) { + /// + /// Turbo Mode is available but globally disabled for the all logical + /// processors in this processor package. + /// BIOS can enable Turbo Mode by IA32_MISC_ENABLE MSR 1A0h bit [38] = 0. + /// + PpmFlags |= PPM_TURBO; + } else if ((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == B_CPUID_POWER_MANAGEMENT_EAX_TURBO) { + /// + /// Turbo Mode is factory-configured as available and enabled for all logical processors in this processor package. + /// This case handles the cases where turbo mode is enabled before PPM gets chance to enable it + /// + PpmFlags |= PPM_TURBO; + } + /// + /// Restore the CPUID limit setting. + /// + if (CpuidLimitingEnabled) { + Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_CPUID_MAX; + AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword); + } + PpmFlags |= PPM_TSTATES; ///< Set the T-states flag + /// + /// Determine if Fine grained clock modulation contol is supported + /// + if (Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_FINE_GRAINED_CLOCK_MODULATION) { + PpmFlags |= PPM_TSTATE_FINE_GRAINED; + } + PpmFlags |= PPM_EEPST; ///< Energy Efficient P-state feature is supported + mPpmGlobalNvsAreaProtocol->Area->PpmFlags = PpmFlags; ///< Update the PPM NVS area PPM flags + + return; +} + +/** + Set the PPM flags based on current user configuration +**/ +VOID +SetUserConfigurationPpmFlags ( + VOID + ) +{ + UINT32 UserPpmFlag; + // + // In advance to clear following PPM flags which are related with policies that user can enabled/disabled. + // + UserPpmFlag = (UINT32)~(PPM_EIST | PPM_C1 | PPM_C1E | PPM_C3 | PPM_C6 | C6_LONG_LATENCY_ENABLE | + PPM_C7S | PPM_C7 | C7_LONG_LATENCY_ENABLE | C7s_LONG_LATENCY_ENABLE | PPM_CD | + PPM_C8 | PPM_C9 | PPM_C10 | PPM_TM | PPM_TURBO | PPM_TSTATES | PPM_TSTATE_FINE_GRAINED | + PPM_EEPST | PPM_TIMED_MWAIT); + /// + /// Configure flag based on user selections + /// + if (mCpuPmConfig->pFunctionEnables->Eist) { + UserPpmFlag |= PPM_EIST; + } + if (mCpuPmConfig->pFunctionEnables->Cx) { + UserPpmFlag |= PPM_C1; + if (mCpuPmConfig->pFunctionEnables->C1e) { + UserPpmFlag |= PPM_C1E; + } + if (mCpuPmConfig->pFunctionEnables->C3) { + UserPpmFlag |= PPM_C3; + } + if (mCpuPmConfig->pFunctionEnables->C6) { + UserPpmFlag |= PPM_C6; + } + if (mCpuPmConfig->pFunctionEnables->LongLatencyC6) { + UserPpmFlag |= C6_LONG_LATENCY_ENABLE; + } + switch (mCpuPmConfig->pFunctionEnables->DeepCState) { + case DeepC7S: + UserPpmFlag |= PPM_C7S; + case DeepC7: + UserPpmFlag |= PPM_C7; + break; + } + if (mCpuPmConfig->pFunctionEnables->LongLatencyC7) { + UserPpmFlag |= (C7_LONG_LATENCY_ENABLE | C7s_LONG_LATENCY_ENABLE); + } + if (mCpuPmConfig->pFunctionEnables->C8) { + UserPpmFlag |= PPM_C8; + } + if (mCpuPmConfig->pFunctionEnables->C9) { + UserPpmFlag |= PPM_C9; + } + if (mCpuPmConfig->pFunctionEnables->C10) { + UserPpmFlag |= PPM_C10; + } + if (UserPpmFlag & (PPM_C8 |PPM_C9 | PPM_C10)) { + UserPpmFlag |= PPM_CD; + } + } + if (mCpuPmConfig->ThermalFuncEnables->ThermalMonitor) { + UserPpmFlag |= PPM_TM; + } + if (mCpuPmConfig->pFunctionEnables->TurboMode) { + UserPpmFlag |= PPM_TURBO; + } + if (mCpuPmConfig->ThermalFuncEnables->TStates) { + UserPpmFlag |= (PPM_TSTATES | PPM_TSTATE_FINE_GRAINED); + } + if (mCpuPmConfig->pFunctionEnables->EnergyEfficientPState) { + UserPpmFlag |= PPM_EEPST; + } + if (mCpuPmConfig->pFunctionEnables->TimedMwait) { + UserPpmFlag |= PPM_TIMED_MWAIT; + } + /// + /// Modify PpmFlags based on user selections + /// + mPpmGlobalNvsAreaProtocol->Area->PpmFlags &= UserPpmFlag; +} + +/** + Initialize the processor power management based on hardware capabilities + and user configuration settings. + + @retval EFI_SUCCESS - on success + @retval Appropiate failure code on error +**/ +EFI_STATUS +InitializePpm ( + VOID + ) +{ + EFI_STATUS Status; + EFI_STATUS CtdpSupport; + + Status = EFI_SUCCESS; + CtdpSupport = EFI_UNSUPPORTED; + + /// + /// Initialize Config TDP + /// + CtdpSupport = InitializeConfigurableTdp (mCpuPmConfig); + + /// + /// Initialize P states + /// + InitializePStates(); + + /// + /// Initialize C State(IdleStates) + /// + InitializeCState(mCpuPmConfig); + + // + // Patch P state table (Fvid table) with ctdp settings. + // + CtdpPatchFvidTable (mFvidPointer); + + Status = InitializePpmAcpiTable (); + if (EFI_ERROR (Status)) { + return Status; + } + + /// + /// Initialize thermal features + /// + InitThermal (mCpuPmConfig); + + /// + /// Initialise Miscellaneous features + /// + InitMiscFeatures(CtdpSupport); + + /// + /// Complete with Ppmpost initialization + /// + PpmPostInit (); + + return Status; +} + + +/** + This is a debug function to print PPM Policy +**/ +VOID +DumpCpuPmConfig ( + VOID + ) +{ +#ifdef EFI_DEBUG + UINT32 Index; + DEBUG ((EFI_D_INFO, "\n\n------------------------ PowerMangement Policy dump Begin -----------------\n\n")); + DEBUG ((EFI_D_INFO, " S3RestoreMsrSwSmiNumber : %x\n", mCpuPmConfig->S3RestoreMsrSwSmiNumber)); + DEBUG ((EFI_D_INFO, "\n Ppm Lock Enables... \n")); + DEBUG ((EFI_D_INFO, " PmgCstCfgCtrlLock : %x\n", mCpuPmConfig->pPpmLockEnables->PmgCstCfgCtrlLock)); + DEBUG ((EFI_D_INFO, " ProcHotLock : %x\n", mCpuPmConfig->pPpmLockEnables->ProcHotLock)); + DEBUG ((EFI_D_INFO, "\n FunctionEnables... \n")); + DEBUG ((EFI_D_INFO, " Eist : %x\n", mCpuPmConfig->pFunctionEnables->Eist)); + DEBUG ((EFI_D_INFO, " Cx : %x\n", mCpuPmConfig->pFunctionEnables->Cx)); + DEBUG ((EFI_D_INFO, " C1e : %x\n", mCpuPmConfig->pFunctionEnables->C1e)); + DEBUG ((EFI_D_INFO, " C3 : %x\n", mCpuPmConfig->pFunctionEnables->C3)); + DEBUG ((EFI_D_INFO, " C6 : %x\n", mCpuPmConfig->pFunctionEnables->C6)); + DEBUG ((EFI_D_INFO, " C6 Long Latency: %x\n", mCpuPmConfig->pFunctionEnables->LongLatencyC6)); + DEBUG ((EFI_D_INFO, " DeepCState : %x\n", mCpuPmConfig->pFunctionEnables->DeepCState)); + DEBUG ((EFI_D_INFO, " C7 Long Latency : %x\n", mCpuPmConfig->pFunctionEnables->LongLatencyC7)); + DEBUG ((EFI_D_INFO, " C1Autodemotion : %x\n", mCpuPmConfig->pFunctionEnables->C1AutoDemotion)); + DEBUG ((EFI_D_INFO, " C3AutoDemotion : %x\n", mCpuPmConfig->pFunctionEnables->C3AutoDemotion)); + DEBUG ((EFI_D_INFO, " C1Undemotion : %x\n", mCpuPmConfig->pFunctionEnables->C1UnDemotion)); + DEBUG ((EFI_D_INFO, " C3UnDemotion : %x\n", mCpuPmConfig->pFunctionEnables->C3UnDemotion)); + DEBUG ((EFI_D_INFO, " PkgCstateUndemotion : %x\n", mCpuPmConfig->pFunctionEnables->PkgCStateUnDemotion)); + DEBUG ((EFI_D_INFO, " PkgCState Demotion : %x\n", mCpuPmConfig->pFunctionEnables->PkgCStateDemotion)); + DEBUG ((EFI_D_INFO, " CStatePreWake : %x\n", mCpuPmConfig->pFunctionEnables->CStatePreWake)); + DEBUG ((EFI_D_INFO, " TurboMode : %x\n", mCpuPmConfig->pFunctionEnables->TurboMode)); + DEBUG ((EFI_D_INFO, " PowerLimit2 : %x\n", mCpuPmConfig->pFunctionEnables->PowerLimit2)); + DEBUG ((EFI_D_INFO, " EnergyEfficientPState : %x\n", mCpuPmConfig->pFunctionEnables->EnergyEfficientPState)); + DEBUG ((EFI_D_INFO, " LakeTiny Support : %x\n", mCpuPmConfig->pFunctionEnables->LakeTiny)); + DEBUG ((EFI_D_INFO, " PkgCStateLimit : %x\n", mCpuPmConfig->PkgCStateLimit)); + DEBUG ((EFI_D_INFO, " TimedMwait : %x\n", mCpuPmConfig->pFunctionEnables->TimedMwait)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl0TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl0TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl1TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl1TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl2TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl2TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl3TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl3TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl4TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl4TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl5TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl5TimeUnit)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl0Irtl : %x\n", mCpuPmConfig->CstateLatencyControl0Irtl)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl1Irtl : %x\n", mCpuPmConfig->CstateLatencyControl1Irtl)); + DEBUG ((EFI_D_INFO, " CstateLatencyControl2Irtl : %x\n", mCpuPmConfig->CstateLatencyControl2Irtl)); + DEBUG ((EFI_D_INFO, " RfiFreqTunningOffsetIsNegative : %x\n", mCpuPmConfig->RfiFreqTunningOffsetIsNegative)); + DEBUG ((EFI_D_INFO, " RfiFreqTunningOffset : %x\n", mCpuPmConfig->RfiFreqTunningOffset)); + DEBUG ((EFI_D_INFO, "\n Turbo settings... \n")); + DEBUG ((EFI_D_INFO, " PowerLimit1 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit1)); + DEBUG ((EFI_D_INFO, " PowerLimit1Time : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit1Time)); + DEBUG ((EFI_D_INFO, " PowerLimit2 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit2)); + DEBUG ((EFI_D_INFO, " PowerLimit3 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3)); + DEBUG ((EFI_D_INFO, " PowerLimit3Time : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3Time)); + DEBUG ((EFI_D_INFO, " PowerLimit3DutyCycle : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3DutyCycle)); + DEBUG ((EFI_D_INFO, " PowerLimit3Lock : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3Lock)); + DEBUG ((EFI_D_INFO, " TurboPowerLimitLock : %x\n", mCpuPmConfig->pTurboSettings->TurboPowerLimitLock)); + DEBUG ((EFI_D_INFO, " ConfigTdpLevel : %x\n", mCpuPmConfig->pTurboSettings->ConfigTdpLevel)); + DEBUG ((EFI_D_INFO, " ConfigTdpLock : %x\n", mCpuPmConfig->pTurboSettings->ConfigTdpLock)); + DEBUG ((EFI_D_INFO, " ConfigTdpCustom : %x\n", mCpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom)); + if (mCpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) { + DEBUG ((EFI_D_INFO, " CustomTdpCount : %d\n", mCpuPmConfig->pCustomCtdpSettings->CustomTdpCount)); + DEBUG ((EFI_D_INFO, " CustomBootModeIndex : %d\n", mCpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex)); + for (Index = 0; Index < MAX_CUSTOM_CTDP_ENTRIES; Index++) { + DEBUG ( + (EFI_D_INFO, + " CustomConfigTdpTable[%d] CustomPowerLimit1 : 0x%x\n", + Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1) + ); + DEBUG ( + (EFI_D_INFO, + " CustomConfigTdpTable[%d] CustomPowerLimit2 : 0x%x\n", + Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2) + ); + DEBUG ( + (EFI_D_INFO, + " CustomConfigTdpTable[%d] CustomPowerLimit1Time : %d\n", + Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1Time) + ); + DEBUG ( + (EFI_D_INFO, + " CustomConfigTdpTable[%d] CustomTurboActivationRatio : %d\n", + Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio) + ); + DEBUG ( + (EFI_D_INFO, + " ConfigTdpTable[%d] CustomConfigTdpControl : %d\n", + Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomConfigTdpControl) + ); + } + } + DEBUG ((EFI_D_INFO, "\n CustomRatioTable... \n")); + DEBUG ((EFI_D_INFO, " VidNumber : %x\n", mCpuPmConfig->pCustomRatioTable->NumberOfEntries)); + DEBUG ((EFI_D_INFO, " VidCpuid : %x\n", mCpuPmConfig->pCustomRatioTable->Cpuid)); + DEBUG ((EFI_D_INFO, " VidMaxRatio : %x\n", mCpuPmConfig->pCustomRatioTable->MaxRatio)); + for (Index = 0; Index < MAX_CUSTOM_RATIO_TABLE_ENTRIES; Index++) { + DEBUG ((EFI_D_INFO, " StateRatio[%d] : %x\n", Index, mCpuPmConfig->pCustomRatioTable->StateRatio[Index])); + } + DEBUG ((EFI_D_INFO, "\n XeConfig... \n")); + DEBUG ((EFI_D_INFO, " Xe : %x\n", mCpuPmConfig->pFunctionEnables->Xe)); + for (Index = 0; Index < 4; Index++) { + DEBUG ((EFI_D_INFO, " RatioLimit[%d] : %x\n", Index, mCpuPmConfig->pRatioLimit[Index])); + } + DEBUG ((EFI_D_INFO, " BiProcHot : %x\n", mCpuPmConfig->ThermalFuncEnables->BiProcHot)); + DEBUG ((EFI_D_INFO, " DisableProcHotOut : %x\n", mCpuPmConfig->ThermalFuncEnables->DisableProcHotOut)); + DEBUG ((EFI_D_INFO, " DisableVRThermalAlert : %x\n", mCpuPmConfig->ThermalFuncEnables->DisableVRThermalAlert)); + DEBUG ((EFI_D_INFO, " ProcHotResponce : %x\n", mCpuPmConfig->ThermalFuncEnables->ProcHotResponce)); + DEBUG ((EFI_D_INFO, " TStates : %x\n", mCpuPmConfig->ThermalFuncEnables->TStates)); + DEBUG ((EFI_D_INFO, " AutoThermalReporting : %x\n", mCpuPmConfig->ThermalFuncEnables->AutoThermalReporting)); + DEBUG ((EFI_D_INFO, " ThermalMonitor : %x\n", mCpuPmConfig->ThermalFuncEnables->ThermalMonitor)); + DEBUG ((EFI_D_INFO, "\n\n------------------------ PowerMangement Policy dump End -------------------\n\n")); +#endif +} |