/** @file
This file contains power management configuration functions for processors.
Acronyms:
- PPM: Processor Power Management
- TM: Thermal Monitor
- IST: Intel(R) Speedstep technology
- HT: Hyper-Threading Technology
@copyright
INTEL CONFIDENTIAL
Copyright 2012 - 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
#include
#include
#include
#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);
}
}