summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c')
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c840
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
+}