diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c')
-rw-r--r-- | ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c | 1302 |
1 files changed, 1302 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c new file mode 100644 index 0000000..9c0c19e --- /dev/null +++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c @@ -0,0 +1,1302 @@ +/** @file + This file contains power management configuration functions for + Haswell processors. + + Acronyms: + PPM - Processor Power Management + TM - Thermal Monitor + IST - Intel(R) Speedstep technology + HT - Hyper-Threading Technology + +@copyright + Copyright (c) 2012 - 2014 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PowerMgmtCommon.h" + +PPM_CTDP_OVERRIDE_TABLE mHswUltPpmCtdpOverideTable[]={ +/// TDP Icc MSR PL1 MSR PL2 TdpUp TdpUp TdpNominal TdpNominal TdpDown TdpDown +/// Max PL1 PL2 PL1 PL2 PL1 PL2 + { 5700, 0, 6700, 8375, 0, 8375, 0, 8375, 0, 8375 }, /// 57W Sku Overrides + { 1500, 0, 2500, 2500, 0, 2500, 0, 2500, 0, 2500 }, /// 15W Sku Overrides + { 1150, 0, 0, 2500, 0, 2500, 0, 2500, 0, 2500 }, /// 11.5W Sku Overrides + { 2800, 40, 0, 3500, 0, 3500, 0, 3500, 0, 3500 } /// 28W 40A Sku Overrides +}; + +PPM_CTRL_TDP_SKU_TBL mHswCtrlTdpSkuTable[] = { + {"Celeron",03,{"2955U","2957U","2005U"}} +}; + +/** + Configurable TDP BIOS Initialization + + @param[in] CpuPmConfig Pointer to policy protocol instance + @param[in] FvidPointer Pointer to Fvid Table + + @exception EFI_UNSUPPORTED Ctdp not Supported + @retval EFI_SUCCESS Ctdp Initiation done +**/ +EFI_STATUS +InitializeConfigurableTdp ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + EFI_STATUS Status; + EFI_STATUS CustomCtdpSettings; + UINTN Index; + + + if (mPpmGlobalNvsAreaProtocol == NULL) { + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Require mPpmGlobalNvsAreaProtocol.\n")); + return EFI_UNSUPPORTED; + } + /// + /// Intialize PPM Global NVS with custom CTDP level settings or CPU provided. + /// + CustomCtdpSettings = InitCustomConfigurableTdp (CpuPmConfig); + if (CustomCtdpSettings != EFI_SUCCESS) { + Status = InitConfigurableTdpSettings (CpuPmConfig); + if (Status != EFI_SUCCESS) { + /// + /// Check for Controllable TDP enable if Ctdp not supported + /// + InitControllableTdp(CpuPmConfig); + 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 < (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported); Index++) { + if (mMinBusRatio == mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar+1) { + mMinBusRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar; + DEBUG ((EFI_D_INFO, "PPM:: mMinBusRatio Modified for Ctdp %d\n", mMinBusRatio)); + } + } + + return EFI_SUCCESS; +} + +/** + Custom Configurable TDP Table BIOS Initialization + + @param[in] CpuPmConfig Pointer to policy protocol instance + + @exception EFI_UNSUPPORTED Custom Ctdp settings are not available + @retval EFI_SUCCESS Successfully Initialized Custom Ctdp Settings +**/ +EFI_STATUS +InitCustomConfigurableTdp ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + UINT8 Index; + + if (!CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) { + return EFI_UNSUPPORTED; + } + /// + /// CTC value should not be more Custom configured levels. + /// + if (CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex > CpuPmConfig->pCustomCtdpSettings->CustomTdpCount - 1) { + CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex = 0; + } + if (mPpmGlobalNvsAreaProtocol != NULL) { + /// + /// Update Custom ConfigTdp table for ACPI + /// + if (CpuPmConfig->pCustomCtdpSettings->CustomTdpCount != 0) { + mPpmGlobalNvsAreaProtocol->Area->CustomConfigTdp = PPM_ENABLE; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = CpuPmConfig->pCustomCtdpSettings->CustomTdpCount; + mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex; + for (Index = 0; Index < (CpuPmConfig->pCustomCtdpSettings->CustomTdpCount); Index++) { + /// + /// Verify and fix Custom configured CTDP Levels PL1 and PL2 + /// + CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1 = VerifyAndFixCustomPowerLimit (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1,mCustomPowerUnit); + CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2 = VerifyAndFixCustomPowerLimit (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2,mCustomPowerUnit); + CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio = VerifyAndFixCustomRatio (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio+1)-1; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = (UINT16) CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = (UINT16) CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1Time; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomConfigTdpControl; + } + } + } + + 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; +} + +/** + CTDP BIOS settings Initialization(From Msrs) + + @param[in] CpuPmConfig Pointer to policy protocol instance + + @exception EFI_UNSUPPORTED Ctdp not supported + @retval EFI_SUCCESS Ctdp Settings Initialized successfully from MSRs +**/ +EFI_STATUS +InitConfigurableTdpSettings ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER TempMsr; + UINTN Index; + UINT16 CpuConfigTdpNominalTdp; + UINT16 CpuConfigTdpLevel1Tdp; + UINT16 CpuConfigTdpLevel2Tdp; + UINT8 CpuConfigTdpNominalRatio; + UINT8 CpuConfigTdpLevel1Ratio; + UINT8 CpuConfigTdpLevel2Ratio; + UINT16 CpuConfigTdpLevels; + + /// + /// Get the number of configurable TDP Levels supported + /// + TempMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO); + TempMsr.Qword &= V_CONFIG_TDP_NUM_LEVELS_MASK; + CpuConfigTdpLevels = (UINT8) RShiftU64 (TempMsr.Qword, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET); + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Supported Levels=%d\n", CpuConfigTdpLevels)); + /// + /// Return if ConfigTDP Levels not supported + /// + if (CpuConfigTdpLevels == 0) { + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Levels not supported\n")); + return EFI_UNSUPPORTED; + } + mPpmGlobalNvsAreaProtocol->Area->CustomConfigTdp = PPM_DISABLE; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = (UINT8) CpuConfigTdpLevels + 1; + mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = CpuPmConfig->pTurboSettings->ConfigTdpLevel; + /// + /// Get PKG_TDP for Config TDP Nominal + /// + TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_NOMINAL); + CpuConfigTdpNominalRatio = (UINT8) (TempMsr.Dwords.Low & CONFIG_TDP_NOMINAL_RATIO_MASK); + CpuConfigTdpNominalTdp = mPackageTdp; + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Nominal Ratio=%d Tdp=%d\n", CpuConfigTdpNominalRatio, CpuConfigTdpNominalTdp)); + /// + /// Set Level0 as Tdp Nominal + /// + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = mPackageTdp; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1); + if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = MB_POWER_LIMIT1_TIME_DEFAULT; + } else { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = DT_POWER_LIMIT1_TIME_DEFAULT; + } + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpTar = (UINT8) (CpuConfigTdpNominalRatio - 1); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpCtc = CONFIG_TDP_NOMINAL; + /// + /// Get PKG_TDP and Ratio for Config TDP Level1 + /// + TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_LVL1); + CpuConfigTdpLevel1Ratio = (UINT8) RShiftU64 ( + TempMsr.Qword & CONFIG_TDP_LVL1_RATIO_MASK, + CONFIG_TDP_LVL1_RATIO_OFFSET + ); + CpuConfigTdpLevel1Tdp = (UINT16) (TempMsr.Dwords.Low & CONFIG_TDP_LVL1_PKG_TDP_MASK); + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Level1 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel1Ratio, CpuConfigTdpLevel1Tdp)); + /// + /// Set Level 1 + /// + Index = 1; + if (CpuConfigTdpLevel1Ratio != 0) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = CpuConfigTdpLevel1Tdp; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = (UINT8) (CpuConfigTdpLevel1Ratio - 1); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CONFIG_TDP_LEVEL1; + Index++; + } + /// + /// If two levels are supported or Level1 was not valid + /// then read Level2 registers + /// + if (CpuConfigTdpLevels == CONFIG_TDP_LEVEL2 || CpuConfigTdpLevel1Ratio == 0) { + /// + /// Get PKG_TDP and Ratio for Config TDP Level2 + /// + TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_LVL2); + CpuConfigTdpLevel2Ratio = (UINT8) RShiftU64 ( + TempMsr.Qword & CONFIG_TDP_LVL2_RATIO_MASK, + CONFIG_TDP_LVL2_RATIO_OFFSET + ); + CpuConfigTdpLevel2Tdp = (UINT16) (TempMsr.Dwords.Low & CONFIG_TDP_LVL2_PKG_TDP_MASK); + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Level2 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel2Ratio, CpuConfigTdpLevel2Tdp)); + /// + /// Set Level2 + /// + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = CpuConfigTdpLevel2Tdp; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = (UINT8) (CpuConfigTdpLevel2Ratio - 1); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CONFIG_TDP_LEVEL2; + } + + return EFI_SUCCESS; +} + +/** + Get Power Limit2 based on Power Limit1 on Config TDP + + @param[in] PowerLimit1 Power Limit 1 Value + + @retval Calculated Power Limit2 value +**/ +UINT16 +GetCtdpPowerLimit2 ( + IN UINT16 PowerLimit1 + ) +{ + UINT16 ConvertedPowerLimit2; + UINT16 Mutliplier; + + /// + /// By default,for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP + /// + Mutliplier = 125; + /// + /// For XE/non-ULV skus Configure PL2 as (1.25 x cTDP). + /// + ConvertedPowerLimit2 = EFI_IDIV_ROUND ((Mutliplier * PowerLimit1), 100); + + return ConvertedPowerLimit2; +} + +/** + 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 Index; + UINTN TempRatio; + UINT8 Turbo; + + /// + /// Check P0 is Turbo Ratio or HFM + /// + Turbo = ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) ? 1 : 0); + + /// + /// Check and patch Fvid table for TAR ratios + /// + for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) { + TempRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar; + for (PssIndex = (Turbo + 2); PssIndex < FvidPointer[0].FvidHeader.Gv3States; PssIndex++) { + if (FvidPointer[PssIndex].FvidState.BusRatio < TempRatio) { + if (FvidPointer[PssIndex - 1].FvidState.BusRatio != TempRatio) { + /// + /// If Tar not Found ,Replace Turbo Active ratio at PssIndex-1 + /// P0 - Turbo ratio P1- HFM ,exclude these two ratios + /// + if (PssIndex == (Turbo + 2)) { + CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio); + DEBUG ((EFI_D_INFO, " TAR Ratio Replace at %x with %x \n", PssIndex, TempRatio)); + } else { + CtdpReplaceFvidRatio (FvidPointer, PssIndex - 1, TempRatio); + DEBUG ((EFI_D_INFO, " TAR Ratio Replace at %x with %x \n", PssIndex-1, 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 + /// + for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) { + TempRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar + 1; + for (PssIndex = (Turbo + 1); PssIndex < FvidPointer[0].FvidHeader.Gv3States; PssIndex++) { + + if (FvidPointer[PssIndex].FvidState.BusRatio == TempRatio) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex].FvidState.State; + } + + if (FvidPointer[PssIndex].FvidState.BusRatio < TempRatio) { + if (FvidPointer[PssIndex - 1].FvidState.BusRatio == TempRatio) { + /// + /// Found Turbo Active ratio at PssIndex-1 + /// + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex - 1].FvidState.State; + break; + } else { + /// + /// If Tar not Found, Replace Turbo Active ratio at PssIndex-1 + /// + if(PssIndex == (Turbo + 1)) { + CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex].FvidState.State; + DEBUG ((EFI_D_INFO, " CTDP Ratio Replace at %x with %x \n", PssIndex, TempRatio)); + } else { + CtdpReplaceFvidRatio (FvidPointer, PssIndex - 1, TempRatio); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex - 1].FvidState.State; + DEBUG ((EFI_D_INFO, " CTDP Ratio Replace at %x with %x \n", PssIndex-1, TempRatio)); + + } + break; + } + } + } + } +} + +/** + Replace P state with given ratio + + @param[in] 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 +**/ +VOID +CtdpReplaceFvidRatio ( + IN OUT FVID_TABLE *FvidPointer, + UINTN PssIndex, + UINTN Ratio + ) +{ + UINT64 wPower1; + UINT64 wPower2; + + FvidPointer[PssIndex].FvidState.BusRatio = (UINT16) Ratio; ///< Replace Ratio + /// + /// Relative Power calculation per HSW BWG + /// + 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; +} + +/** + 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) + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +ConfigurePowerLimitsNonConfigTdpSkus ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER PakagePowerLimitMsr; + UINT16 ConvertedPowerLimit1; + UINT8 ConvertedPowerLimit1Time; + UINT16 ConvertedShortDurationPowerLimit; + UINT16 CpuConvertedPowerLimit1MaxLimit; + UINT16 CpuConvertedPowerLimit2MaxLimit; + UINT16 Multiplier; + + 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 (mTdpLimitProgrammble) { + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_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 (CpuPmConfig->pTurboSettings->PowerLimit1 != AUTO) { + /// + /// CpuPmConfig->pTurboSettings->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) ((CpuPmConfig->pTurboSettings->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) ((CpuPmConfig->pTurboSettings->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; + } + } + } + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit1); + DEBUG ( + (EFI_D_INFO, + "New Power Limit 1 %d watt (%d in CPU power unit)\n", + CpuPmConfig->pTurboSettings->PowerLimit1, + ConvertedPowerLimit1) + ); + /// + /// Force Power Limit 1 override to be enabled + /// + PakagePowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE; + /// + /// 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 ((CpuPmConfig->pTurboSettings->PowerLimit1Time == AUTO) || + (CpuPmConfig->pTurboSettings->PowerLimit1Time > MAX_POWER_LIMIT_1_TIME_IN_SECONDS) + ) { + if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) { + /// + /// For Mobile, default value is 28 seconds + /// + CpuPmConfig->pTurboSettings->PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT; + } else { + /// + /// For Desktop, default value is 1 second + /// + CpuPmConfig->pTurboSettings->PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT; + } + } + ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit1Time, PL12TimeWindowCovert); + /// + /// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17] + /// + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_1_TIME_MASK; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit1Time, 17); + /// + /// 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] + /// + /// CpuPmConfig->pTurboSettings->PowerLimit2 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) ((CpuPmConfig->pTurboSettings->PowerLimit2 * mProcessorPowerUnit) / mCustomPowerUnit); + PakagePowerLimitMsr.Dwords.High &= ~(POWER_LIMIT_MASK | B_POWER_LIMIT_ENABLE); + /// + /// 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 (CpuPmConfig->pTurboSettings->PowerLimit2 == AUTO) { + ConvertedShortDurationPowerLimit = EFI_IDIV_ROUND ((Multiplier * mPackageTdp), 100); + + } + if (ConvertedShortDurationPowerLimit > CpuConvertedPowerLimit2MaxLimit) { + ConvertedShortDurationPowerLimit = CpuConvertedPowerLimit2MaxLimit; + } + if (ConvertedShortDurationPowerLimit < mPackageMinPower) { + ConvertedShortDurationPowerLimit = mPackageMinPower; + } + PakagePowerLimitMsr.Dwords.High |= (UINT32) (ConvertedShortDurationPowerLimit); + + if (CpuPmConfig->pFunctionEnables->PowerLimit2 == PPM_ENABLE) { + PakagePowerLimitMsr.Dwords.High |= B_POWER_LIMIT_ENABLE; + } else { + PakagePowerLimitMsr.Dwords.High &= (~B_POWER_LIMIT_ENABLE); + } + + DEBUG ( + (EFI_D_INFO, + "Short duration Power limit enabled, Power Limit = %d Watts\n", + CpuPmConfig->pTurboSettings->PowerLimit2) + ); + + DEBUG ((EFI_D_INFO,"MSR(610h)=%08X%08X\n",PakagePowerLimitMsr.Dwords.High,PakagePowerLimitMsr.Dwords.Low)); + + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); + } + + /// + /// Enable Power Clamp when Controllable TDP is enabled. + /// + if (mControllableTdpEnable) { + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + PakagePowerLimitMsr.Dwords.Low |= B_CRITICAL_POWER_CLAMP_ENABLE; + DEBUG ((EFI_D_INFO, "Critical Power Clamp1 enabled : %x\n",PakagePowerLimitMsr.Qword)); + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); + } + + /// + ///BIOS to override 41W PL1 for 47W 2C parts (Cahce Size = 3MB) + /// + if((CpuPmConfig->pTurboSettings->PowerLimit1 == AUTO) && (mPackageTdp == 47) && (mCpuCacheSize == 3 * 1024)) { + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) ((41 * mProcessorPowerUnit) & POWER_LIMIT_MASK); + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); + } + /// + /// PL1 and PL2 BIOS Overrides for 57W Non CTDP SKU + /// + if((CpuPmConfig->pTurboSettings->PowerLimit1 == AUTO) && + (CpuPmConfig->pTurboSettings->PowerLimit2 == AUTO) && + (mPackageTdp == 57 * mProcessorPowerUnit)) { + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + /// + /// PL1=67W + /// + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) ((67 * mProcessorPowerUnit) & POWER_LIMIT_MASK); + /// + /// PL2=83.75W + /// + PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.High |= (UINT32) (((8375 * mProcessorPowerUnit) / 100) & POWER_LIMIT_MASK); + + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); + } + // + // End if ((PlatformInfoMsr.Dwords.Low & B_EFI_PLATFORM_INFO_TDC_TDP_LIMIT)) + // + /// + /// Pass the power limits of the non-CTDP part to the Global NVS Area for use by DPTF + /// + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = (UINT16) (PakagePowerLimitMsr.Dwords.Low & POWER_LIMIT_MASK); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = (UINT16) (PakagePowerLimitMsr.Dwords.High & POWER_LIMIT_MASK); + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = (UINT8) CpuPmConfig->pTurboSettings->PowerLimit1Time; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpTar = (UINT8) mTurboBusRatio; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpCtc = 1; + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = 1; + mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = 0; +} + +/** + Configures following fields of MSR 0x615 + Configures power limit 3 power level and time window + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +ConfigurePL3PowerLimits ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER PlatformPowerLimitMsr; + UINT16 ConvertedPowerLimit3; + UINT8 ConvertedPowerLimit3Time; + CPU_STEPPING CpuSteppingId; + CPU_FAMILY CpuFamilyId; + + CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING; + + /// + /// PL3 is supported on HSW ULT C0 & HSW C0 and later + /// + if(((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) + || ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId >= EnumHswUltC0))) { + /// + /// Return if No user overrides selected. + /// + if((CpuPmConfig->pTurboSettings->PowerLimit3 == AUTO) + && (CpuPmConfig->pTurboSettings->PowerLimit3Time == AUTO) + && (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle == AUTO)){ + return; + } + + PlatformPowerLimitMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_POWER_LIMIT); + DEBUG ((EFI_D_INFO," PL3 MSR 615 Before Writing %x ",PlatformPowerLimitMsr.Dwords.Low)); + /// + /// Configure PL3 Power Limit if custom value is avaiable + /// + if (CpuPmConfig->pTurboSettings->PowerLimit3 != AUTO) { + ConvertedPowerLimit3 = (UINT16) ((CpuPmConfig->pTurboSettings->PowerLimit3 * mProcessorPowerUnit) / mCustomPowerUnit); + PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PlatformPowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit3); + PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE; + } + + /// + /// Configure PL3 Time window if custom value is avaiable + /// + if (CpuPmConfig->pTurboSettings->PowerLimit3Time != AUTO) { + ConvertedPowerLimit3Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit3Time, PL3TimeWindowConvert); + PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_3_TIME_MASK; + PlatformPowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit3Time, 17); + PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE; + } + + /// + /// Configure PL3 Duty Cycle if custom value is avaiable + /// + if (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle != AUTO) { + PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_3_DUTY_CYCLE_MASK; + PlatformPowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle, 24); + PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE; + } + // + // Enable/Disable PL3 lock + // + if (CpuPmConfig->pTurboSettings->PowerLimit3Lock == PPM_ENABLE) { + PlatformPowerLimitMsr.Dwords.Low |= (UINT32) B_POWER_LIMIT_LOCK; + }else { + PlatformPowerLimitMsr.Dwords.Low &= (~((UINT32) B_POWER_LIMIT_LOCK)); + } + + AsmWriteMsr64 (MSR_PLATFORM_POWER_LIMIT, PlatformPowerLimitMsr.Qword); + DEBUG ((EFI_D_INFO," PL3 MSR 615 After Writing %x ",PlatformPowerLimitMsr.Dwords.Low)); + } // End if Processor Check +} + +/** + 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) + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +ConfigureCtdpPowerLimits ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER PakagePowerLimitMsr; + UINT16 ConvertedPowerLimit1; + UINT16 ConvertedPowerLimit2; + UINT8 ConvertedPowerLimit1Time; + UINT16 Mutliplier; + UINTN Index; + CPU_FAMILY mCpuFamilyId; + + mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + ConvertedPowerLimit1Time = 0; + /// + /// By default, for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP + /// + Mutliplier = 125; + // + // For ConfigTdp enabled skus + // + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK; + /// + /// 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; + /// + /// Short duration Power Limit (PL2) = 1.25 * PL1 + /// + ConvertedPowerLimit2 = EFI_IDIV_ROUND ((Mutliplier * ConvertedPowerLimit1), 100); + if (ConvertedPowerLimit2 > PACKAGE_TDP_POWER_MASK) { + ConvertedPowerLimit2 = PACKAGE_TDP_POWER_MASK; + } + } else { + /// + /// Set Maximum value for Turbo Power Limit MSR [14:0] and [46:32] = + /// Max of CTDP Level Power Limts + /// + ConvertedPowerLimit1 = 0; + for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) { + if (ConvertedPowerLimit1 < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1) { + ConvertedPowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1; + } + } + ConvertedPowerLimit2 = 0; + for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) { + if (ConvertedPowerLimit2 < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2) { + ConvertedPowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2; + } + } + } + /// + /// 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 (CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom == PPM_ENABLE) { + ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[0].CustomPowerLimit1Time, PL12TimeWindowCovert); + } else { + if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) { + /// + /// For Mobile, default value is 28 seconds + /// + CpuPmConfig->pTurboSettings->PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT; + } else { + /// + /// For Desktop, default value is 1 second + /// + CpuPmConfig->pTurboSettings->PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT; + } + ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit1Time, PL12TimeWindowCovert); + } + /// + /// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17] + /// + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_1_TIME_MASK; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit1Time, 17); + PakagePowerLimitMsr.Dwords.High |= B_POWER_LIMIT_ENABLE; + PakagePowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit1); + PakagePowerLimitMsr.Dwords.High |= (UINT32) (ConvertedPowerLimit2); + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); +} + +/** + 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) + + @param[in] None +**/ +VOID +ConfigureCtdpPowerLimitsOverrides ( + ){ + UINTN Index; + UINTN NoOfOverrides; + CPU_FAMILY mCpuFamilyId; + UINT32 LibStatus; + UINT32 IccMaxValue; + EFI_STATUS Status; + UINTN PackageTdp; + MSR_REGISTER PakagePowerLimitMsr; + PPM_CTDP_OVERRIDE_TABLE *PpmCtdpOverideTable; + + mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + + if(mCpuFamilyId == EnumCpuHswUlt) { + PpmCtdpOverideTable = mHswUltPpmCtdpOverideTable; + NoOfOverrides = (sizeof(mHswUltPpmCtdpOverideTable))/(sizeof(PPM_CTDP_OVERRIDE_TABLE)); + }else { + return; + } + + PackageTdp = (mPackageTdpWatt * 100); + if((mPackageTdp % mProcessorPowerUnit) !=0) { + PackageTdp += ((mPackageTdp % mProcessorPowerUnit)* 100) / mProcessorPowerUnit ; + } + + for(Index = 0; Index < NoOfOverrides;Index++,PpmCtdpOverideTable++) { + if(PpmCtdpOverideTable->SkuPackageTdp == PackageTdp) { + + if(PpmCtdpOverideTable->SkuIccMax) { + /// + /// If SkuIccMax is not Zero check ICC Max for SKU detection.if No match go to next entry. + /// Read Icc Max from BIOS P code Mail box + /// + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_ICC_MAX_CMD, &IccMaxValue, &LibStatus); + IccMaxValue = IccMaxValue & 0x0FFF; + IccMaxValue = IccMaxValue /8; + if ((Status == EFI_SUCCESS) && (IccMaxValue != 0) && (IccMaxValue != PpmCtdpOverideTable->SkuIccMax)) { + continue; + } + } + + DEBUG ((EFI_D_INFO, "PPM:: Ctdp BIOS PL1/PL2 Override Ctdp SKU Found :%d override table index :%d\n",PpmCtdpOverideTable->SkuPackageTdp,Index)); + /// + /// MSR Overrides + /// + PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + if(PpmCtdpOverideTable->MsrCtdpPowerLimit1) { + PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.Low |= ((PpmCtdpOverideTable->MsrCtdpPowerLimit1 * mProcessorPowerUnit)/100) & POWER_LIMIT_MASK; + } + if(PpmCtdpOverideTable->MsrCtdpPowerLimit2) { + PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK; + PakagePowerLimitMsr.Dwords.High |=((PpmCtdpOverideTable->MsrCtdpPowerLimit2 * mProcessorPowerUnit)/100) & POWER_LIMIT_MASK; + } + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword); + + /// + /// MMIO Overrides + /// + if(PpmCtdpOverideTable->CtdpNominalPowerLimit1) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpNominalPowerLimit1 * mProcessorPowerUnit)/100; + } + if(PpmCtdpOverideTable->CtdpNominalPowerLimit2) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpNominalPowerLimit2 * mProcessorPowerUnit)/100; + } + if(PpmCtdpOverideTable->CtdpDownPowerLimit1) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[1].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpDownPowerLimit1 * mProcessorPowerUnit)/100; + } + if(PpmCtdpOverideTable->CtdpDownPowerLimit2) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[1].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpDownPowerLimit2 * mProcessorPowerUnit)/100; + } + if(PpmCtdpOverideTable->CtdpDownPowerLimit1) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[2].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpUpPowerLimit1 * mProcessorPowerUnit)/100; + } + if(PpmCtdpOverideTable->CtdpUpPowerLimit2) { + mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[2].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpUpPowerLimit2 * mProcessorPowerUnit)/100; + } + break; + } + } +} + +/** + Configure cTDP BIOS MSRs to Boot Ctdp values + - Configures CONFIG_TDP_CONTROL MSR + - Configures TURBO_ACTIVATION_RATIO MSR + + @param[in] CpuPmConfig Pointer to policy protocol instance + @param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user +**/ +VOID +SelectCtdpLevel ( + IN POWER_MGMT_CONFIG *CpuPmConfig, + IN UINT8 CpuConfigTdpBootLevel + ) +{ + MSR_REGISTER TempMsr; + + /// + /// Select cTDP Nominal if Ctdp disabled or boot level not supported. + /// + if (CpuConfigTdpBootLevel == CONFIG_TDP_DEACTIVATE || CpuConfigTdpBootLevel >= mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported) { + CpuConfigTdpBootLevel = 0; + } + + mCpuConfigTdpBootRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpTar+1; + mPpmGlobalNvsAreaProtocol->Area->ConfigurablePpc = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPpc; + /// + /// Program the selected level 00:nominal,01:level1,10:level2 to + /// CONFIG TDP CONTROL MSR. + /// + TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_CONTROL); + if ((TempMsr.Qword & CONFIG_TDP_CONTROL_LOCK) == 0) { + TempMsr.Dwords.Low = (UINT16) TempMsr.Dwords.Low &~CONFIG_TDP_CONTROL_LVL_MASK; + TempMsr.Dwords.Low = (UINT16) TempMsr.Dwords.Low | (CpuConfigTdpBootLevel & CONFIG_TDP_CONTROL_LVL_MASK); + if (CpuPmConfig->pTurboSettings->ConfigTdpLock == PPM_ENABLE) { + TempMsr.Dwords.Low |= CONFIG_TDP_CONTROL_LOCK; + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL is locked\n")); + } + AsmWriteMsr64 (MSR_CONFIG_TDP_CONTROL, TempMsr.Qword); + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL=%x\n", TempMsr.Qword)); + } else { + DEBUG ((EFI_D_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. + /// + TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_ACTIVATION_RATIO); + if ((TempMsr.Qword & MSR_TURBO_ACTIVATION_RATIO_LOCK) == 0) { + TempMsr.Dwords.Low &= ~MSR_TURBO_ACTIVATION_RATIO_MASK; + TempMsr.Dwords.Low |= (UINT16) ((mCpuConfigTdpBootRatio-1) & MSR_TURBO_ACTIVATION_RATIO_MASK); + if (CpuPmConfig->pTurboSettings->ConfigTdpLock == PPM_ENABLE ) { + TempMsr.Dwords.Low |= MSR_TURBO_ACTIVATION_RATIO_LOCK; + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO is locked\n")); + } + AsmWriteMsr64 (MSR_TURBO_ACTIVATION_RATIO, TempMsr.Qword); + DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO=%x\n", TempMsr.Qword)); + } else { + DEBUG ((EFI_D_INFO, "PPM:: Could not write MSR_TURBO_ACTIVATION_RATIO\n")); + } +} + +/** + Configures the TURBO_POWER_LIMIT MMIO for Boot ConfigTdp Level + + @param[in] CpuPmConfig Pointer to policy protocol instance + @param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user +**/ +VOID +SelectCtdpPowerLimits ( + IN POWER_MGMT_CONFIG *CpuPmConfig, + IN UINT8 CpuConfigTdpBootLevel + ) +{ + UINTN PciD0F0RegBase; + UINTN MchBar; + UINT32 Data32And; + UINT32 Data32Or; + UINT16 PowerLimit1; + UINT16 PowerLimit2; + MSR_REGISTER TempMsr; + + /// + /// If Ctdp deactivate, Program MSRs to Nominal and MMIO to 0 to enable overclocking + /// + if (CpuConfigTdpBootLevel == CONFIG_TDP_DEACTIVATE) { + PowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1; + PowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2; + TempMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + TempMsr.Dwords.Low &= ~POWER_LIMIT_MASK; + TempMsr.Dwords.Low |= PowerLimit1; + TempMsr.Dwords.High &= ~POWER_LIMIT_MASK; + TempMsr.Dwords.High |= PowerLimit2; + AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, TempMsr.Qword); + return; + } + + /// + /// Select cTDP Nominal if Ctdp disabled or boot level not supported. + /// + if (CpuConfigTdpBootLevel >= mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported) { + CpuConfigTdpBootLevel = 0; + } + + PowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPowerLimit1; + PowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPowerLimit2; + /// + /// 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 + /// + PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0); + MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0; + /// + /// Read PowerLimit MSR + /// + TempMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT); + /// + /// Program cTDP Power Limit1 + /// + Data32And = (UINT32) ~(PACKAGE_TDP_POWER_MASK); + Data32Or = (UINT32) (PowerLimit1 | (TempMsr.Dwords.Low &~PACKAGE_TDP_POWER_MASK)); + MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, Data32And, Data32Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT), + 1, + (VOID *) (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT) + ); + /// + /// Program cTDP Power Limit2 + /// + Data32And = (UINT32) ~(PACKAGE_TDP_POWER_MASK); + Data32Or = (UINT32) (PowerLimit2 | (TempMsr.Dwords.High &~PACKAGE_TDP_POWER_MASK)); + MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT + 4, Data32And, Data32Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT + 4), + 1, + (VOID *) (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT + 4) + ); +} + + +/** + 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 + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +ConfigureDdrPowerLimits ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER DdrPowerLimitMsr; + UINTN PciD0F0RegBase; + UINTN MchBar; + + PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0); + MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0; + + DdrPowerLimitMsr.Qword = 0; + DdrPowerLimitMsr.Qword = MmioRead64 (MchBar + MMIO_DDR_RAPL_LIMIT); + + DEBUG ( + (EFI_D_INFO, + "DDR Power Limit 1 = %d\n", + DdrPowerLimitMsr.Dwords.Low & POWER_LIMIT_MASK) + ); + DEBUG ( + (EFI_D_INFO, + "DDR Power Limit 2 = %d\n", + DdrPowerLimitMsr.Dwords.High & POWER_LIMIT_MASK) + ); + + AsmWriteMsr64 (MSR_DDR_RAPL_LIMIT, DdrPowerLimitMsr.Qword); +} + +/** + Configures PowerLimits and Config TDP values + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +ConfigureCtdp ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + /// + /// Configure CTDP power limits.Refer Rev 0.6.0 BWG sec 16.7.1: Enabling Intel Configurable TDP support + /// + ConfigureCtdpPowerLimits (CpuPmConfig); + + /// + /// BIOS power limit overrides + /// Don't override if custom ctdp settings are provided. + /// + if (!CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) { + ConfigureCtdpPowerLimitsOverrides(); + } + /// + /// To avoid issues and race conditions it is recommended that the below order of be followed + /// - For TDP Up program the Config TDP Level followed by Power Limits + /// - For TDP down program the Power Limits followed by Config TDP level + /// + if (CpuPmConfig->pTurboSettings->ConfigTdpLevel == CONFIG_TDP_UP) { + SelectCtdpPowerLimits (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex); + SelectCtdpLevel (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex); + } else { + SelectCtdpLevel (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex); + SelectCtdpPowerLimits (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex); + } +} + +EFI_STATUS +InitControllableTdp ( + IN OUT POWER_MGMT_CONFIG *CpuPmConfig + ) +/** + Check for Ctrl TDP enabled SKUs and enable Controllable TDP + + @param[in] CpuPmConfig Pointer to policy protocol instance + + @exception EFI_UNSUPPORTED Controllable TDP not Supported + @retval EFI_SUCCESS Controllable TDP Supported +**/ +{ + UINTN CpuFamilyIndex; + UINTN CpuModelIndex; + UINT32 CtrlTdpSkuSize; + UINT8 CtrlTdpSkuDetected; + CHAR8 BrandIdString[MAXIMUM_CPU_BRAND_STRING_LENGTH + 1]; + CPU_FAMILY CpuFamilyId; + CPU_STEPPING CpuSteppingId; + EFI_CPUID_REGISTER CpuExtendedSupport; + EFI_CPUID_REGISTER CpuBrandString; + PPM_CTRL_TDP_SKU_TBL *CtrlTdpSku; + MSR_REGISTER TempMsr; +/// +/// Debug +/// + + CtrlTdpSkuDetected = 0; + CtrlTdpSkuSize = 0; + + CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING; + + if((CpuFamilyId == EnumCpuHswUlt) || (CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) { + CtrlTdpSku = mHswCtrlTdpSkuTable; + CtrlTdpSkuSize = 1; + }else { + return EFI_UNSUPPORTED; + } + + DEBUG ((EFI_D_ERROR, "\n Function InitControllableTdp \n")); + // + // Get CPU Brand String + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuExtendedSupport.RegEax, &CpuExtendedSupport.RegEbx, &CpuExtendedSupport.RegEcx, &CpuExtendedSupport.RegEdx); + AsmCpuid (CPUID_BRAND_STRING1, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx); + // + // Check if Brand ID String is supported or filled up + // + if (CpuExtendedSupport.RegEax == 0) { + return EFI_UNSUPPORTED; + } + CopyMem ((CHAR8 *) &BrandIdString[0],(CHAR8 *) &CpuBrandString,16); + AsmCpuid (CPUID_BRAND_STRING2, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx); + CopyMem ((CHAR8 *) &BrandIdString[16],(CHAR8 *) &CpuBrandString,16); + AsmCpuid (CPUID_BRAND_STRING3, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx); + CopyMem ((CHAR8 *) &BrandIdString[31],(CHAR8 *) &CpuBrandString,16); + BrandIdString[MAXIMUM_CPU_BRAND_STRING_LENGTH] = 0; + + // + // Check for Match with Controllable TDP SKU list + // + for(CpuFamilyIndex = 0;CpuFamilyIndex < CtrlTdpSkuSize;CpuFamilyIndex++) { + if(EfiAsciiStrStr((CHAR8 *) BrandIdString, (CHAR8 *) CtrlTdpSku[CpuFamilyIndex].CpuFamily)) { + // + // If NoOfCpus=0xff ,all processors in the family are ULV skus + // + if(CtrlTdpSku[CpuFamilyIndex].NoOfCpus == 0xFF) { + CtrlTdpSkuDetected = 1; + DEBUG ((EFI_D_ERROR, "\n Found Control TDP SKU")); + break; + } + for(CpuModelIndex = 0;CpuModelIndex < CtrlTdpSku[CpuFamilyIndex].NoOfCpus; CpuModelIndex++) { + if(EfiAsciiStrStr((CHAR8 *) BrandIdString,(CHAR8 *) CtrlTdpSku[CpuFamilyIndex].CpuModel[CpuModelIndex])) { + CtrlTdpSkuDetected = 1; + DEBUG ((EFI_D_ERROR, "\n Found Control TDP SKU")); + break; + } + } // end of CpuModelIndex + break; + } + } // end of if CpuFamilyIndex + + /// + /// Enable Controllable TDp when + /// Power Limt1 is less than Package Tdp + /// Min Power is Zero + /// + if (CpuPmConfig->pTurboSettings->PowerLimit1 != AUTO && (CpuPmConfig->pTurboSettings->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit < mPackageTdp + && (mPackageMinPower == 0) && (CtrlTdpSkuDetected == 1)){ + mControllableTdpEnable = 1; + // + // For ControllableTDP enabled systems add fake P-State below LFM and set PPC as LFM + // + mMinBusRatio = mMinBusRatio - 1; + // + // Set TAR MSR to LFM-1 (Fake LFM) + // + TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_ACTIVATION_RATIO); + TempMsr.Dwords.Low &= ~MSR_TURBO_ACTIVATION_RATIO_MASK; + TempMsr.Dwords.Low |= (UINT16)((mMinBusRatio) & MSR_TURBO_ACTIVATION_RATIO_MASK); + DEBUG ((EFI_D_INFO, "\n Wrting MSR_TURBO_ACTIVATION_RATIO : %x \n",TempMsr.Qword)); + AsmWriteMsr64 (MSR_TURBO_ACTIVATION_RATIO, TempMsr.Qword); + } + return EFI_SUCCESS; +} + |