1774 lines
62 KiB
C
1774 lines
62 KiB
C
/** @file
|
|
This file contains power management configuration functions for processors.
|
|
|
|
<b>Acronyms:</b>
|
|
- PPM: Processor Power Management
|
|
- TM: Thermal Monitor
|
|
- IST: Intel(R) Speedstep technology
|
|
- HT: Hyper-Threading Technology
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2012 - 2021 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"
|
|
#include <Library/CpuCommonLib.h>
|
|
#include <Ppi/SiPolicy.h>
|
|
#include <Library/CpuInfoFruLib.h>
|
|
#include <Library/MsrFruLib.h>
|
|
|
|
#define CONFIG_TDP_LVL1_PKG_TDP_MASK (0x7FFF)
|
|
#define PACKAGE_POWER_LIMIT_PKG_CLMP_LIM_1_MASK (BIT16)
|
|
|
|
/**
|
|
Configurable TDP BIOS Initialization
|
|
|
|
@exception EFI_UNSUPPORTED Ctdp not Supported
|
|
@retval EFI_SUCCESS Ctdp Initiation done
|
|
**/
|
|
EFI_STATUS
|
|
InitializeConfigurableTdp (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
|
|
|
|
|
|
///
|
|
/// Intialize PPM Global NVS with custom CTDP level settings or CPU provided.
|
|
///
|
|
Status = InitConfigurableTdpSettings ();
|
|
if (Status != EFI_SUCCESS) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
///
|
|
/// In case of LFM == TDP Down Ratio/Tdp Nominal , consider TDP Down TAR as the new LFM to insert fake P state.
|
|
///
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
if (mMinBusRatio == mCtdpTar[Index] + 1) {
|
|
mMinBusRatio = mCtdpTar[Index];
|
|
DEBUG ((DEBUG_INFO, "PPM:: mMinBusRatio Modified for Ctdp %d\n", mMinBusRatio));
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Verify and fix Custom Power Limit values
|
|
|
|
@param[in] CustomPowerLimit Custom Power Limit value
|
|
@param[in] CustomPlUnit Custom Power Limit Unit
|
|
**/
|
|
UINT16
|
|
VerifyAndFixCustomPowerLimit (
|
|
IN UINT32 CustomPowerLimit,
|
|
IN UINT16 CustomPlUnit
|
|
)
|
|
{
|
|
UINT16 ConvertedPowerLimit;
|
|
UINT16 CpuConvertedPowerLimitMaxLimit;
|
|
|
|
ConvertedPowerLimit = (UINT16) ((CustomPowerLimit * mProcessorPowerUnit) / CustomPlUnit);
|
|
if (mPackageMaxPower == 0 && ConvertedPowerLimit >= mPackageMinPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [46:32] = 0 means there is no upper limit ( since this field is 15 bits, the max value is 2^15 - 1 )
|
|
///
|
|
CpuConvertedPowerLimitMaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
|
|
if (ConvertedPowerLimit > CpuConvertedPowerLimitMaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > CpuConvertedPowerLimit1MaxLimit, program Power Limit 1 to CpuConvertedPowerLimit1MaxLimit
|
|
///
|
|
ConvertedPowerLimit = CpuConvertedPowerLimitMaxLimit;
|
|
}
|
|
} else if (mPackageMinPower == 0 && ConvertedPowerLimit > 0 && ConvertedPowerLimit <= mPackageMaxPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [30:16] = 0 means there is no lower limit
|
|
///
|
|
ConvertedPowerLimit = (UINT16) ((CustomPowerLimit * mProcessorPowerUnit) / CustomPlUnit);
|
|
} else {
|
|
///
|
|
/// Power Limit 1 needs to be between mPackageMinPower and mPackageMaxPower
|
|
///
|
|
CpuConvertedPowerLimitMaxLimit = mPackageMaxPower;
|
|
if (ConvertedPowerLimit < mPackageMinPower) {
|
|
///
|
|
/// If new Power Limit 1 is < mPackageMinPower, program Power Limit 1 to mPackageMinPower
|
|
///
|
|
ConvertedPowerLimit = mPackageMinPower;
|
|
} else if (ConvertedPowerLimit > CpuConvertedPowerLimitMaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > mPackageMaxPower, program Power Limit 1 to mPackageMaxPower
|
|
///
|
|
ConvertedPowerLimit = CpuConvertedPowerLimitMaxLimit;
|
|
}
|
|
}
|
|
|
|
return ConvertedPowerLimit;
|
|
}
|
|
|
|
/**
|
|
Verify and fix Custom Ratio values
|
|
Custom Ratio should be between MaxTurboFrequency and LFM
|
|
|
|
@param[in] CustomRatio Custom Ratio value
|
|
**/
|
|
UINT8
|
|
VerifyAndFixCustomRatio (
|
|
IN UINT8 CustomRatio
|
|
)
|
|
{
|
|
if (CustomRatio > mTurboBusRatio) {
|
|
///
|
|
/// Use HFM as max value if Turbo is not supported
|
|
///
|
|
if (mTurboBusRatio == 0) {
|
|
CustomRatio = (UINT8) mMaxBusRatio;
|
|
} else {
|
|
CustomRatio = (UINT8) mTurboBusRatio;
|
|
}
|
|
} else if (CustomRatio < mMinBusRatio) {
|
|
///
|
|
/// Use LFM as min value
|
|
///
|
|
CustomRatio = (UINT8) mMinBusRatio;
|
|
}
|
|
|
|
return CustomRatio;
|
|
}
|
|
|
|
/**
|
|
Initalizes CTDP BIOS settings from silicon defaults and overrides custom cTDP settings if needed
|
|
|
|
@exception EFI_UNSUPPORTED Ctdp not supported
|
|
@retval EFI_SUCCESS Ctdp Settings Initialized successfully from MSRs
|
|
**/
|
|
EFI_STATUS
|
|
InitConfigurableTdpSettings (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_CONFIG_TDP_NOMINAL_REGISTER ConfigTdpNominalMsr;
|
|
MSR_CONFIG_TDP_LEVEL1_REGISTER ConfigTdpLevel1Msr;
|
|
MSR_CONFIG_TDP_LEVEL2_REGISTER ConfigTdpLevel2Msr;
|
|
UINTN NoOfOverrides;
|
|
PPM_OVERRIDE_TABLE *PpmCtdpOverrideTable;
|
|
|
|
UINTN Index;
|
|
UINTN PpmIndex;
|
|
UINT16 CpuConfigTdpNominalTdp;
|
|
UINT16 CpuConfigTdpLevel1Tdp;
|
|
UINT16 CpuConfigTdpLevel2Tdp;
|
|
UINT32 CpuConfigTdpNominalRatio;
|
|
UINT32 CpuConfigTdpLevel1Ratio;
|
|
UINT32 CpuConfigTdpLevel2Ratio;
|
|
UINT8 CpuConfigTdpLevels;
|
|
|
|
///
|
|
/// Get the number of configurable TDP Levels supported
|
|
///
|
|
CpuConfigTdpLevels = MsrGetConfigTdpLevels ();
|
|
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP Supported Levels=%d\n", CpuConfigTdpLevels));
|
|
///
|
|
/// Return if ConfigTDP Levels not supported
|
|
///
|
|
if (CpuConfigTdpLevels == 0) {
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP Levels not supported\n"));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
mCtdpLevelsSupported = CpuConfigTdpLevels + 1;
|
|
mConfigTdpBootModeIndex = (UINT8) gCpuConfigLibPreMemConfig->ConfigTdpLevel;
|
|
|
|
///
|
|
/// Get PKG_TDP for Config TDP Nominal
|
|
///
|
|
ConfigTdpNominalMsr.Uint64 = AsmReadMsr64 (MSR_CONFIG_TDP_NOMINAL);
|
|
CpuConfigTdpNominalRatio = ConfigTdpNominalMsr.Bits.TdpRatio;
|
|
CpuConfigTdpNominalTdp = mPackageTdp;
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP Nominal Ratio=%d Tdp=%d\n", CpuConfigTdpNominalRatio, CpuConfigTdpNominalTdp));
|
|
|
|
PpmCtdpOverrideTable = GetFruPowerLimits (&NoOfOverrides);
|
|
for (PpmIndex = 0; PpmIndex < NoOfOverrides; PpmIndex++, PpmCtdpOverrideTable++) {
|
|
if (PpmCtdpOverrideTable->CpuIdentifier == mCpuIdentifier) {
|
|
///
|
|
/// Set Level0 as Tdp Nominal
|
|
///
|
|
mCtdpPowerLimit1[0] = mPackageTdp;
|
|
mCtdpPowerLimit2[0] = (UINT16) ((PpmCtdpOverrideTable->CtdpNominalPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
if (IsMobileSku () || IsHaloSku ()) {
|
|
mCtdpPowerLimitWindow[0] = MB_POWER_LIMIT1_TIME_DEFAULT;
|
|
} else {
|
|
mCtdpPowerLimitWindow[0] = DT_POWER_LIMIT1_TIME_DEFAULT;
|
|
}
|
|
mCtdpTar[0] = (UINT8) (CpuConfigTdpNominalRatio - 1);
|
|
mCtdpCtc[0] = 0;
|
|
|
|
///
|
|
/// Get PKG_TDP and Ratio for Config TDP Level1
|
|
///
|
|
ConfigTdpLevel1Msr.Uint64 = AsmReadMsr64 (MSR_CONFIG_TDP_LEVEL1);
|
|
CpuConfigTdpLevel1Ratio = ConfigTdpLevel1Msr.Bits.TdpRatio;
|
|
CpuConfigTdpLevel1Tdp = (UINT16) (ConfigTdpLevel1Msr.Bits.PkgTdp);
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP Level1 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel1Ratio, CpuConfigTdpLevel1Tdp));
|
|
///
|
|
/// Set Level 1
|
|
///
|
|
Index = 1;
|
|
if (CpuConfigTdpLevel1Ratio != 0) {
|
|
mCtdpPowerLimit1[Index] = CpuConfigTdpLevel1Tdp;
|
|
mCtdpPowerLimit2[Index] = (UINT16) ((PpmCtdpOverrideTable->CtdpDownPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
mCtdpPowerLimitWindow[Index] = mCtdpPowerLimitWindow[0];
|
|
mCtdpTar[Index] = (UINT8) (CpuConfigTdpLevel1Ratio - 1);
|
|
mCtdpCtc[Index] = 1;
|
|
Index++;
|
|
}
|
|
///
|
|
/// If two levels are supported or Level1 was not valid
|
|
/// then read Level2 registers
|
|
///
|
|
if (CpuConfigTdpLevels == 2 || CpuConfigTdpLevel1Ratio == 0) {
|
|
///
|
|
/// Get PKG_TDP and Ratio for Config TDP Level2
|
|
///
|
|
ConfigTdpLevel2Msr.Uint64 = AsmReadMsr64 (MSR_CONFIG_TDP_LEVEL2);
|
|
CpuConfigTdpLevel2Ratio = ConfigTdpLevel2Msr.Bits.TdpRatio;
|
|
CpuConfigTdpLevel2Tdp = (UINT16) (ConfigTdpLevel2Msr.Bits.PkgTdp);
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP Level2 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel2Ratio, CpuConfigTdpLevel2Tdp));
|
|
///
|
|
/// Set Level2
|
|
///
|
|
mCtdpPowerLimit1[Index] = CpuConfigTdpLevel2Tdp;
|
|
mCtdpPowerLimit2[Index] = (UINT16) ((PpmCtdpOverrideTable->CtdpUpPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
mCtdpPowerLimitWindow[Index] = mCtdpPowerLimitWindow[0];
|
|
mCtdpTar[Index] = (UINT8) (CpuConfigTdpLevel2Ratio - 1);
|
|
mCtdpCtc[Index] = 2;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Override any custom ConfigTdp information if applicable. This will only update if a custom
|
|
/// setting change is detected, otherwise the CPU based default cTDP settings will be applied.
|
|
///
|
|
for (Index = 0; Index < MAX_CUSTOM_CTDP_ENTRIES; Index++) {
|
|
///
|
|
/// Verify and fix Custom configured CTDP Levels PL1
|
|
///
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1 != 0) {
|
|
mCtdpPowerLimit1[Index] = VerifyAndFixCustomPowerLimit (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1, mCustomPowerUnit);
|
|
}
|
|
|
|
///
|
|
/// Ctdp PL1 Time Window
|
|
///
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1Time != 0) {
|
|
mCtdpPowerLimitWindow[Index] = (UINT8) gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1Time;
|
|
}
|
|
|
|
///
|
|
/// Verify and fix Custom configured CTDP Levels PL2
|
|
///
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2 != 0) {
|
|
mCtdpPowerLimit2[Index] = VerifyAndFixCustomPowerLimit (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2,mCustomPowerUnit);
|
|
}
|
|
|
|
///
|
|
/// cTDP Turbo Activation Ratio
|
|
///
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomTurboActivationRatio != 0) {
|
|
mCtdpTar[Index] = VerifyAndFixCustomRatio ((UINT8) gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomTurboActivationRatio + 1) - 1;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Patch Fvid Table with Ctdp Tar ratio and Tar-1 Ratio
|
|
|
|
@param[in] FvidPointer Pointer to Fvid Table
|
|
**/
|
|
VOID
|
|
CtdpPatchFvidTable (
|
|
IN OUT FVID_TABLE *FvidPointer
|
|
)
|
|
{
|
|
UINTN PssIndex;
|
|
UINTN PssIndexP1;
|
|
UINTN Index;
|
|
UINTN TempRatio;
|
|
UINT16 Turbo;
|
|
|
|
///
|
|
/// Check and patch Fvid table for TAR ratios
|
|
///
|
|
DEBUG ((DEBUG_INFO, "\nCtdpPatchFvidTable - Start \n"));
|
|
|
|
Turbo = ((mPpmFlags & PPM_TURBO) ? 1 : 0);
|
|
|
|
///
|
|
/// PSS Index for P1 (HFM) depends on Turbo Enabled/Disabled
|
|
/// - Turbo Enabled:
|
|
/// -- PSS Index for P1 = 2
|
|
///- Turbo Disabled:
|
|
/// -- PSS Index for P1 = 1
|
|
///
|
|
if (Turbo) {
|
|
PssIndexP1 = 2;
|
|
} else {
|
|
PssIndexP1 = 1;
|
|
}
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
TempRatio = mCtdpTar[Index];
|
|
///
|
|
/// Fvid Table's first entry is Header only, then state ratios start from the second entry.
|
|
/// Size of table is EistStates plus one, but need to stop iterating one entry early, due to use of PssIndex + 1.
|
|
///
|
|
for (PssIndex = PssIndexP1; PssIndex < FvidPointer[0].FvidHeader.EistStates; PssIndex++) {
|
|
if (FvidPointer[PssIndex + 1].FvidState.BusRatio < TempRatio) {
|
|
if (FvidPointer[PssIndex].FvidState.BusRatio != TempRatio) {
|
|
///
|
|
/// If TAR not Found, Replace Turbo Activation Ratio at PssIndex
|
|
///
|
|
CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio, FALSE);
|
|
DEBUG ((DEBUG_INFO, " TAR Ratio Replace at Index %d with Ratio:%d \n", PssIndex, TempRatio));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Check and patch Fvid table for CTDP ratios.
|
|
/// This is done separately to make sure Ctdp ratios are not override by TAR ratios
|
|
/// when CTDP ratios are adjacent.
|
|
///
|
|
|
|
///
|
|
/// PSS Index for P1 (HFM) depends on Turbo Enabled/Disabled
|
|
/// - Turbo Enabled:
|
|
/// -- PSS Index for P1 = 2
|
|
///- Turbo Disabled:
|
|
/// -- PSS Index for P1 = 1
|
|
///
|
|
if (Turbo) {
|
|
PssIndexP1 = 2;
|
|
} else {
|
|
PssIndexP1 = 1;
|
|
}
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
TempRatio = mCtdpTar[Index] + 1;
|
|
///
|
|
/// Fvid Table's first entry is Header only, then state ratios start from the second entry.
|
|
/// Size of table is EistStates plus one, but need to stop iterating one entry early, due to use of PssIndex + 1.
|
|
///
|
|
for (PssIndex = PssIndexP1; PssIndex < FvidPointer[0].FvidHeader.EistStates; PssIndex++) {
|
|
if (FvidPointer[PssIndex + 1].FvidState.BusRatio == TempRatio) {
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex + 1].FvidState.State;
|
|
}
|
|
|
|
if (FvidPointer[PssIndex + 1].FvidState.BusRatio < TempRatio) {
|
|
if (FvidPointer[PssIndex].FvidState.BusRatio == TempRatio) {
|
|
///
|
|
/// Found Turbo Activation Ratio + 1 at PssIndex
|
|
///
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex].FvidState.State;
|
|
break;
|
|
} else {
|
|
///
|
|
/// If TAR+1 not Found, Replace Turbo Activation Ratio + 1 at PssIndex
|
|
///
|
|
CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio, FALSE);
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex].FvidState.State;
|
|
DEBUG ((DEBUG_INFO, " CTDP Ratio Replace Index at %d with Ratio:%d \n", PssIndex, TempRatio));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DEBUG ((DEBUG_INFO, "CtdpPatchFvidTable - End \n\n"));
|
|
}
|
|
|
|
/**
|
|
Patch Fvid Table with Ctdp Tar ratio and Tar-1 Ratio for Legacy OS
|
|
|
|
@param[in] FvidPointer Pointer to Fvid Table
|
|
**/
|
|
VOID
|
|
CtdpPatchFvidTableforLimit16Pstate (
|
|
IN OUT FVID_TABLE *FvidPointer
|
|
)
|
|
{
|
|
UINTN PssIndex;
|
|
UINTN PssIndexP1;
|
|
UINTN Index;
|
|
UINTN TempRatio;
|
|
UINT16 Turbo;
|
|
|
|
///
|
|
/// Check and patch Fvid table for TAR ratios
|
|
///
|
|
DEBUG ((DEBUG_INFO, "CtdpPatchFvidTableforLimit16Pstate - Start \n"));
|
|
|
|
Turbo = ((mPpmFlags & PPM_TURBO) ? 1 : 0);
|
|
///
|
|
/// PSS Index for P1 (HFM) depends on Turbo Enabled/Disabled
|
|
/// - Turbo Enabled:
|
|
/// -- PSS Index for P1 = 2
|
|
///- Turbo Disabled:
|
|
/// -- PSS Index for P1 = 1
|
|
///
|
|
if (Turbo) {
|
|
PssIndexP1 = 2;
|
|
} else {
|
|
PssIndexP1 = 1;
|
|
}
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
TempRatio = mCtdpTar[Index];
|
|
///
|
|
/// Fvid Table's first entry is Header only, then state ratios start from the second entry.
|
|
/// Size of table is EistStates plus one, but need to stop iterating one entry early, due to use of PssIndex + 1.
|
|
///
|
|
for (PssIndex = PssIndexP1; PssIndex < LPSS_FVID_MAX_STATES; PssIndex++) {
|
|
if (FvidPointer[PssIndex + 1].FvidState.Limit16BusRatio < TempRatio) {
|
|
if (FvidPointer[PssIndex].FvidState.Limit16BusRatio != TempRatio) {
|
|
///
|
|
/// If TAR not Found, Replace Turbo Activation Ratio at PssIndex
|
|
///
|
|
CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio, TRUE);
|
|
DEBUG ((DEBUG_INFO, " TAR Ratio Replace Index at %d with Ratio:%d \n", PssIndex, TempRatio));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Check and patch Fvid table for CTDP ratios.
|
|
/// This is done separately to make sure Ctdp ratios are not override by TAR ratios
|
|
/// when CTDP ratios are adjacent.
|
|
///
|
|
|
|
///
|
|
/// PSS Index for P1 (HFM) depends on Turbo Enabled/Disabled
|
|
/// - Turbo Enabled:
|
|
/// -- PSS Index for P1 = 2
|
|
///- Turbo Disabled:
|
|
/// -- PSS Index for P1 = 1
|
|
///
|
|
if (Turbo) {
|
|
PssIndexP1 = 2;
|
|
} else {
|
|
PssIndexP1 = 1;
|
|
}
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
TempRatio = mCtdpTar[Index] + 1;
|
|
///
|
|
/// Fvid Table's first entry is Header only, then state ratios start from the second entry.
|
|
/// Size of table is EistStates plus one, but need to stop iterating one entry early, due to use of PssIndex + 1.
|
|
///
|
|
for (PssIndex = PssIndexP1; PssIndex < LPSS_FVID_MAX_STATES; PssIndex++) {
|
|
if (FvidPointer[PssIndex + 1].FvidState.Limit16BusRatio == TempRatio) {
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex + 1].FvidState.Limit16State;
|
|
}
|
|
|
|
if (FvidPointer[PssIndex + 1].FvidState.Limit16BusRatio < TempRatio) {
|
|
if (FvidPointer[PssIndex].FvidState.Limit16BusRatio == TempRatio) {
|
|
///
|
|
/// Found Turbo Activation Ratio + 1 at PssIndex
|
|
///
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex].FvidState.Limit16State;
|
|
break;
|
|
} else {
|
|
///
|
|
/// If TAR+1 not Found, Replace Turbo Activation Ratio + 1 at PssIndex
|
|
///
|
|
CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio, TRUE);
|
|
mCtdpPpc[Index] = (UINT8) FvidPointer[PssIndex].FvidState.Limit16State;
|
|
DEBUG ((DEBUG_INFO, " CTDP Ratio Replace Index at %d with Ratio:%d \n", PssIndex, TempRatio));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DEBUG ((DEBUG_INFO, "CtdpPatchFvidTableforLimit16Pstate - End \n\n"));
|
|
}
|
|
|
|
/**
|
|
Replace P state with given ratio
|
|
|
|
@param[in out] FvidPointer Pointer to Fvid Table
|
|
@param[in] PssIndex FVID table index of P state to be replaced
|
|
@param[in] Ratio Target Ratio to put in
|
|
@param[in] Limit16Pstate FVID table for LPSS
|
|
**/
|
|
VOID
|
|
CtdpReplaceFvidRatio (
|
|
IN OUT FVID_TABLE *FvidPointer,
|
|
UINTN PssIndex,
|
|
UINTN Ratio,
|
|
BOOLEAN Limit16Pstate
|
|
)
|
|
{
|
|
UINT64 wPower1;
|
|
UINT64 wPower2;
|
|
|
|
if (Limit16Pstate) {
|
|
///
|
|
/// Replace new Ratio
|
|
///
|
|
FvidPointer[PssIndex].FvidState.Limit16BusRatio = (UINT16) Ratio;
|
|
|
|
///
|
|
/// Calculate relative Power (Limit16 States)
|
|
///
|
|
wPower1 = (mMaxBusRatio - FvidPointer[PssIndex].FvidState.Limit16BusRatio) * 625;
|
|
wPower1 = (110000 - wPower1);
|
|
wPower1 = DivU64x32 (wPower1, 11);
|
|
wPower1 = MultU64x64 (wPower1, wPower1);
|
|
//
|
|
// Power is calculated in milliwatts
|
|
//
|
|
wPower2 = (((FvidPointer[PssIndex].FvidState.Limit16BusRatio * 100) / mMaxBusRatio));
|
|
wPower2 = DivU64x32 (MultU64x32 (MultU64x64 (wPower2, wPower1), mPackageTdpWatt), 10000000);
|
|
FvidPointer[PssIndex].FvidState.Limit16Power = (UINT32) wPower2;
|
|
|
|
} else {
|
|
///
|
|
/// Replace new Ratio
|
|
///
|
|
FvidPointer[PssIndex].FvidState.BusRatio = (UINT16) Ratio;
|
|
|
|
///
|
|
/// Calculate relative Power
|
|
///
|
|
wPower1 = (mMaxBusRatio - FvidPointer[PssIndex].FvidState.BusRatio) * 625;
|
|
wPower1 = (110000 - wPower1);
|
|
wPower1 = DivU64x32 (wPower1, 11);
|
|
wPower1 = MultU64x64 (wPower1, wPower1);
|
|
//
|
|
// Power is calculated in milliwatts
|
|
//
|
|
wPower2 = (((FvidPointer[PssIndex].FvidState.BusRatio * 100) / mMaxBusRatio));
|
|
wPower2 = DivU64x32 (MultU64x32 (MultU64x64 (wPower2, wPower1), mPackageTdpWatt), 10000000);
|
|
FvidPointer[PssIndex].FvidState.Power = (UINT32) wPower2;
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check if Dual Tau boost is enabled.
|
|
|
|
@retval TRUE Dual Tau boost is enabled.
|
|
FALSE Dual Tau boost is disabled.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsDualTauEnable (
|
|
VOID
|
|
)
|
|
{
|
|
return ((GetCpuSku () == EnumCpuTrad) && gCpuPowerMgmtBasicConfig->DualTauBoost);
|
|
}
|
|
|
|
/**
|
|
Get power limit settings for dual tau boost
|
|
|
|
@param[out] MsrPl1 The override MSR PL1 value
|
|
@param[out] MsrPl2 The override MSR PL2 value
|
|
@param[out] MsrTau The override MSR tau value
|
|
@param[out] MmioPl1 The override MMIO PL1 value
|
|
@param[out] MmioPl2 The override MMIO PL2 value
|
|
@param[out] MmioTau The override MMIO tau value
|
|
|
|
@retval TRUE The override values are provided.
|
|
FALSE The override values are not provided.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
DualTauGetPowerLimit (
|
|
OUT UINT32 *MsrPl1,
|
|
OUT UINT32 *MsrPl2,
|
|
OUT UINT32 *MsrTau,
|
|
OUT UINT32 *MmioPl1,
|
|
OUT UINT32 *MmioPl2,
|
|
OUT UINT32 *MmioTau
|
|
)
|
|
{
|
|
switch (mPackageTdpWatt) {
|
|
//
|
|
// For 35W TDP
|
|
//
|
|
case 35:
|
|
if (MsrPl1 != NULL) *MsrPl1 = 35;
|
|
if (MsrPl2 != NULL) *MsrPl2 = 70;
|
|
if (MsrTau != NULL) *MsrTau = 224;
|
|
if (MmioPl1 != NULL) *MmioPl1 = 45;
|
|
if (MmioPl2 != NULL) *MmioPl2 = 70;
|
|
if (MmioTau != NULL) *MmioTau = 28;
|
|
return TRUE;
|
|
//
|
|
// For 65W TDP
|
|
//
|
|
case 65:
|
|
if (MsrPl1 != NULL) *MsrPl1 = 65;
|
|
if (MsrPl2 != NULL) *MsrPl2 = 129;
|
|
if (MsrTau != NULL) *MsrTau = 224;
|
|
if (MmioPl1 != NULL) *MmioPl1 = 85;
|
|
if (MmioPl2 != NULL) *MmioPl2 = 129;
|
|
if (MmioTau != NULL) *MmioTau = 28;
|
|
return TRUE;
|
|
//
|
|
// For 125W TDP
|
|
//
|
|
case 125:
|
|
if (MsrPl1 != NULL) *MsrPl1 = 125;
|
|
if (MsrPl2 != NULL) *MsrPl2 = 250;
|
|
if (MsrTau != NULL) *MsrTau = 224;
|
|
if (MmioPl1 != NULL) *MmioPl1 = 165;
|
|
if (MmioPl2 != NULL) *MmioPl2 = 250;
|
|
if (MmioTau != NULL) *MmioTau = 28;
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configure Dual Tau boost if it's enabled.
|
|
|
|
@param[in] CtdpSupported The CPU part whether supports Ctdp feature.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
ConfigureDualTauBoostOverride (
|
|
IN BOOLEAN CtdpSupported
|
|
)
|
|
{
|
|
BOOLEAN DualTauPowerLimitValueProvided;
|
|
UINT32 DualTauMsrPl1;
|
|
UINT32 DualTauMsrPl2;
|
|
UINT32 DualTauMsrTau;
|
|
UINT32 DualTauMmioPl1;
|
|
UINT32 DualTauMmioPl2;
|
|
UINT32 DualTauMmioTau;
|
|
UINT32 MchBar;
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMsr;
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMmio;
|
|
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride Start\n"));
|
|
//
|
|
// Override power limit for Dual Tau Boost
|
|
//
|
|
DualTauPowerLimitValueProvided = DualTauGetPowerLimit (
|
|
&DualTauMsrPl1,
|
|
&DualTauMsrPl2,
|
|
&DualTauMsrTau,
|
|
&DualTauMmioPl1,
|
|
&DualTauMmioPl2,
|
|
&DualTauMmioTau
|
|
);
|
|
if (DualTauPowerLimitValueProvided) {
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride original MSR 610 = %016lx\n", PackageRaplLimitMsr.Uint64));
|
|
//
|
|
// Override MSR PL1
|
|
//
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = DualTauMsrPl1 * mProcessorPowerUnit;
|
|
//
|
|
// Override MSR Tau
|
|
//
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1Time = GetConvertedTime (DualTauMsrTau, SecondsTimeWindowConvert);
|
|
|
|
if (CtdpSupported) {
|
|
//
|
|
// Override MSR PL2
|
|
//
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = DualTauMsrPl2 * mProcessorPowerUnit;
|
|
}
|
|
AsmWriteMsr64 (MSR_PACKAGE_RAPL_LIMIT, PackageRaplLimitMsr.Uint64);
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride modified MSR 610 = %016lx\n", PackageRaplLimitMsr.Uint64));
|
|
|
|
MchBar = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MCHBAR)) & ~BIT0;
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride original 59A0 = %x\n", MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT)));
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride original 59A4 = %x\n", MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT_HIGH)));
|
|
|
|
//
|
|
// Reuse the MSR_PACKAGE_RAPL_LIMIT_REGISTER structure for MMIO register since they are identical.
|
|
//
|
|
PackageRaplLimitMmio.Uint64 = LShiftU64 (MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT_HIGH), 32) + MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT);
|
|
//
|
|
// Override MMIO PL1
|
|
//
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim1 = DualTauMmioPl1 * mProcessorPowerUnit;
|
|
//
|
|
// Override MMIO Tau
|
|
//
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim1Time = GetConvertedTime (DualTauMmioTau, SecondsTimeWindowConvert);
|
|
//
|
|
// Program MMIO PowerLimit enable bit for PL1_EN
|
|
//
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim1En = 1;
|
|
MmioWrite32 (MchBar + MMIO_TURBO_POWER_LIMIT, (UINT32) PackageRaplLimitMmio.Uint64);
|
|
|
|
if (CtdpSupported) {
|
|
//
|
|
// Override MMIO PL2
|
|
//
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim2 = DualTauMmioPl2 * mProcessorPowerUnit;
|
|
} else {
|
|
//
|
|
// non-cTDP MMIO PL2 = MSR PL2
|
|
//
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim2 = PackageRaplLimitMsr.Bits.PkgPwrLim2;
|
|
}
|
|
PackageRaplLimitMmio.Bits.PkgPwrLim2En = 1;
|
|
MmioWrite32 (MchBar + MMIO_TURBO_POWER_LIMIT_HIGH, (UINT32) RShiftU64 (PackageRaplLimitMmio.Uint64, 32));
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride modified 59A0 = %x\n", MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT)));
|
|
DEBUG ((DEBUG_INFO, "ConfigureDualTauBoostOverride modified 59A4 = %x\n", MmioRead32 (MchBar + MMIO_TURBO_POWER_LIMIT_HIGH)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configures following fields of MSR 0x610 based on user configuration:
|
|
Configures Long duration Turbo Mode (power limit 1) power level and time window
|
|
Configures Short duration turbo mode (power limit 2)
|
|
**/
|
|
VOID
|
|
ConfigurePowerLimitsNonConfigTdpSkus (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMsr;
|
|
UINT32 PowerLimit1Time;
|
|
UINT16 ConvertedPowerLimit1;
|
|
UINT8 ConvertedPowerLimit1Time;
|
|
UINT16 ConvertedShortDurationPowerLimit;
|
|
UINT16 CpuConvertedPowerLimit1MaxLimit;
|
|
UINT16 CpuConvertedPowerLimit2MaxLimit;
|
|
UINT16 Multiplier;
|
|
UINTN MchBar;
|
|
PPM_OVERRIDE_TABLE *PpmOverrideTable;
|
|
UINTN NoOfOverrides;
|
|
UINTN Index;
|
|
|
|
///
|
|
/// Override table parameters
|
|
///
|
|
PpmOverrideTable = GetFruPowerLimits (&NoOfOverrides);
|
|
PowerLimit1Time = gCpuPowerMgmtBasicConfig->PowerLimit1Time;
|
|
CpuConvertedPowerLimit1MaxLimit = 0;
|
|
CpuConvertedPowerLimit2MaxLimit = 0;
|
|
ConvertedPowerLimit1Time = 0;
|
|
///
|
|
/// By default, for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP
|
|
///
|
|
Multiplier = 125;
|
|
///
|
|
/// Check if TDP limits are programmable
|
|
/// - Platform Info MSR (0xCE) [29]
|
|
///
|
|
if (mTdpLimitProgrammable) {
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
///
|
|
/// Initialize the Power Limit 1 and Power Limit 1 enable bit
|
|
/// - Power Limit 1: Turbo Power Limit MSR [14:0]
|
|
/// - Power Limit 1 Enable: Turbo Power Limit MSR [15]
|
|
///
|
|
///
|
|
/// By default, program Power Limit 1 to Package TDP limit
|
|
///
|
|
ConvertedPowerLimit1 = mPackageTdp;
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit1 != AUTO) {
|
|
///
|
|
/// gCpuPowerMgmtBasicConfig->PowerLimit1 is in mW or watts. We need to convert it to
|
|
/// CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].
|
|
/// Since we are converting from Watts to CPU power units, multiply by
|
|
/// PACKAGE_POWER_SKU_UNIT_MSR[3:0].
|
|
/// Refer to BWG 14.13.7 for Power Limit 1 limits.
|
|
///
|
|
ConvertedPowerLimit1 = (UINT16) ((gCpuPowerMgmtBasicConfig->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
if (mPackageMaxPower == 0 && ConvertedPowerLimit1 >= mPackageMinPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [46:32] = 0 means there is no upper limit ( since this field is 15 bits, the max value is 2^15 - 1 )
|
|
///
|
|
CpuConvertedPowerLimit1MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
|
|
if (ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > CpuConvertedPowerLimit1MaxLimit, program Power Limit 1 to CpuConvertedPowerLimit1MaxLimit
|
|
///
|
|
ConvertedPowerLimit1 = CpuConvertedPowerLimit1MaxLimit;
|
|
}
|
|
} else if (mPackageMinPower == 0 && ConvertedPowerLimit1 > 0 && ConvertedPowerLimit1 <= mPackageMaxPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [30:16] = 0 means there is no lower limit
|
|
///
|
|
ConvertedPowerLimit1 = (UINT16) ((gCpuPowerMgmtBasicConfig->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
|
|
} else {
|
|
///
|
|
/// Power Limit 1 needs to be between mPackageMinPower and mPackageMaxPower
|
|
///
|
|
CpuConvertedPowerLimit1MaxLimit = mPackageMaxPower;
|
|
|
|
if (ConvertedPowerLimit1 < mPackageMinPower) {
|
|
///
|
|
/// If new Power Limit 1 is < mPackageMinPower, program Power Limit 1 to mPackageMinPower
|
|
///
|
|
ConvertedPowerLimit1 = mPackageMinPower;
|
|
} else if (ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > mPackageMaxPower, program Power Limit 1 to mPackageMaxPower
|
|
///
|
|
ConvertedPowerLimit1 = CpuConvertedPowerLimit1MaxLimit;
|
|
}
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Power Limit 1 = AUTO\n"));
|
|
for (Index = 0; Index < NoOfOverrides; Index++, PpmOverrideTable++) {
|
|
if ( (PpmOverrideTable->CpuIdentifier == mCpuIdentifier) && (PpmOverrideTable->MsrPowerLimit1 != 0) ) {
|
|
ConvertedPowerLimit1 = (UINT16) (PpmOverrideTable->MsrPowerLimit1 / 100) * 8;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = (UINT32) (ConvertedPowerLimit1);
|
|
///
|
|
/// Force Power Limit 1 override to be enabled
|
|
///
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1En = 1;
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"New Power Limit 1 %d watt (%d in CPU power unit)\n",
|
|
gCpuPowerMgmtBasicConfig->PowerLimit1,
|
|
ConvertedPowerLimit1)
|
|
);
|
|
|
|
///
|
|
/// Program Power Limit 1 (Long Duration Turbo) Time Window
|
|
/// If PowerLimit1Time is AUTO OR If PowerLimit1Time is > MAX_POWER_LIMIT_1_TIME_IN_SECONDS
|
|
/// program default values
|
|
///
|
|
if ((gCpuPowerMgmtBasicConfig->PowerLimit1Time == AUTO) ||
|
|
(gCpuPowerMgmtBasicConfig->PowerLimit1Time > MAX_POWER_LIMIT_1_TIME_IN_SECONDS)
|
|
) {
|
|
if (IsMobileSku () || IsHaloSku ()) {
|
|
///
|
|
/// For Mobile and Halo, default value is 28 seconds.
|
|
///
|
|
PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT;
|
|
if (mPackageTdpWatt == 45) {
|
|
///
|
|
/// For 45W SKU, Tau is 56 seconds.
|
|
///
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
}
|
|
} else {
|
|
///
|
|
/// For Desktop, default value is 28 seconds. For 125 Watt it is 56 seconds.
|
|
///
|
|
if (mPackageTdpWatt >= 125) {
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
} else {
|
|
PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT;
|
|
}
|
|
if (IsSbgaSkuSupported ()) {
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
}
|
|
}
|
|
}
|
|
ConvertedPowerLimit1Time = GetConvertedTime (PowerLimit1Time, SecondsTimeWindowConvert);
|
|
///
|
|
/// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17]
|
|
///
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1Time = ConvertedPowerLimit1Time;
|
|
///
|
|
/// Initialize Short Duration Power limit and enable bit
|
|
/// Short duration Power Limit: Turbo Power Limit MSR (0x450h) [46:32]
|
|
/// Short duration Power Limit Enable:Turbo Power Limit MSR (0x450h) [47]
|
|
///
|
|
/// gCpuPowerMgmtBasicConfig->PowerLimit2Power value is in mW or watts. We need to convert it to
|
|
/// CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].
|
|
/// Since we are converting from Watts to CPU power units, multiply by
|
|
/// PACKAGE_POWER_SKU_UNIT_MSR[3:0]
|
|
///
|
|
ConvertedShortDurationPowerLimit = (UINT16) ((gCpuPowerMgmtBasicConfig->PowerLimit2Power * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = 0;
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2En = 0;
|
|
///
|
|
/// If PowerLimit2 is AUTO OR if PowerLimit2 is > mPackageMaxPower OR if PowerLimit2 < mPackageMinPower
|
|
/// program defaul values.
|
|
///
|
|
CpuConvertedPowerLimit2MaxLimit = mPackageMaxPower;
|
|
if (CpuConvertedPowerLimit2MaxLimit == 0) {
|
|
CpuConvertedPowerLimit2MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
|
|
}
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit2Power == AUTO) {
|
|
ConvertedShortDurationPowerLimit = EFI_IDIV_ROUND ((Multiplier * mPackageTdp), 100);
|
|
///
|
|
/// If Power Limit 2 is set to AUTO, then program PL2 defaults by sku
|
|
///
|
|
DEBUG ((DEBUG_INFO, "Power Limit 2 overrides\n"));
|
|
for (Index = 0; Index < NoOfOverrides; Index++, PpmOverrideTable++) {
|
|
if ((PpmOverrideTable->CpuIdentifier == mCpuIdentifier) && (PpmOverrideTable->MsrPowerLimit2 != 0)) {
|
|
DEBUG ((DEBUG_INFO, "Power Limit 2 override found! PpmOverrideTable->MsrPowerLimit2 = %d\n", PpmOverrideTable->MsrPowerLimit2));
|
|
ConvertedShortDurationPowerLimit = (UINT16) (PpmOverrideTable->MsrPowerLimit2 / 100) * 8;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ConvertedShortDurationPowerLimit > CpuConvertedPowerLimit2MaxLimit) {
|
|
ConvertedShortDurationPowerLimit = CpuConvertedPowerLimit2MaxLimit;
|
|
}
|
|
if (ConvertedShortDurationPowerLimit < mPackageMinPower) {
|
|
ConvertedShortDurationPowerLimit = mPackageMinPower;
|
|
}
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = (UINT32) (ConvertedShortDurationPowerLimit);
|
|
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit2 == TRUE) {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2En = 1;
|
|
} else {
|
|
///
|
|
/// When we disable Power Limit 2, we need to write power limit = 0
|
|
///
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = 0;
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2En = 0;
|
|
}
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"Short duration Power limit enabled, Power Limit = %d Watts\n",
|
|
gCpuPowerMgmtBasicConfig->PowerLimit2Power)
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO,"MSR(610h)=%16X\n",PackageRaplLimitMsr.Uint64));
|
|
|
|
AsmWriteMsr64 (MSR_PACKAGE_RAPL_LIMIT, PackageRaplLimitMsr.Uint64);
|
|
}
|
|
|
|
//
|
|
// Configure Dual Tau Boost for non-cTDP CPU part
|
|
//
|
|
if (IsDualTauEnable ()) {
|
|
ConfigureDualTauBoostOverride (FALSE);
|
|
}
|
|
|
|
///
|
|
/// Set PACKAGE_POWER_LIMIT.CRITICAL_POWER_CLAMP_1(bit 16)
|
|
///
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
PackageRaplLimitMsr.Bits.PkgClmpLim1 = 1;
|
|
AsmWriteMsr64 (MSR_PACKAGE_RAPL_LIMIT, PackageRaplLimitMsr.Uint64);
|
|
|
|
///
|
|
/// Get the MCH space base address.
|
|
///
|
|
MchBar = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MCHBAR)) & ~BIT0;
|
|
|
|
///
|
|
/// Program MMIO PL1 clamp enable
|
|
///
|
|
MmioOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, PACKAGE_POWER_LIMIT_PKG_CLMP_LIM_1_MASK);
|
|
|
|
///
|
|
/// Pass the power limits of the non-CTDP part to the Global NVS Area for use by DPTF
|
|
///
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
mCtdpPowerLimit1[0] = (UINT16) (PackageRaplLimitMsr.Bits.PkgPwrLim1);
|
|
mCtdpPowerLimit2[0] = (UINT16) (PackageRaplLimitMsr.Bits.PkgPwrLim2);
|
|
mCtdpPowerLimitWindow[0] = (UINT8) PowerLimit1Time;
|
|
mCtdpTar[0] = (UINT8) mTurboBusRatio;
|
|
mCtdpCtc[0] = 1;
|
|
mCtdpLevelsSupported = 1;
|
|
mConfigTdpBootModeIndex = 0;
|
|
}
|
|
|
|
/**
|
|
Configures following fields of MSR 0x615
|
|
Configures power limit 3 power level and time window
|
|
**/
|
|
VOID
|
|
ConfigurePl3PowerLimits (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_PL3_CONTROL_REGISTER PowerLimit3ControlMsr;
|
|
|
|
UINT16 ConvertedPowerLimit3;
|
|
UINT8 ConvertedPowerLimit3Time;
|
|
|
|
///
|
|
/// PL3 is supported
|
|
///
|
|
PowerLimit3ControlMsr.Uint64 = AsmReadMsr64 (MSR_PL3_CONTROL);
|
|
DEBUG ((DEBUG_INFO," PL3 MSR 615 Before Writing %x \n",PowerLimit3ControlMsr.Uint32));
|
|
///
|
|
/// Configure PL3 Power Limit if custom value is available
|
|
///
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit3 != AUTO) {
|
|
ConvertedPowerLimit3 = (UINT16) ((gCpuPowerMgmtBasicConfig->PowerLimit3 * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
PowerLimit3ControlMsr.Bits.PowerLimit = (UINT32) (ConvertedPowerLimit3);
|
|
PowerLimit3ControlMsr.Bits.Enable = 1;
|
|
}
|
|
|
|
///
|
|
/// Configure PL3 Time window if custom value is available
|
|
///
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit3Time != AUTO) {
|
|
ConvertedPowerLimit3Time = GetConvertedTime (gCpuPowerMgmtBasicConfig->PowerLimit3Time, MilliSecondsTimeWindowConvert);
|
|
PowerLimit3ControlMsr.Bits.Timewindow = (UINT32) ConvertedPowerLimit3Time;
|
|
PowerLimit3ControlMsr.Bits.Enable = 1;
|
|
}
|
|
|
|
///
|
|
/// Configure PL3 Duty Cycle if custom value is available
|
|
///
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit3DutyCycle != AUTO) {
|
|
PowerLimit3ControlMsr.Bits.Dutycyle = (UINT32) gCpuPowerMgmtBasicConfig->PowerLimit3DutyCycle;
|
|
PowerLimit3ControlMsr.Bits.Enable = 1;
|
|
}
|
|
|
|
//
|
|
// Enable/Disable PL3 lock
|
|
//
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit3Lock == TRUE) {
|
|
PowerLimit3ControlMsr.Bits.Lock = 1;
|
|
} else {
|
|
PowerLimit3ControlMsr.Bits.Lock = 0;
|
|
}
|
|
|
|
if ((gCpuPowerMgmtBasicConfig->PowerLimit3DutyCycle == AUTO) &&
|
|
(gCpuPowerMgmtBasicConfig->PowerLimit3Time == AUTO) &&
|
|
(gCpuPowerMgmtBasicConfig->PowerLimit3 == AUTO)) {
|
|
//
|
|
// Explicitly disable PL3 if all options are set to AUTO
|
|
//
|
|
PowerLimit3ControlMsr.Bits.PowerLimit = 0;
|
|
PowerLimit3ControlMsr.Bits.Enable = 0;
|
|
}
|
|
|
|
AsmWriteMsr64 (MSR_PL3_CONTROL, PowerLimit3ControlMsr.Uint64);
|
|
DEBUG ((DEBUG_INFO," PL3 MSR 615 After Writing %x \n",PowerLimit3ControlMsr.Uint32));
|
|
}
|
|
|
|
/**
|
|
Configure PL4 limits by programming the CURRENT LIMIT and LOCK fields of MSR 601
|
|
**/
|
|
VOID
|
|
ConfigurePl4PowerLimits (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_VR_CURRENT_CONFIG_REGISTER PowerLimit4Msr;
|
|
|
|
UINT16 ConvertedPowerLimit4;
|
|
UINTN NoOfOverrides;
|
|
UINTN Index;
|
|
PPM_OVERRIDE_TABLE *PpmOverrideTable;
|
|
BOOLEAN FvmDisable;
|
|
|
|
NoOfOverrides = 0;
|
|
FvmDisable = TRUE;
|
|
|
|
for (Index = 0; Index < MAX_NUM_VRS; Index++) {
|
|
if (gCpuPowerMgmtVrConfig->IccLimit[Index] != 0) {
|
|
FvmDisable = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
PowerLimit4Msr.Uint64 = AsmReadMsr64 (MSR_VR_CURRENT_CONFIG);
|
|
PowerLimit4Msr.Bits.CurrentLimit = 0;
|
|
DEBUG ((DEBUG_INFO," PL4 MSR 601 Before Writing %x \n", PowerLimit4Msr.Uint32));
|
|
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit4 != AUTO) {
|
|
///
|
|
/// User defined PL4
|
|
///
|
|
ConvertedPowerLimit4 = (UINT16) ((gCpuPowerMgmtBasicConfig->PowerLimit4 * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
PowerLimit4Msr.Bits.CurrentLimit = (UINT32) (ConvertedPowerLimit4);
|
|
} else {
|
|
//
|
|
// Set PL4 power limit = 0 when AUTO is selected
|
|
//
|
|
if (gOverClockingPreMemConfig->OcSupport == 0) {
|
|
PpmOverrideTable = GetFruPowerLimits (&NoOfOverrides);
|
|
///
|
|
/// Override the PL4 power limit with the table value
|
|
///
|
|
for (Index = 0; Index < NoOfOverrides; Index++, PpmOverrideTable++) {
|
|
if (PpmOverrideTable->CpuIdentifier == mCpuIdentifier) {
|
|
///
|
|
/// We need to check that the CpuIdentifier matches before updating PL4
|
|
///
|
|
if (PpmOverrideTable->MsrPowerLimit4DisableFvm !=0 && IsFastVmodeIccLimitSupport() && FvmDisable) {
|
|
PowerLimit4Msr.Bits.CurrentLimit = ((PpmOverrideTable->MsrPowerLimit4DisableFvm * mProcessorPowerUnit) / 100);
|
|
} else if (PpmOverrideTable->MsrPowerLimit4 != 0) {
|
|
PowerLimit4Msr.Bits.CurrentLimit = ((PpmOverrideTable->MsrPowerLimit4 * mProcessorPowerUnit) / 100);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
///
|
|
/// Disable PL4 when AUTO is selected and overclocking is enabled.
|
|
///
|
|
PowerLimit4Msr.Uint32 = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable/Disable PL4 lock
|
|
//
|
|
if (gCpuPowerMgmtBasicConfig->PowerLimit4Lock == TRUE) {
|
|
PowerLimit4Msr.Bits.Lock = 1;
|
|
} else {
|
|
PowerLimit4Msr.Bits.Lock = 0;
|
|
}
|
|
|
|
AsmWriteMsr64 (MSR_VR_CURRENT_CONFIG, PowerLimit4Msr.Uint64);
|
|
DEBUG ((DEBUG_INFO," PL4 MSR 601 After Writing %x \n ", PowerLimit4Msr.Uint32));
|
|
}
|
|
|
|
/**
|
|
Configures following fields of MSR 0x610
|
|
Configures Long duration Turbo Mode (power limit 1) power level and time window
|
|
Configures Short duration turbo mode (power limit 2)
|
|
**/
|
|
VOID
|
|
ConfigureCtdpPowerLimits (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMsr;
|
|
UINT32 PowerLimit1Time;
|
|
UINT16 ConvertedPowerLimit1;
|
|
UINT16 ConvertedPowerLimit2;
|
|
UINT16 ConvertedCustomPowerLimit1;
|
|
UINT16 ConvertedCustomPowerLimit2;
|
|
UINT8 ConvertedPowerLimit1Time;
|
|
UINTN MchBar;
|
|
UINTN Index;
|
|
BOOLEAN Pl1Flag;
|
|
BOOLEAN Pl2Flag;
|
|
|
|
PowerLimit1Time = gCpuPowerMgmtBasicConfig->PowerLimit1Time;
|
|
ConvertedPowerLimit1 = 0 ;
|
|
ConvertedCustomPowerLimit1 = 0;
|
|
ConvertedPowerLimit1Time = 0;
|
|
ConvertedPowerLimit2 = 0;
|
|
ConvertedCustomPowerLimit2 = 0;
|
|
Pl1Flag = FALSE;
|
|
Pl2Flag = FALSE;
|
|
|
|
//
|
|
// For ConfigTdp enabled skus
|
|
//
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = 0;
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = 0;
|
|
///
|
|
/// Initialize the Power Limit 1/2 and Power Limit 2 enable bit in MSR
|
|
/// Power Limit 1: Turbo Power Limit MSR [14:0] and Power Limit 2: Turbo Power Limit MSR [46:32]
|
|
/// Set MSR value for Power Limit 1/2 to Max Package Power Value or Maximum Supported Value
|
|
///
|
|
///
|
|
if (mPackageMaxPower) {
|
|
ConvertedPowerLimit1 = mPackageMaxPower;
|
|
} else {
|
|
ConvertedPowerLimit1 = mCtdpPowerLimit1[gCpuConfigLibPreMemConfig->ConfigTdpLevel];
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1 != 0) {
|
|
Pl1Flag = TRUE;
|
|
}
|
|
if (ConvertedCustomPowerLimit1 < gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1) {
|
|
ConvertedCustomPowerLimit1 = gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < mCtdpLevelsSupported; Index++) {
|
|
if (ConvertedPowerLimit2 < mCtdpPowerLimit2[Index]) {
|
|
ConvertedPowerLimit2 = mCtdpPowerLimit2[Index];
|
|
}
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2 != 0) {
|
|
Pl2Flag = TRUE;
|
|
}
|
|
if (ConvertedCustomPowerLimit2 < gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2) {
|
|
ConvertedCustomPowerLimit2 = gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Program Power Limit 1 (Long Duration Turbo) Time Window
|
|
/// If PowerLimit1Time is AUTO OR If PowerLimit1Time is > MAX_POWER_LIMIT_1_TIME_IN_SECONDS
|
|
/// program default values
|
|
///
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[0].CustomPowerLimit1Time != 0) {
|
|
ConvertedPowerLimit1Time = GetConvertedTime (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[0].CustomPowerLimit1Time, SecondsTimeWindowConvert);
|
|
} else {
|
|
if (IsMobileSku () || IsHaloSku ()) {
|
|
///
|
|
/// For Mobile and Halo, default value is 28 seconds.
|
|
///
|
|
PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT;
|
|
if (mPackageTdpWatt == 45) {
|
|
///
|
|
/// For 45W SKU, Tau is 56 seconds.
|
|
///
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
}
|
|
} else {
|
|
///
|
|
/// For Desktop, default value is 1 second.For 125 Watt it is 56 seconds.
|
|
///
|
|
if (mPackageTdpWatt >= 125) {
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
} else {
|
|
PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT;
|
|
}
|
|
if (IsSbgaSkuSupported ()) {
|
|
PowerLimit1Time = POWER_LIMIT1_TIME_56_SEC;
|
|
}
|
|
}
|
|
ConvertedPowerLimit1Time = GetConvertedTime (PowerLimit1Time, SecondsTimeWindowConvert);
|
|
}
|
|
///
|
|
/// Set PkgClmpLim1 (bit 16)
|
|
///
|
|
PackageRaplLimitMsr.Bits.PkgClmpLim1 = 1;
|
|
|
|
///
|
|
/// Get the MCH space base address.
|
|
///
|
|
MchBar = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MCHBAR)) & ~BIT0;
|
|
|
|
///
|
|
/// Program MMIO PL1 clamp enable
|
|
///
|
|
MmioOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, PACKAGE_POWER_LIMIT_PKG_CLMP_LIM_1_MASK);
|
|
|
|
///
|
|
/// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17]
|
|
///
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1Time = (UINT32) ConvertedPowerLimit1Time;
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2En = 1;
|
|
if (Pl1Flag) {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = (UINT32) ConvertedCustomPowerLimit1;
|
|
} else {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = (UINT32) ConvertedPowerLimit1;
|
|
}
|
|
if (Pl2Flag) {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = (UINT32) ConvertedCustomPowerLimit2;
|
|
} else {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = (UINT32) ConvertedPowerLimit2;
|
|
}
|
|
AsmWriteMsr64 (MSR_PACKAGE_RAPL_LIMIT, PackageRaplLimitMsr.Uint64);
|
|
}
|
|
|
|
/**
|
|
Configures BIOS overrides in MSR 0x610
|
|
Configures Long duration Turbo Mode (power limit 1) power level and time window
|
|
Configures Short duration turbo mode (power limit 2)
|
|
**/
|
|
VOID
|
|
ConfigureCtdpPowerLimitsOverrides (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN NoOfOverrides;
|
|
PPM_OVERRIDE_TABLE *PpmCtdpOverrideTable;
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMsr;
|
|
|
|
PpmCtdpOverrideTable = GetFruPowerLimits (&NoOfOverrides);
|
|
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
|
|
for (Index = 0; Index < NoOfOverrides; Index++, PpmCtdpOverrideTable++) {
|
|
if (PpmCtdpOverrideTable->CpuIdentifier == mCpuIdentifier) {
|
|
///
|
|
/// MSR Overrides
|
|
///
|
|
if (PpmCtdpOverrideTable->MsrPowerLimit1) {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim1 = (UINT32) ((PpmCtdpOverrideTable->MsrPowerLimit1 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->MsrPowerLimit2) {
|
|
PackageRaplLimitMsr.Bits.PkgPwrLim2 = (UINT32) ((PpmCtdpOverrideTable->MsrPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->MsrPowerLimit1 || PpmCtdpOverrideTable->MsrPowerLimit2) {
|
|
AsmWriteMsr64 (MSR_PACKAGE_RAPL_LIMIT, PackageRaplLimitMsr.Uint64);
|
|
}
|
|
///
|
|
/// MMIO Overrides
|
|
///
|
|
if (PpmCtdpOverrideTable->CtdpNominalPowerLimit1) {
|
|
mCtdpPowerLimit1[0] = (UINT16) ((PpmCtdpOverrideTable->CtdpNominalPowerLimit1 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->CtdpDownPowerLimit1) {
|
|
mCtdpPowerLimit1[1] = (UINT16) ((PpmCtdpOverrideTable->CtdpDownPowerLimit1 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->CtdpUpPowerLimit1) {
|
|
mCtdpPowerLimit1[2] = (UINT16) ((PpmCtdpOverrideTable->CtdpUpPowerLimit1 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->CtdpNominalPowerLimit2) {
|
|
mCtdpPowerLimit2[0] = (UINT16) ((PpmCtdpOverrideTable->CtdpNominalPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->CtdpDownPowerLimit2) {
|
|
mCtdpPowerLimit2[1] = (UINT16) ((PpmCtdpOverrideTable->CtdpDownPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
}
|
|
if (PpmCtdpOverrideTable->CtdpUpPowerLimit2) {
|
|
mCtdpPowerLimit2[2] = (UINT16) ((PpmCtdpOverrideTable->CtdpUpPowerLimit2 * mProcessorPowerUnit) / 100);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configure cTDP BIOS MSRs to Boot Ctdp values
|
|
- Configures CONFIG_TDP_CONTROL MSR
|
|
- Configures TURBO_ACTIVATION_RATIO MSR
|
|
|
|
@param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user
|
|
**/
|
|
VOID
|
|
SelectCtdpLevel (
|
|
IN UINT8 CpuConfigTdpBootLevel
|
|
)
|
|
{
|
|
MSR_CONFIG_TDP_CONTROL_REGISTER ConfigTdpControlMsr;
|
|
MSR_TURBO_ACTIVATION_RATIO_REGISTER TurboActivationRatioMsr;
|
|
|
|
///
|
|
/// Select cTDP Nominal if cTDP is disabled or the level is not supported.
|
|
///
|
|
if (CpuConfigTdpBootLevel == CONFIG_TDP_DEACTIVATE || CpuConfigTdpBootLevel >= mCtdpLevelsSupported) {
|
|
CpuConfigTdpBootLevel = 0;
|
|
}
|
|
|
|
if (CpuConfigTdpBootLevel >= 3) {
|
|
DEBUG ((DEBUG_ERROR, "ERROR: Invalid CpuConfigTdpBootLevel=%x, and CpuConfigTdpBootLevel should be range in 0-2 \n", CpuConfigTdpBootLevel));
|
|
ASSERT (FALSE);
|
|
return;
|
|
}
|
|
|
|
mCpuConfigTdpBootRatio = mCtdpTar[CpuConfigTdpBootLevel] + 1;
|
|
mConfigurablePpc = mCtdpPpc[CpuConfigTdpBootLevel];
|
|
///
|
|
/// Program the selected level 00:nominal,01:level1,10:level2 to
|
|
/// CONFIG TDP CONTROL MSR.
|
|
///
|
|
ConfigTdpControlMsr.Uint64 = AsmReadMsr64 (MSR_CONFIG_TDP_CONTROL);
|
|
if (ConfigTdpControlMsr.Bits.ConfigTdpLock == 0) {
|
|
ConfigTdpControlMsr.Bits.TdpLevel = (UINT32) CpuConfigTdpBootLevel;
|
|
if (gCpuPowerMgmtCustomConfig->ConfigTdpLock == TRUE ) {
|
|
ConfigTdpControlMsr.Bits.ConfigTdpLock = 1;
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL is locked\n"));
|
|
}
|
|
AsmWriteMsr64 (MSR_CONFIG_TDP_CONTROL, ConfigTdpControlMsr.Uint64);
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL=0x%x\n", ConfigTdpControlMsr.Uint64));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "PPM:: Could not write MSR_CONFIG_TDP_CONTROL\n"));
|
|
}
|
|
///
|
|
/// Program the max non-turbo ratio corresponding to default selected level
|
|
/// in TURBO_ACTIVATION_RATIO MSR.
|
|
///
|
|
TurboActivationRatioMsr.Uint64 = AsmReadMsr64 (MSR_TURBO_ACTIVATION_RATIO);
|
|
if (TurboActivationRatioMsr.Bits.TurboActivationRatioLock == 0) {
|
|
TurboActivationRatioMsr.Bits.MaxNonTurboRatio = (UINT32) (mCpuConfigTdpBootRatio - 1);
|
|
if (gCpuPowerMgmtCustomConfig->ConfigTdpLock == TRUE) {
|
|
TurboActivationRatioMsr.Bits.TurboActivationRatioLock = 1;
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO is locked\n"));
|
|
}
|
|
AsmWriteMsr64 (MSR_TURBO_ACTIVATION_RATIO, TurboActivationRatioMsr.Uint64);
|
|
DEBUG ((DEBUG_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO=0x%x\n", TurboActivationRatioMsr.Uint64));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "PPM:: Could not write MSR_TURBO_ACTIVATION_RATIO\n"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configures the TURBO_POWER_LIMIT MMIO for Boot ConfigTdp Level
|
|
|
|
@param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user
|
|
**/
|
|
VOID
|
|
SelectCtdpPowerLimits (
|
|
IN UINT8 CpuConfigTdpBootLevel
|
|
)
|
|
{
|
|
UINTN MchBar;
|
|
UINT32 Data32And;
|
|
UINT32 Data32Or;
|
|
UINT16 PowerLimit1;
|
|
UINT16 PowerLimit2;
|
|
|
|
MSR_PACKAGE_RAPL_LIMIT_REGISTER PackageRaplLimitMsr;
|
|
|
|
//
|
|
// Skip the programming if Dual Tau Boost is supported
|
|
//
|
|
if (IsDualTauEnable () && DualTauGetPowerLimit (NULL, NULL, NULL, NULL, NULL, NULL)) {
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// Select cTDP Nominal if Ctdp disabled or boot level not supported.
|
|
///
|
|
if (CpuConfigTdpBootLevel >= mCtdpLevelsSupported) {
|
|
CpuConfigTdpBootLevel = 0;
|
|
}
|
|
|
|
PowerLimit1 = mCtdpPowerLimit1[CpuConfigTdpBootLevel];
|
|
PowerLimit2 = mCtdpPowerLimit2[CpuConfigTdpBootLevel];
|
|
///
|
|
/// Check if Power Limits are initalized
|
|
///
|
|
if (PowerLimit1 != 0 && PowerLimit2 != 0) {
|
|
///
|
|
/// Get the MCH space base address.
|
|
/// Program Turbo Power Limit MMIO register MCHBAR+0x59A0 Bits [14:0] and [46:32]
|
|
/// for ConfigTdp mode PL1 and PL2
|
|
///
|
|
MchBar = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MCHBAR)) & ~BIT0;
|
|
///
|
|
/// Read PowerLimit MSR
|
|
///
|
|
PackageRaplLimitMsr.Uint64 = AsmReadMsr64 (MSR_PACKAGE_RAPL_LIMIT);
|
|
///
|
|
/// Program cTDP Power Limit1
|
|
///
|
|
Data32And = (UINT32) ~(CONFIG_TDP_LVL1_PKG_TDP_MASK);
|
|
Data32Or = (UINT32) (PowerLimit1 | (PackageRaplLimitMsr.Uint32 & ~(CONFIG_TDP_LVL1_PKG_TDP_MASK)));
|
|
MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, Data32And, Data32Or);
|
|
///
|
|
/// Program cTDP Power Limit2
|
|
///
|
|
Data32And = (UINT32) ~(CONFIG_TDP_LVL1_PKG_TDP_MASK);
|
|
Data32Or = (UINT32) (PowerLimit2 | ((UINT32) RShiftU64 (PackageRaplLimitMsr.Uint64, 32) & ~(CONFIG_TDP_LVL1_PKG_TDP_MASK)));
|
|
MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT_HIGH, Data32And, Data32Or);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Configures following fields of MSR 0x618 based on corresponding MMIO register (MCHBAR+0x58E0):
|
|
Configures Long duration Turbo Mode (power limit 1) power level and time window for DDR domain
|
|
Configures Short duration Turbo Mode (power limit 2) power level and time window for DDR domain
|
|
**/
|
|
VOID
|
|
ConfigureDdrPowerLimits (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_DDR_RAPL_LIMIT_REGISTER DdrRaplLimitMsr;
|
|
|
|
UINTN MchBar;
|
|
|
|
MchBar = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MCHBAR)) & ~BIT0;
|
|
|
|
DdrRaplLimitMsr.Uint64 = (MmioRead32 (MchBar + MMIO_DDR_RAPL_LIMIT) &~BIT0) + LShiftU64 (MmioRead32 (MchBar + MMIO_DDR_RAPL_LIMIT + 4), 32);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"DDR Power Limit 1 = %d\n",
|
|
DdrRaplLimitMsr.Bits.Limit1Power)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"DDR Power Limit 2 = %d\n",
|
|
DdrRaplLimitMsr.Bits.Limit2Power)
|
|
);
|
|
|
|
AsmWriteMsr64 (MSR_DDR_RAPL_LIMIT, DdrRaplLimitMsr.Uint64);
|
|
}
|
|
|
|
/**
|
|
Configures MSR 0x65C platform power limits (PSys)
|
|
-Configures Platform Power Limit 1 Enable, power and time window
|
|
-Configures Platform Power Limit 2 Enable, power
|
|
-Platform power limits are limited by the Package Max and Min power
|
|
**/
|
|
VOID
|
|
ConfigurePlatformPowerLimits (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 ConvertedPowerLimit1;
|
|
BOOLEAN ConvertedPowerLimit1En;
|
|
UINT32 ConvertedPowerLimit1Time;
|
|
UINT32 ConvertedPowerLimit2;
|
|
BOOLEAN ConvertedPowerLimit2En;
|
|
BOOLEAN ConvertedLock;
|
|
UINT16 CpuConvertedPowerLimit1MaxLimit;
|
|
UINT16 CpuConvertedPowerLimit2MaxLimit;
|
|
UINT16 Multiplier;
|
|
UINT32 PsysPowerLimit1Time;
|
|
|
|
ConvertedPowerLimit1 = 0;
|
|
ConvertedPowerLimit1En = FALSE;
|
|
ConvertedPowerLimit1Time = 0;
|
|
ConvertedPowerLimit2 = 0;
|
|
ConvertedPowerLimit2En = FALSE;
|
|
ConvertedLock = FALSE;
|
|
CpuConvertedPowerLimit1MaxLimit = 0;
|
|
CpuConvertedPowerLimit2MaxLimit = 0;
|
|
PsysPowerLimit1Time = gCpuPowerMgmtPsysConfig->PsysPowerLimit1Time;
|
|
///
|
|
/// By default, for Mobile & Desktop Processors: Platform Power Limit 2 = 1.25 * Package TDP
|
|
///
|
|
Multiplier = 125;
|
|
|
|
///
|
|
/// Initialize the Power Limit 1 and Power Limit 1 enable bit
|
|
/// - Power Limit 1: Platform Power Limit MSR [14:0]
|
|
/// - Power Limit 1 Enable: Platform Power Limit MSR [15]
|
|
///
|
|
///
|
|
/// By default, program Power Limit 1 to Package TDP limit
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) mPackageTdp;
|
|
if (gCpuPowerMgmtPsysConfig->PsysPowerLimit1Power != AUTO) {
|
|
///
|
|
/// gCpuPowerMgmtPsysConfig->PsysPowerLimit1Power is in mW or watts. We need to
|
|
/// convert it to CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].
|
|
/// Since we are converting from Watts to CPU power units, multiply by
|
|
/// PACKAGE_POWER_SKU_UNIT_MSR[3:0].
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) ((gCpuPowerMgmtPsysConfig->PsysPowerLimit1Power * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
if (mPackageMaxPower == 0 && (UINT16) ConvertedPowerLimit1 >= mPackageMinPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [46:32] = 0 means there is no upper limit ( since this field is 15 bits, the max value is 2^15 - 1 )
|
|
///
|
|
CpuConvertedPowerLimit1MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
|
|
if ((UINT16) ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > CpuConvertedPowerLimit1MaxLimit, program Power Limit 1 to CpuConvertedPowerLimit1MaxLimit
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) CpuConvertedPowerLimit1MaxLimit;
|
|
}
|
|
} else if (mPackageMinPower == 0 && ConvertedPowerLimit1 > 0 && (UINT16) ConvertedPowerLimit1 <= mPackageMaxPower) {
|
|
///
|
|
/// If PACKAGE_POWER_SKU_MSR [30:16] = 0 means there is no lower limit
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) ((gCpuPowerMgmtBasicConfig->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
} else {
|
|
///
|
|
/// Power Limit 1 needs to be between mPackageMinPower and mPackageMaxPower
|
|
///
|
|
CpuConvertedPowerLimit1MaxLimit = mPackageMaxPower;
|
|
|
|
if ((UINT16) ConvertedPowerLimit1 < mPackageMinPower) {
|
|
///
|
|
/// If new Power Limit 1 is < mPackageMinPower, program Power Limit 1 to mPackageMinPower
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) mPackageMinPower;
|
|
} else if ((UINT16) ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
|
|
///
|
|
/// If new Power Limit 1 is > mPackageMaxPower, program Power Limit 1 to mPackageMaxPower
|
|
///
|
|
ConvertedPowerLimit1 = (UINT32) CpuConvertedPowerLimit1MaxLimit;
|
|
}
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Update Platform Power Limit 1 enable bit
|
|
///
|
|
if (gCpuPowerMgmtPsysConfig->PsysPowerLimit1) {
|
|
ConvertedPowerLimit1En = (BOOLEAN) gCpuPowerMgmtPsysConfig->PsysPowerLimit1;
|
|
} else {
|
|
///
|
|
/// When we disable Platform Power Limit we need to write power limit = 0
|
|
///
|
|
ConvertedPowerLimit1 = 0;
|
|
ConvertedPowerLimit1En = 0;
|
|
}
|
|
|
|
///
|
|
/// Program Platform Power Limit 1 Time Window
|
|
/// If PlatformPowerLimit1Time is AUTO OR If PlatformPowerLimit1Time
|
|
/// is > MAX_POWER_LIMIT_1_TIME_IN_SECONDS program default values
|
|
///
|
|
if ((gCpuPowerMgmtPsysConfig->PsysPowerLimit1Time == AUTO) ||
|
|
(gCpuPowerMgmtPsysConfig->PsysPowerLimit1Time > MAX_POWER_LIMIT_1_TIME_IN_SECONDS)
|
|
) {
|
|
if (IsMobileSku () || IsHaloSku ()) {
|
|
///
|
|
/// For Mobile, default value is 28 seconds
|
|
///
|
|
PsysPowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT;
|
|
} else {
|
|
///
|
|
/// For Desktop, default value is 1 second
|
|
///
|
|
PsysPowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT;
|
|
}
|
|
}
|
|
|
|
ConvertedPowerLimit1Time = (UINT32) GetConvertedTime (PsysPowerLimit1Time, SecondsTimeWindowConvert);
|
|
|
|
///
|
|
/// Initialize Short Duration Power limit and enable bit
|
|
/// Platform Power Limit 2: Platform Power Limit MSR (0x450h) [46:32]
|
|
/// Platform Power Limit 2 Enable: Platform Power Limit MSR (0x450h) [47]
|
|
///
|
|
/// gCpuPowerMgmtPsysConfig->PsysPowerLimit2Power value is in mW or watts. We need to convert it to
|
|
/// CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].Since we are converting
|
|
/// from Watts to CPU power units, multiply by PACKAGE_POWER_SKU_UNIT_MSR[3:0]
|
|
///
|
|
ConvertedPowerLimit2 = (UINT32) ((gCpuPowerMgmtPsysConfig->PsysPowerLimit2Power * mProcessorPowerUnit) / mCustomPowerUnit);
|
|
|
|
///
|
|
/// If PlatformPowerLimit2 is AUTO OR if PlatformPowerLimit2 is > mPackageMaxPower
|
|
/// OR if Platform PowerLimit2 < mPackageMinPower program defaul values.
|
|
///
|
|
CpuConvertedPowerLimit2MaxLimit = mPackageMaxPower;
|
|
if (CpuConvertedPowerLimit2MaxLimit == 0) {
|
|
CpuConvertedPowerLimit2MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
|
|
}
|
|
if (gCpuPowerMgmtPsysConfig->PsysPowerLimit2Power == AUTO) {
|
|
ConvertedPowerLimit2 = (UINT32) EFI_IDIV_ROUND ((Multiplier * mPackageTdp), 100);
|
|
}
|
|
if ((UINT16) ConvertedPowerLimit2 > CpuConvertedPowerLimit2MaxLimit) {
|
|
ConvertedPowerLimit2 = (UINT32) CpuConvertedPowerLimit2MaxLimit;
|
|
}
|
|
if ((UINT16) ConvertedPowerLimit2 < mPackageMinPower) {
|
|
ConvertedPowerLimit2 = (UINT32) mPackageMinPower;
|
|
}
|
|
|
|
if (gCpuPowerMgmtPsysConfig->PsysPowerLimit2) {
|
|
ConvertedPowerLimit2En = (BOOLEAN) gCpuPowerMgmtPsysConfig->PsysPowerLimit2;
|
|
} else {
|
|
///
|
|
/// When we disable Platform Power Limit we need to write power limit = 0
|
|
///
|
|
ConvertedPowerLimit2 = 0;
|
|
ConvertedPowerLimit2En = 0;
|
|
}
|
|
|
|
MsrGetPlatformPowerLimit (
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ConvertedLock
|
|
);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"New Platform Power Limit 1 %d watt (%d in CPU power unit)\n",
|
|
gCpuPowerMgmtPsysConfig->PsysPowerLimit1Power,
|
|
(UINT16) ConvertedPowerLimit1)
|
|
);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"Platform Power Limit 2 Power = %d Watts (%d in CPU power unit)\n",
|
|
gCpuPowerMgmtPsysConfig->PsysPowerLimit2Power,
|
|
(UINT16) ConvertedPowerLimit2)
|
|
);
|
|
|
|
MsrSetPlatformPowerLimit (
|
|
ConvertedPowerLimit1,
|
|
ConvertedPowerLimit1En,
|
|
ConvertedPowerLimit1Time,
|
|
ConvertedPowerLimit2,
|
|
ConvertedPowerLimit2En,
|
|
ConvertedLock
|
|
);
|
|
}
|
|
|
|
/**
|
|
Configures PowerLimits and Config TDP values
|
|
**/
|
|
VOID
|
|
ConfigureCtdp (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 CustomPowerLimits;
|
|
UINT8 Index;
|
|
///
|
|
/// Configure CTDP power limits.Refer Rev 0.6.0 BWG sec 16.7.1: Enabling Intel Configurable TDP support
|
|
///
|
|
ConfigureCtdpPowerLimits ();
|
|
|
|
///
|
|
///
|
|
/// Check if any power limits are overriden, flag CustomPowerLimits if detected
|
|
///
|
|
CustomPowerLimits = FALSE;
|
|
for (Index = 0; Index < MAX_CUSTOM_CTDP_ENTRIES; Index++) {
|
|
if (gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1 != 0 ||
|
|
gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit1Time != 0 ||
|
|
gCpuPowerMgmtCustomConfig->CustomConfigTdpTable[Index].CustomPowerLimit2 != 0) {
|
|
CustomPowerLimits = TRUE;
|
|
}
|
|
}
|
|
|
|
///
|
|
/// BIOS power limit overrides
|
|
/// Don't override if custom ctdp settings are provided.
|
|
///
|
|
if (CustomPowerLimits == FALSE) {
|
|
ConfigureCtdpPowerLimitsOverrides ();
|
|
}
|
|
|
|
//
|
|
// Configure Dual Tau Boost
|
|
//
|
|
if (IsDualTauEnable ()) {
|
|
ConfigureDualTauBoostOverride (TRUE);
|
|
}
|
|
|
|
///
|
|
/// To avoid issues and race conditions it is recommended for the below order to be followed:
|
|
/// - For TDP Up program the Power Limits followed by Config TDP Level
|
|
/// - For TDP Down program the Config TDP Level followed by Power Limits
|
|
///
|
|
if (gCpuConfigLibPreMemConfig->ConfigTdpLevel == CONFIG_TDP_UP) {
|
|
SelectCtdpPowerLimits (mConfigTdpBootModeIndex);
|
|
SelectCtdpLevel (mConfigTdpBootModeIndex);
|
|
} else {
|
|
SelectCtdpLevel (mConfigTdpBootModeIndex);
|
|
SelectCtdpPowerLimits (mConfigTdpBootModeIndex);
|
|
}
|
|
}
|