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/IdleStates.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c')
-rw-r--r-- | ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c | 918 |
1 files changed, 918 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c b/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c new file mode 100644 index 0000000..a450b5d --- /dev/null +++ b/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c @@ -0,0 +1,918 @@ +/** @file + This file contains power management C State 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 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PowerMgmtCommon.h" + +/** + Initializes C States Power management features + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +InitializeCState ( + IN POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + EFI_STATUS Status; + UINT16 mAcpiBaseAddr; + /// + /// Get the ACPI Base Address + /// + mAcpiBaseAddr = PchLpcPciCfg16 (R_PCH_LPC_ACPI_BASE) & 0xFFFE; + + /// + /// Initialize C states, some are general, some are processor specific. + /// Dynamic loading of CST SSDT tables occurs at PpmPostInit. + /// + EnableCStates (mAcpiBaseAddr + PM_CST_LVL2); + /// + /// Calibrate C State 24MHz BCLK + /// +//@todo: Need to finalize on whether or not re-calibration option should be provided + Status = CalibrateBclkForCStates (); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_INFO, "24MHz BCLK calibration Failed \n")); +//@todo: Need to finalize on how to handle failure of 24 MHz calibration + } + + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) { + /// + /// Update Fadt table for C State support. + /// + ConfigureFadtCStates (); + } + InitCstatePreWake (mCpuPmConfig); + +} + +/** + Disable/Enable the CState Pre-Wake Feature + + @param[in] CpuPmConfig Pointer to policy protocol instance +**/ +VOID +InitCstatePreWake ( + IN POWER_MGMT_CONFIG *CpuPmConfig + ) +{ + MSR_REGISTER TempMsr; + + TempMsr.Qword = AsmReadMsr64 (MSR_POWER_CTL); + TempMsr.Dwords.Low &= ~(B_MSR_POWER_CTL_CSTATE_PRE_WAKE_DISABLE); + if (CpuPmConfig->pFunctionEnables->CStatePreWake == PPM_DISABLE) { + TempMsr.Dwords.Low |= B_MSR_POWER_CTL_CSTATE_PRE_WAKE_DISABLE; + } + AsmWriteMsr64 (MSR_POWER_CTL, TempMsr.Qword); + + return; +} + +/** + Enables C-State support as specified by the input flags on all logical + processors and sets associated timing requirements in the chipset. + + @param[in] C3IoAddress IO address to generate C3 states (PM base + 014 usually) +**/ +VOID +EnableCStates ( + IN UINT16 C3IoAddress + ) +{ + MSR_REGISTER PowerCtl; + MSR_REGISTER TempMsr; + UINT32 LCR0Latency; + UINT32 LCR1Latency; + UINT32 LCR2Latency; + UINT32 LCR3Latency; + UINT32 LCR4Latency; + UINT32 LCR5Latency; + UINT16 EnableCStateParameters; + CPU_FAMILY mCpuFamilyId; + + mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + /// + /// Load the C-State parameters to pass to the core function. + /// + EnableCStateParameters = C3IoAddress; + /// + /// Enable C-States on all logical processors. + /// + RunOnAllLogicalProcessors (ApSafeEnableCStates, &EnableCStateParameters); + /// + /// If C-states are disabled or not supported, Disable C1e and retrun + /// + if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) == 0) { + PowerCtl.Qword = AsmReadMsr64 (MSR_POWER_CTL); + PowerCtl.Dwords.Low &= ~B_MSR_POWER_CTL_C1E; + AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Qword); + DEBUG ( + (EFI_D_INFO, + "Setup C state disabled.Disable C1e. MSR(1FC) : %X %X\n", + PowerCtl.Dwords.High, + PowerCtl.Dwords.Low) + ); + return; + } + /// + /// Configure supported enhanced C-states + /// + /// Read Power Ctl MSR + /// + PowerCtl.Qword = AsmReadMsr64 (MSR_POWER_CTL); + DEBUG ((EFI_D_INFO, "MSR(1FC) before configuring C1E: %X %X\n", PowerCtl.Dwords.High, PowerCtl.Dwords.Low)); + /// + /// Enable supported states + /// + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C1E) { + PowerCtl.Dwords.Low |= B_MSR_POWER_CTL_C1E; + } else { + PowerCtl.Dwords.Low &= ~B_MSR_POWER_CTL_C1E; + } + /// + /// Update Power Control MSR + /// + AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Qword); + DEBUG ((EFI_D_INFO, "MSR(1FC) after configuring C1E: %X %X\n", PowerCtl.Dwords.High, PowerCtl.Dwords.Low)); + /// + /// Program Interrupt response time limits used by processor to decided when to get into + /// package C3, C6 and C7 + /// + DEBUG ((EFI_D_INFO, "Programming the 0xC3/C6/C7 (MSR 0x60A, 0x60B ,0X60C Latencies \n")); + // + // Package C3 Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_0); + DEBUG ((EFI_D_INFO, "MSR(60A) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x60A + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl0Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl0TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_0, TempMsr.Qword); + // + // Package C6/C7 short Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_1); + DEBUG ((EFI_D_INFO, "MSR(60B) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x60B + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl1Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl1TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_1, TempMsr.Qword); + // + // Package C6/C7 long Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_2); + DEBUG ((EFI_D_INFO, "MSR(60C) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x60C + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl2Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl2TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_2, TempMsr.Qword); + if (mCpuFamilyId == EnumCpuHswUlt) { + // + // Package C8 Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_3); + DEBUG ((EFI_D_INFO, "MSR(633) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x633 + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl3Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl3TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_3, TempMsr.Qword); + // + // Package C9 Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_4); + DEBUG ((EFI_D_INFO, "MSR(634) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x634 + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl4Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl4TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_4, TempMsr.Qword); + // + // Package C10 Interrupt response time + // + TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_5); + DEBUG ((EFI_D_INFO, "MSR(635) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low)); + TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID); + /// + /// Program Interrupt Response Time Unit and Latency for MSR 0x635 + /// + TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl5Irtl; + TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl5TimeUnit, N_TIME_UNIT_OFFSET); + TempMsr.Dwords.Low |= B_PKG_IRTL_VALID; + AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_5, TempMsr.Qword); + } + /// + /// Update the PPM Global NVS Area + /// + LCR0Latency = (1 << (mCpuPmConfig->CstateLatencyControl0TimeUnit * 5)); + LCR0Latency = (LCR0Latency * mCpuPmConfig->CstateLatencyControl0Irtl) / 1000; + // + // _CST Latency: WordConst, so limit the latency value to max 0xFFFF + // + if (LCR0Latency > 0xFFFF) { + LCR0Latency = 0xFFFF; + } + LCR1Latency = (1 << (mCpuPmConfig->CstateLatencyControl1TimeUnit * 5)); + LCR1Latency = (LCR1Latency * mCpuPmConfig->CstateLatencyControl1Irtl) / 1000; + if (LCR1Latency > 0xFFFF) { + LCR1Latency = 0xFFFF; + } + LCR2Latency = (1 << (mCpuPmConfig->CstateLatencyControl2TimeUnit * 5)); + LCR2Latency = (LCR2Latency * mCpuPmConfig->CstateLatencyControl2Irtl) / 1000; + if (LCR2Latency > 0xFFFF) { + LCR2Latency = 0xFFFF; + } + + LCR3Latency = (1 << (mCpuPmConfig->CstateLatencyControl3TimeUnit * 5)); + LCR3Latency = (LCR3Latency * mCpuPmConfig->CstateLatencyControl3Irtl) / 1000; + if (LCR3Latency > 0xFFFF) { + LCR3Latency = 0xFFFF; + } + + LCR4Latency = (1 << (mCpuPmConfig->CstateLatencyControl4TimeUnit * 5)); + LCR4Latency = (LCR4Latency * mCpuPmConfig->CstateLatencyControl4Irtl) / 1000; + if (LCR4Latency > 0xFFFF) { + LCR4Latency = 0xFFFF; + } + + LCR5Latency = (1 << (mCpuPmConfig->CstateLatencyControl5TimeUnit * 5)); + LCR5Latency = (LCR5Latency * mCpuPmConfig->CstateLatencyControl5Irtl) / 1000; + if (LCR5Latency > 0xFFFF) { + LCR5Latency = 0xFFFF; + } + + /// + /// Update the PPM Global NVS Area. + /// Update the PPM NVRAM values for C3 + /// + mPpmGlobalNvsAreaProtocol->Area->C3MwaitValue = 0x10; + mPpmGlobalNvsAreaProtocol->Area->C3Latency = (UINT16) LCR0Latency; + /// + /// Update PPM NVRAM Values for C6 + /// + if ((mCpuPmConfig->pFunctionEnables->LongLatencyC6) &&( mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C6_LONG_LATENCY_ENABLE)) { + mPpmGlobalNvsAreaProtocol->Area->C6MwaitValue = 0x21; + mPpmGlobalNvsAreaProtocol->Area->C6Latency = (UINT16) LCR2Latency; + } else { + mPpmGlobalNvsAreaProtocol->Area->C6MwaitValue = 0x20; + mPpmGlobalNvsAreaProtocol->Area->C6Latency = (UINT16) LCR1Latency; + } + /// + /// Update PPM NVRAM Values for C7 - select the C-state supported among- C7 / C7S + /// + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7) { // Is C7 supported ? + if ((mCpuPmConfig->pFunctionEnables->LongLatencyC7) && (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C7_LONG_LATENCY_ENABLE)) { + mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x31; + mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR2Latency; + } else { + mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x30; + mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR1Latency; + } + } + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7S) { // Is C7S supported ? + if ((mCpuPmConfig->pFunctionEnables->LongLatencyC7) && (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C7s_LONG_LATENCY_ENABLE)) { + mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x33; + mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR2Latency; + } else { + mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x32; + mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR1Latency; + } + } + /// + /// Update PPM NVRAM Values for CD - select the deepest C-state supported among- C8 / C9 / C10 + /// + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) { // C10 supported + mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV7; + mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C10_POWER; + mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x60; + mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR5Latency; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) { // C9 supported + mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV6; + mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C9_POWER; + mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x50; + mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR4Latency; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) { // C8 supported + mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV5; + mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C8_POWER; + mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x40; + mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR3Latency; + } + + return; +} + +/** + BootScript for PCode Mailbox function for mailbox write commands. + This function will poll the mailbox interface for control, issue the command + during s3 resume + + @param[IN] MailboxCommand, + @param[IN] MailboxData, +**/ +VOID +MailboxS3Write ( + IN UINT32 MailboxCommand, + IN UINT32 MailboxData + ) +{ +#ifdef ULT_FLAG + UINT32 Data32Mask; + UINT32 Data32Value; + UINT16 StallCount; + UINT32 MchBar; + + StallCount = 0; + + /// + /// Poll the run/busy to ensure the interface is available + /// + Data32Mask = BIT31; + Data32Value = 0; + MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0); + SCRIPT_MEM_POLL ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET), + &Data32Mask, + &Data32Value, + MAILBOX_WAIT_STALL, + MAILBOX_WAIT_TIMEOUT + ); + + /// + /// Write the PCODE mailbox DATA field + /// + MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) ((MchBar + PCODE_MAILBOX_DATA_OFFSET)), + 1, + &(MailboxData) + ); + /// + /// Write the PCODE mailbox Command field + /// + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET), + 1, + &(MailboxCommand) + ); +#endif // ULT_FLAG + return; +} + +/** + Calibrate 24MHz BCLK support to reduce the power consumption in idle states. + + @retval EFI_UNSUPPORTED Unrecognized 24MHz BCLK Calibration Type. + @retval EFI_SUCCESS Processor C-State 24MHz BCLK support calibrated successfully. +**/ +EFI_STATUS +CalibrateBclkForCStates ( + VOID + ) +{ + /***************************************************************************************************************** + - BIOS can choose to configure the conversion factor or allow PCODE to calibrate itself or have NO calibration at all. + - If NO Calibration then the below steps are needed + o BIOS should bypass all calibration process and write a constant value via "WRITE convert ratio" + - If BIOS chooses PCODE calibration then the below steps are needed + o BIOS writes FSM interval: A value of all Fs is recommended for this + o Read PCODE calibration factor + o Store and use if needed on next Power up for BIOS calibration + - If BIOS chooses to calibrate itself then the below steps are needed + o Send command for calibration to prevent BCLK shut off + o Read TSC counter values (send command for atomic sampling of TSC100 and TSC24, then read the values) + o Delay (what is the maximum tolerable delay?) + o Read counters again + o Divide 100 MHz ticks by 24 MHz ticks to get the calibration factor + o Store the calibration factor value + o Write calibration factor using mailbox command during subsequent power-ups + + Command: Command Name: Description: + 0x80000009 WriteTsc24_100Cmd Sample 24 MHz and 100 MHz TSC simultaneously + 0x80000109 ReadTsc24LowerCmd Read lower 32 bits of 24 MHz TSC + 0x80000209 ReadTsc24UpperCmd Read upper 32 bits of 24 MHz TSC + 0x80000309 ReadTsc100LowerCmd Read lower 32 bits of 100 MHz TSC + 0x80000409 ReadTsc100UpperCmd Read upper 32 bits of 100 MHz TSC + 0x80000509 ReadPcodeCalibratedCmd Read PCODE calibrated conversion factor + 0x80000609 WriteConversionRatioCmd Command for writing the conversion ratio + 0x80000709 WritePreventBclkOffCmd Command for calibration prevents BCLK from shutting off and prevents package + from entering deep C states + 0x80000809 WRITE_MEASURE_INTERVAL_CMD Measurement interval for pCode calibration of TSC24-to-TSC100 conversion factor + 0x80000909 WriteFsmMeasureIntvlCmd Write FSM measure interval + 0x85000000 StartCalValue Constant value to start calibration + 0xFFFFFFFF PcodeIntervalValue PCODE flow calibration time value + + ***************************************************************************************************************/ + + EFI_STATUS Status = EFI_SUCCESS; + +#ifdef ULT_FLAG + CPU_FAMILY mCpuFamilyId; + mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + if (mCpuFamilyId == EnumCpuHswUlt) { + UINT32 PcodeIntervalValue; + UINT32 BiosMeasureIntervalValue; + UINT32 PcalFactor_Lower; + UINT32 PcalFactor_Upper; + UINT32 LibStatus; + UINT64 Tsc24_64; + UINT64 Tsc100_64; + UINT64 Temp24_64; + UINT64 Temp100_64; + UINT64 PcalFactor; + UINT64 SafeCalibrationValue; + UINT64 TscRemainder; + + PCODE_BCLK_CALIBRATION_MAILBOX ReturnCalVal; + + PcodeIntervalValue = 0xFFFFFFFF; + BiosMeasureIntervalValue = 0x7270E00; + PcalFactor_Lower = 0x0; + PcalFactor_Upper = 0x0; + Tsc24_64 = 0x0; + Tsc100_64 = 0x0; + Temp24_64 = 0x0; + Temp100_64 = 0x0; + PcalFactor = 0x0; + SafeCalibrationValue = 0x0; + TscRemainder = 0x0; + LibStatus = 0x0; + DEBUG ((EFI_D_INFO, "Initializing 24MHz BCLK calibration \n")); + + switch (mCpuPmConfig->PcodeCalibration) { + case NO_CALIBRATE: + /// + /// Bypass all calibration process + /// + DEBUG ((EFI_D_INFO, "Bypass the 24MHz BCLK calibration \n")); + /// + /// Write a constant value + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_CONVERTION_RATIO_CMD, START_CAL_VALUE, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed to write a constant value \n")); + break; + } + MailboxS3Write(WRITE_CONVERTION_RATIO_CMD, START_CAL_VALUE); + break; + + case PCODE_CALIBRATE: + /// + /// Initiate the PCODE calibration + /// + DEBUG ((EFI_D_INFO, "Initiate PCODE 24MHz BCLK calibration \n")); + /// + /// BIOS writes FSM interval: A value of all F's is recommended for this + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_FSM_MEASURE_INTVL_CMD, PcodeIntervalValue, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed BIOS writes FSM interval \n")); + break; + } + MailboxS3Write(WRITE_FSM_MEASURE_INTVL_CMD, PcodeIntervalValue); + break; + + case BIOS_CALIBRATE: + /// + /// Initiate Bios calibration + /// + DEBUG ((EFI_D_INFO, "Initiate BIOS 24MHz BCLK calibration \n")); + /// + /// Send command for calibration to prevent BCLK shut off + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_PREVENT_BCLKOFF_CMD, 1, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to prevent BCLK shut off \n")); + break; + } + /// + /// Read TSC counter values (send command for atomic sampling of TSC100 and TSC24) + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, SAMPLE_TSC_24AND100_CMD, 0, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First Write TSC counter values (send command for atomic sampling of TSC100 and TSC24) \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_LOWER_CMD, &ReturnCalVal.TSC24_L1, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-24 Lower 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_UPPER_CMD, &ReturnCalVal.TSC24_U1, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-24 Upper 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_LOWER_CMD, &ReturnCalVal.TSC100_L1, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-100 Lower 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_UPPER_CMD, &ReturnCalVal.TSC100_U1, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-100 Upper 32 bits \n")); + break; + } + /// + /// Store initial clock values + /// + Tsc24_64 = ((UINT64)ReturnCalVal.TSC24_U1 << 32); + Temp24_64 = (Tsc24_64 |= (ReturnCalVal.TSC24_L1)); + Tsc100_64 = ((UINT64)ReturnCalVal.TSC100_U1 << 32); + Temp100_64 = (Tsc100_64 |= (ReturnCalVal.TSC100_L1)); + + /// + /// Delay for 22 ms + /// + gBS->Stall (PCODE_BCLK_CALIBRATION_TIMEOUT * STALL_ONE_MILLI_SECOND); + + /// + /// Read TSC 24 and TSC 100 counters again, and calculate calibration factor + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, SAMPLE_TSC_24AND100_CMD, 0, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second Write TSC counter values (send command for atomic sampling of TSC100 and TSC24) \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_LOWER_CMD, &ReturnCalVal.TSC24_L2, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-24 Lower 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_UPPER_CMD, &ReturnCalVal.TSC24_U2, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-24 Upper 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_LOWER_CMD, &ReturnCalVal.TSC100_L2, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-100 Lower 32 bits \n")); + break; + } + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_UPPER_CMD, &ReturnCalVal.TSC100_U2, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Second read TSC-100 Upper 32 bits \n")); + break; + } + /// + /// Store current clock values, and calculate difference + /// + Tsc24_64 = ((UINT64)ReturnCalVal.TSC24_U2 << 32); + Tsc24_64 = ((Tsc24_64 |= (ReturnCalVal.TSC24_L2)) - Temp24_64); + Tsc100_64 = ((UINT64)ReturnCalVal.TSC100_U2 << 32); + Tsc100_64 = ((Tsc100_64 |= (ReturnCalVal.TSC100_L2)) - Temp100_64); + + /// + /// Calculate updated conversion factor in fixed point format (U32.3.29) + /// + Tsc100_64 = (Tsc100_64 << 29); + if (Tsc24_64 !=0) { + PcalFactor = InternalMathDivRemS64x64 (Tsc100_64, Tsc24_64, (INT64 *) &TscRemainder); + } + + /// + /// Read the TSC24-to-TSC100 conversion factor currently in use by pCode + /// + Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_PCODE_CALIBRATED_CMD, &ReturnCalVal.PCalFactor, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed read TSC24-to-TSC100 PCalFactor from pCode currently\n")); + break; + } + + if (PcalFactor <= 0) { + /// + /// Set Safe Calibration Value as ReturnCalVal.PCalFactor which is TSC24-to-TSC100 PCalFactor read from pCode by READ_PCODE_CALIBRATED_CMD + /// + PcalFactor = ReturnCalVal.PCalFactor; + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Warning - SafeCalibrationValue used \n")); + } + PcalFactor_Lower |= PcalFactor; + PcalFactor_Upper |= (PcalFactor >> 32); + /// + /// Calibrate 24MHz BCLK using the calculated calibration factor value + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_CONVERTION_RATIO_CMD, PcalFactor_Lower, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Calibrate 24MHz BCLK using the calculated lower calibration factor value \n")); + break; + } + MailboxS3Write(WRITE_CONVERTION_RATIO_CMD, PcalFactor_Lower); + + /// + /// Send command for calibration to turn BCLK on + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_PREVENT_BCLKOFF_CMD, 0, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to turn BCLK on \n")); + break; + } + MailboxS3Write(WRITE_PREVENT_BCLKOFF_CMD, 0); + + /// + /// Write measurement interval for pCode calibration of TSC24-to-TSC100 conversion factor + /// + Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_MEASURE_INTERVAL_CMD, BiosMeasureIntervalValue, &LibStatus); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to meature interval for pCode calibration \n")); + break; + } + MailboxS3Write(WRITE_MEASURE_INTERVAL_CMD, BiosMeasureIntervalValue); + break; + + default: + DEBUG ((EFI_D_ERROR, "Unrecognized 24MHz BCLK Calibration Type \n")); + Status = EFI_UNSUPPORTED; + break; + } + + DEBUG ((EFI_D_INFO, "24MHz BCLK calibration completed \n")); + + } +#endif // ULT_FLAG + + return Status; +} + +/** + Enable C-State support as specified by the input flags on a logical processor. + Configure BIOS C1 Coordination (SMI coordination) + Enable IO redirection coordination + Choose proper coordination method + Configure extended C-States + + This function must be MP safe. + + @param[in] Buffer Pointer to a ENABLE_CSTATE_PARAMS containing the necessary + information to enable C-States + + @retval EFI_SUCCESS Processor C-State support configured successfully. +**/ +VOID +EFIAPI +ApSafeEnableCStates ( + IN OUT VOID *Buffer + ) +{ + MSR_REGISTER Ia32MiscEnable; + MSR_REGISTER PmCfgCtrl; + MSR_REGISTER IoCaptAddr; + UINT16 C3IoAddress; + CPU_STEPPING mCpuSteppingId; + CPU_FAMILY mCpuFamilyId; + mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL; + mCpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING; + /// + /// Extract parameters from the buffer + /// + C3IoAddress = *((UINT16 *) Buffer); + /// + /// If C-states are disabled in setup, disable C-states + /// + if (!(mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES)) { + PmCfgCtrl.Qword = AsmReadMsr64 (MSR_PMG_CST_CONFIG); + PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT; + AsmWriteMsr64 (MSR_PMG_CST_CONFIG, PmCfgCtrl.Qword); + return; + } + /// + /// Set C-state package limit to the highest C-state enabled + /// + PmCfgCtrl.Qword = AsmReadMsr64 (MSR_PMG_CST_CONFIG); + if (mCpuPmConfig->PkgCStateLimit != PkgCpuDefault) { + PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT; + + if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C10; + } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C9; + } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C8; + } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7S) && + !((mCpuFamilyId == EnumCpuHsw) && (mCpuSteppingId == EnumHswA0) && (mCpuPmConfig->PkgCStateLimit == PkgAuto))) { // When user selects Auto - Disable Package C7s state on Haswell A-step processors + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C7S; + } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7)&& + !((mCpuFamilyId == EnumCpuHsw) && (mCpuSteppingId == EnumHswA0) && (mCpuPmConfig->PkgCStateLimit == PkgAuto))) { // When user selects Auto - Disable Package C7 state on Haswell A-step processors + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C7; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C6) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C6; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C3; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C1) { + PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C1; + } + if (mCpuPmConfig->PkgCStateLimit < PkgCMax) { + PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT; + PmCfgCtrl.Dwords.Low |= (mCpuPmConfig->PkgCStateLimit & B_PACKAGE_C_STATE_LIMIT); + } + } + /// + /// Enable C State IO redirection by default + /// + PmCfgCtrl.Dwords.Low |= B_IO_MWAIT_REDIRECTION_ENABLE; + // + // Enable TimedMwait + // + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TIMED_MWAIT) { + PmCfgCtrl.Dwords.Low &= (~B_TIMED_MWAIT_ENABLE); + PmCfgCtrl.Dwords.Low |= B_TIMED_MWAIT_ENABLE; + } + /// + /// Configure C-state auto-demotion + /// + PmCfgCtrl.Dwords.Low &= ~(B_C1_AUTO_DEMOTION_ENABLE | B_C3_AUTO_DEMOTION_ENABLE); + if (mCpuPmConfig->pFunctionEnables->C3AutoDemotion) { + /// + /// Enable C6/C7 Auto-demotion to C3 + /// + PmCfgCtrl.Dwords.Low |= B_C3_AUTO_DEMOTION_ENABLE; + } + if (mCpuPmConfig->pFunctionEnables->C1AutoDemotion) { + /// + /// Enable C3/C6/C7 Auto-demotion to C1 + /// + PmCfgCtrl.Dwords.Low |= B_C1_AUTO_DEMOTION_ENABLE; + } + /// + /// Configure C-state un-demotion + /// + PmCfgCtrl.Dwords.Low &= ~(B_C1_AUTO_UNDEMOTION_ENABLE | B_C3_AUTO_UNDEMOTION_ENABLE); + if (mCpuPmConfig->pFunctionEnables->C3UnDemotion) { + /// + /// Enable un-demotion from demoted C3 + /// + PmCfgCtrl.Dwords.Low |= B_C3_AUTO_UNDEMOTION_ENABLE; + } + if (mCpuPmConfig->pFunctionEnables->C1UnDemotion) { + /// + /// Enable un-demotion from demoted C1 + /// + PmCfgCtrl.Dwords.Low |= B_C1_AUTO_UNDEMOTION_ENABLE; + } + /// + /// Configure Package C-state Demotion / un-demotion - Supported only on HSW B0 and Above + /// + if (mCpuSteppingId > EnumHswA0) { + PmCfgCtrl.Dwords.Low &= ~(B_PKG_CSTATE_DEMOTION_ENABLE | B_PKG_CSTATE_UNDEMOTION_ENABLE); + if (mCpuPmConfig->pFunctionEnables->PkgCStateDemotion) { + /// + /// Enable Package C-state Demotion + /// + PmCfgCtrl.Dwords.Low |= B_PKG_CSTATE_DEMOTION_ENABLE; + } + if (mCpuPmConfig->pFunctionEnables->PkgCStateUnDemotion) { + /// + /// Enable Package C-state un-demotion + /// + PmCfgCtrl.Dwords.Low |= B_PKG_CSTATE_UNDEMOTION_ENABLE; + } + } + AsmWriteMsr64 (MSR_PMG_CST_CONFIG, PmCfgCtrl.Qword); + /// + /// Enable MONITOR/MWAIT support + /// (already done on BSP, but must be done on all components.) + /// + Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE); + Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_MONITOR; + AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword); + /// + /// Haswell specific configuration of I/O capture and I/O coordination SMI MSR. + /// Configure the base port and range in the MSR to match LVL_X settings in ACPI tables + /// Set I/O capture base port and range + /// + IoCaptAddr.Qword = AsmReadMsr64 (MSR_PMG_IO_CAPTURE_BASE); + /// + /// Mask off CST range and set the CST range + /// + IoCaptAddr.Dwords.Low &= ~B_MSR_PMG_CST_RANGE; + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL7; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL6; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL5; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL4; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C6) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL3; + } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) { + IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL2; + } + /// + /// Set the base CST address + /// + IoCaptAddr.Dwords.Low &= ~(V_IO_CAPT_LVL2_BASE_ADDR_MASK); + IoCaptAddr.Dwords.Low |= C3IoAddress; + AsmWriteMsr64 (MSR_PMG_IO_CAPTURE_BASE, IoCaptAddr.Qword); + return; +} + + +// +// Update ACPI IdleStates tables +// + +/** + Configure the FACP for C state support +**/ +VOID +ConfigureFadtCStates ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_DESCRIPTION_HEADER *Table; + EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer; + INTN Index; + UINTN Handle; + EFI_ACPI_TABLE_VERSION Version; + + /// + /// Locate table with matching ID + /// + Index = 0; + do { + Status = mAcpiSupport->GetAcpiTable (mAcpiSupport, Index, (VOID **) &Table, &Version, &Handle); + if (Status == EFI_NOT_FOUND) { + break; + } + ASSERT_EFI_ERROR (Status); + Index++; + } while (Table->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE); + // + // Can't have ACPI without FADT, so safe to assert + // + ASSERT (Table->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE); + FadtPointer = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) Table; + // + // Verify expected state. Should be initialized to off during build. + // + ASSERT (FadtPointer->PLvl3Lat >= FADT_C3_LATENCY_DISABLED); + /// + /// Configure C states + /// + if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) { + /// + /// Enable C3 in FADT. + /// + FadtPointer->PLvl3Lat = FADT_C3_LATENCY; + } + /// + /// Update the table + /// + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + Table, + Table->Length, + &Handle + ); + FreePool (Table); + + return; +}
\ No newline at end of file |