diff options
Diffstat (limited to 'ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c')
-rw-r--r-- | ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c | 1536 |
1 files changed, 1536 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c b/ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c new file mode 100644 index 0000000..38dad6c --- /dev/null +++ b/ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c @@ -0,0 +1,1536 @@ +/** @file + Digital Thermal Sensor (DTS) driver. + This SMM driver configures and supports the Digital Thermal Sensor features for the platform. + +@copyright + Copyright (c) 1999 - 2012 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 "DigitalThermalSensorSmm.h" +#include "KscLib.h" +// +// Protocol GUID definition +// +DXE_CPU_PLATFORM_POLICY_PROTOCOL *mPlatformCpu = NULL; + +EFI_GUID gDtsInitStatusProtocolGuid = DTS_INIT_STATUS_PROTOCOL_GUID; +EFI_GUID mEfiGlobalNvsAreaProtocolGuid = EFI_GLOBAL_NVS_AREA_PROTOCOL_GUID; +EFI_GUID mEfiSmmIoTrapDispatchProtocolGuid = EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID; +DTS_INIT_STATUS_PROTOCOL mDtsInitStatusProtocol; + +// +// Global variables +// +EFI_SMM_BASE_PROTOCOL *mSmmBase; +EFI_SMM_SYSTEM_TABLE *mSmst; + +EFI_GLOBAL_NVS_AREA *mGlobalNvsAreaPtr; +UINT8 DTSSetupValue; + +BOOLEAN mDtsEnabled; +UINT8 mDtsTjMax; +UINT16 mAcpiBaseAddr; +BOOLEAN mUpdateDtsInEverySmi; +UINT8 mNoOfThresholdRanges; +UINT8 (*mDtsThresholdTable)[3]; +UINT8 gIsPackageTempMsrAvailable; +/// +/// The table is updated for the current CPU. +/// +UINT8 mDigitalThermalSensorThresholdTable[DTS_NUMBER_THRESHOLD_RANGES][3] = { + /// + /// TJ_MAX = 110 ///< Current Temp. Low Temp. High Temp. + /// + {TJ_MAX-80,100,75}, ///< <= 30 10 35 + {TJ_MAX-70,85,65}, ///< 30 ~ 39 25 45 + {TJ_MAX-60,75,55}, ///< 40 ~ 49 35 55 + {TJ_MAX-50,65,45}, ///< 50 ~ 59 45 65 + {TJ_MAX-40,55,35}, ///< 60 ~ 69 55 75 + {TJ_MAX-30,45,25}, ///< 70 ~ 79 65 85 + {TJ_MAX-20,35,15}, ///< 80 ~ 89 75 95 + {TJ_MAX-10,25,05}, ///< 90 ~ 99 85 105 + {TJ_MAX-00,15,00} ///< 100 ~ 109 95 110 +}; + +// +// Function implementations +// +/** + Read the temperature data per core/thread. + This function must be AP safe. + + @param[in] Buffer Pointer to UINT8 to update with the current temperature + + @retval EFI_SUCCESS Digital Thermal Sensor temperature has updated successfully. +**/ +VOID +EFIAPI +DigitalThermalSensorUpdateTemperature ( + VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + UINT8 Temperature; + UINT8 DefApicId; + EFI_CPUID_REGISTER CpuidRegisters; + UINT8 *TempPointer; + + AsmCpuid ( + EFI_CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + /// + /// Default APIC ID = CPUID Function 01, EBX[31:24] + /// + DefApicId = (UINT8) RShiftU64 (CpuidRegisters.RegEbx, 24); + + /// + /// Read the temperature + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_STATUS); + + /// + /// Find the DTS temperature. + /// + Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK); + /// + /// We only update the temperature if it is above the current temperature. + /// + TempPointer = Buffer; + if (Temperature > *((UINT8 *) (TempPointer + DefApicId))) { + *((UINT8 *) (TempPointer + DefApicId)) = Temperature; + } + + return; +} + +/** + Read the temperature and update the data for PTID support. + + @retval EFI_SUCCESS Digital Thermal Sensor temperature has updated successfully. +**/ +EFI_STATUS +DigitalThermalSensorUpdatePTID ( + VOID + ) +{ + /// + /// ThreadTemperatureBuffer[0], [2], [4] and [6] are Thread0 and [1], [3], [5] and [7] are Thread1 for each Core. + /// If thread or core not active, this thread/core temperature will be reported as 0 + /// + UINT8 ThreadTemperatureBuffer[MAX_NUMBER_OF_THREADS_SUPPORTED]; + UINT8 Index; + UINT8 CoreTemp[MAX_NUMBER_OF_THREADS_SUPPORTED / 2]; + + /// + /// Get DTS temperature for all cores/threads. + /// + for (Index = 0; Index < MAX_NUMBER_OF_THREADS_SUPPORTED; Index++) { + ThreadTemperatureBuffer[Index] = 0; + } + + RunOnAllLogicalProcessors (DigitalThermalSensorUpdateTemperature, ThreadTemperatureBuffer); + /// + /// Compare thread1 and thread2 temperature in each core and only report higher temperature as core temperature. + /// + for (Index = 0; Index < MAX_NUMBER_OF_THREADS_SUPPORTED; Index += 2) { + CoreTemp[(UINT8) DivU64x32 (Index, 2)] = + (ThreadTemperatureBuffer[Index] > ThreadTemperatureBuffer[Index + 1]) + ? ThreadTemperatureBuffer[Index] : ThreadTemperatureBuffer[Index + 1]; + } + + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = CoreTemp[0]; + if ((MAX_NUMBER_OF_THREADS_SUPPORTED / 2) > 1) { + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = CoreTemp[1]; + } + + if ((MAX_NUMBER_OF_THREADS_SUPPORTED / 2) > 2) { + mGlobalNvsAreaPtr->Ap2DigitalThermalSensorTemperature = CoreTemp[2]; + } + + if ((MAX_NUMBER_OF_THREADS_SUPPORTED / 2) > 3) { + mGlobalNvsAreaPtr->Ap3DigitalThermalSensorTemperature = CoreTemp[3]; + } + + return EFI_SUCCESS; +} + +/** + SMI handler to handle Digital Thermal Sensor CPU Local APIC SMI + for thermal Out Of Spec interrupt + + @param[in] SmmImageHandle Image handle returned by the SMM driver. + @param[in] CommunicationBuffer Pointer to the buffer that contains the communication Message + @param[in] SourceSize Size of the memory image to be used for handler. + + @retval EFI_SUCCESS Callback Function Executed +**/ +EFI_STATUS +EFIAPI +DtsOutOfSpecSmiCallback ( + IN EFI_HANDLE SmmImageHandle, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + + DTS_EVENT_TYPE EventType; + + /// + /// If not enabled; return. (The DTS will be disabled upon S3 entry + /// and will remain disabled until after re-initialized upon wake.) + /// + if (!mDtsEnabled) { + return EFI_SUCCESS; + } + + EventType = DtsEventNone; + + if (gIsPackageTempMsrAvailable) { + /// + /// Get the Package DTS Event Type + /// + DigitalThermalSensorEventCheckPackageMsr (&EventType); + } else { + /// + /// Get the DTS Event Type + /// + DigitalThermalSensorEventCheck (&EventType); + } + /// + /// Check if this a DTS Out Of Spec SMI event + /// + if (EventType == DtsEventOutOfSpec) { + /// + /// Return Critical temperature value to _TMP and generate GPE event for critical shutdown. + /// + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = DTS_OUT_OF_SPEC_OCCURRED; + + /// + /// Generate SCI to shut down the system + /// + DigitalThermalSensorSetSwGpeSts (); + } + + return EFI_SUCCESS; +} + +/** + Call from SMI handler to handle Package thermal temperature Digital Thermal Sensor CPU Local APIC SMI + for thermal threshold interrupt + + @retval None +**/ +VOID +PackageThermalDTS ( + VOID + ) +{ + DTS_EVENT_TYPE PkgEventType; + + PkgEventType = DtsEventNone; + + /// + /// Check is this a Platform SMI event or the flag of update DTS temperature and threshold value in every SMI + /// + if (DigitalThermalSensorEventCheckPackageMsr (&PkgEventType) || mUpdateDtsInEverySmi) { + /// + /// Disable Local APIC SMI before programming the threshold + /// + RunOnAllLogicalProcessors (DigitalThermalSensorDisableSmi, NULL); + + do { + /// + /// Handle Package events + /// + if ((PkgEventType == DtsEventOutOfSpec) && (mGlobalNvsAreaPtr->OperatingSystem == 0)) { + /// + /// Handle critical event by shutting down via EC if ACPI + /// is not enabled. + /// + PlatformEventOutOfSpec (); + } + /// + /// Set the thermal trip toints as needed. + /// + mGlobalNvsAreaPtr->PackageDTSTemperature = 0; + + /// + /// Set the Package thermal sensor thresholds + /// + PackageDigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->PackageDTSTemperature); + + /// + /// Set SWGPE Status to generate an SCI if we had any events + /// + if ((PkgEventType != DtsEventNone) || mUpdateDtsInEverySmi) { + DigitalThermalSensorSetSwGpeSts (); + } + + } while (DigitalThermalSensorEventCheckPackageMsr (&PkgEventType)); + /// + /// Enable Local APIC SMI on all logical processors + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL); + } +} + +/** + SMI handler to handle Digital Thermal Sensor CPU Local APIC SMI + for thermal threshold interrupt + + @param[in] SmmImageHandle Image handle returned by the SMM driver. + @param[in] CommunicationBuffer Pointer to the buffer that contains the communication Message + @param[in] SourceSize Size of the memory image to be used for handler. + + @retval EFI_SUCCESS Callback Function Executed +**/ +EFI_STATUS +EFIAPI +DtsSmiCallback ( + IN EFI_HANDLE SmmImageHandle, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + UINTN Index; + DTS_EVENT_TYPE EventType; + /// + /// If not enabled; return. (The DTS will be disabled upon S3 entry + /// and will remain disabled until after re-initialized upon wake.) + /// + if (!mDtsEnabled) { + return EFI_SUCCESS; + } + /// + /// Get the Package thermal temperature + /// + if (gIsPackageTempMsrAvailable) { + RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL); + PackageThermalDTS (); + } else { + /// + /// We enable the Thermal interrupt on the AP's prior to the event check + /// for the case where the AP has gone through the INIT-SIPI-SIPI sequence + /// and does not have the interrupt enabled. (This allows the AP thermal + /// interrupt to be re-enabled due to chipset-based SMIs without waiting + /// to receive a DTS event on the BSP.) + /// + for (Index = 1; Index < mSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor (DigitalThermalSensorEnableSmi, Index, NULL); + } + /// + /// Check is this a DTS SMI event or the flag of update DTS temperature and threshold value in every SMI + /// + if (DigitalThermalSensorEventCheck (&EventType) || mUpdateDtsInEverySmi) { + /// + /// Disable Local APIC SMI before programming the threshold + /// + RunOnAllLogicalProcessors (DigitalThermalSensorDisableSmi, NULL); + + do { + /// + /// Handle BSP events + /// + if ((EventType == DtsEventOutOfSpec) && (mGlobalNvsAreaPtr->OperatingSystem == 0)) { + /// + /// Handle critical event by shutting down via EC if ACPI + /// is not enabled. + /// + PlatformEventOutOfSpec (); + } + /// + /// Update temperatures for PTID + /// + DigitalThermalSensorUpdatePTID (); + + /// + /// Set the thermal trip toints as needed. + /// Note: We only save the highest temperature of each die in + /// the NVS area when more than two logical processors are + /// present as only the highest DTS reading is actually used by + /// the current ASL solution. + /// + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + + /// + /// Set the BSP thermal sensor thresholds + /// + DigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature); + + /// + /// Set the AP thermal sensor thresholds and update temperatures + /// + for (Index = 1; Index < mSmst->NumberOfCpus / 2; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature + ); + } + + for (Index = mSmst->NumberOfCpus / 2; Index < mSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature + ); + } + /// + /// Set SWGPE Status to generate an SCI if we had any events + /// + if ((EventType != DtsEventNone) || mUpdateDtsInEverySmi) { + DigitalThermalSensorSetSwGpeSts (); + } + + } while (DigitalThermalSensorEventCheck (&EventType)); + /// + /// Enable Local APIC SMI on all logical processors + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL); + } + } + + return EFI_SUCCESS; +} + +/** + This catches IO trap SMI generated by the ASL code to enable the DTS AP function + + @param[in] DispatchHandle Not used + @param[in] CallbackContext Not used +**/ +VOID +EFIAPI +DtsIoTrapCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT *CallbackContext + ) +{ + UINTN Index; + EFI_STATUS Status; + UINT8 RetryIteration; + + /// + /// Determine the function desired, passed in the global NVS area + /// + switch (mGlobalNvsAreaPtr->DigitalThermalSensorSmiFunction) { + /// + /// Enable AP Digital Thermal Sensor function after resume from S3 + /// + case IO_TRAP_INIT_DTS_FUNCTION_AFTER_S3: + /// + /// Enable the Package DTS on the processors. + /// + if (gIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorEnable (NULL); + } else { + /// + /// Enable the DTS on all logical processors. + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnable, NULL); + } + + if (DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) { + /// + /// Set the thermal trip toints on all logical processors. + /// Note: We only save the highest temperature of each die in the NVS area when + /// more than two logical processors are present as only the highest DTS reading + /// is actually used by the current ASL solution. + /// + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->PackageDTSTemperature = 0; + + if (gIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->PackageDTSTemperature); + } else { + /// + /// Update temperatures for PTID + /// + DigitalThermalSensorUpdatePTID (); + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + DigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature); + + for (Index = 1; Index < mSmst->NumberOfCpus / 2; Index++) { + Status = EFI_NOT_READY; + for (RetryIteration = 0; + (RetryIteration < DTS_AP_SAFE_RETRY_LIMIT) && (Status != EFI_SUCCESS); + RetryIteration++ + ) { + Status = mSmst->SmmStartupThisAp ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature + ); + if (Status != EFI_SUCCESS) { + /// + /// SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again. + /// + PchPmTimerStall (DTS_WAIT_PERIOD); + } + } + } + + for (Index = mSmst->NumberOfCpus / 2; Index < mSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature + ); + } + } + /// + /// Re-enable the DTS. + /// + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_ENABLE; + } else { + /// + /// Enable Out Of Spec Interrupt + /// + if (gIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetOutOfSpecInterrupt (NULL); + } else { + RunOnAllLogicalProcessors (DigitalThermalSensorSetOutOfSpecInterrupt, NULL); + } + /// + /// Re-enable the DTS which only handle Out-Of-Spec condition + /// + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = DTS_OUT_OF_SPEC_ONLY; + } + /// + /// Enable the Local APIC SMI on all logical processors + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL); + /// + /// Set SWGPE Status + /// + DigitalThermalSensorSetSwGpeSts (); + + mUpdateDtsInEverySmi = UPDATE_DTS_EVERY_SMI; + mDtsEnabled = TRUE; + break; + + /// + /// Disable update DTS temperature and threshold value in every SMI + /// + case IO_TRAP_DISABLE_UPDATE_DTS: + mUpdateDtsInEverySmi = FALSE; + break; + + default: + break; + } + /// + /// Store return value + /// + mGlobalNvsAreaPtr->DigitalThermalSensorSmiFunction = 0; +} + +/** + This function executes DTS procedures for preparing to enter S3. + + @param[in] Handle Handle of the callback + @param[in] Context The dispatch context + + @retval EFI_SUCCESS DTS disabled +**/ +VOID +EFIAPI +DtsS3EntryCallBack ( + IN EFI_HANDLE Handle, + IN EFI_SMM_SX_DISPATCH_CONTEXT *Context + ) +{ + /// + /// Clear the Digital Thermal Sensor flag in ACPI NVS. + /// + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_DISABLE; + /// + /// Clear the enable flag. + /// + mDtsEnabled = FALSE; + + return; +} + +/** + Performs initialization of the threshold table. + + @todo Update this function as necessary for the tables used by the implementation. + + @retval EFI_SUCCESS Threshold tables initialized successfully. +**/ +EFI_STATUS +ThresholdTableInit ( + VOID + ) +{ + UINTN i; + UINT8 Delta; + + /// + /// If the table must be updated, shift the thresholds by the difference between + /// TJ_MAX=110 and DtsTjMax. + /// + if (mDtsTjMax != TJ_MAX) { + Delta = TJ_MAX - mDtsTjMax; + + for (i = 0; i < mNoOfThresholdRanges; i++) { + if (mDtsThresholdTable[i][1] <= mDtsTjMax) { + mDtsThresholdTable[i][0] = mDtsThresholdTable[i][0] - Delta; + } else { + mDtsThresholdTable[i][0] = 0; + } + } + } + + return EFI_SUCCESS; +} + +/** + Perform first time initialization of the Digital Thermal Sensor + + @retval EFI_SUCCESS Init Digital Thermal Sensor successfully +**/ +EFI_STATUS +DigitalThermalSensorInit ( + VOID + ) +{ + UINTN Index; + + if (DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) { + /// + /// Initialize the DTS threshold table. + /// + ThresholdTableInit (); + + /// + /// Set the thermal trip points on all logical processors. + /// Note: We only save the highest temperature of each die in the NVS area when + /// more than two logical processors are present as only the highest DTS reading + /// is actually used by the current ASL solution. + /// + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->PackageDTSTemperature = 0; + if (gIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->PackageDTSTemperature); + } else { + /// + /// Update temperatures for PTID + /// + DigitalThermalSensorUpdatePTID (); + mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + DigitalThermalSensorSetThreshold (&mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature); + + for (Index = 1; Index < mSmst->NumberOfCpus / 2; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature + ); + } + + for (Index = mSmst->NumberOfCpus / 2; Index < mSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature + ); + } + } + + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_ENABLE; + } else { + /// + /// Enable Out Of Spec Interrupt + /// + if (gIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetOutOfSpecInterrupt (NULL); + } else { + RunOnAllLogicalProcessors (DigitalThermalSensorSetOutOfSpecInterrupt, NULL); + } + + mGlobalNvsAreaPtr->EnableDigitalThermalSensor = DTS_OUT_OF_SPEC_ONLY; + } + /// + /// Enable the Local APIC SMI on all logical processors + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL); + /// + /// Set Digital Thermal Sensor flag in ACPI NVS + /// + mUpdateDtsInEverySmi = UPDATE_DTS_EVERY_SMI; + mDtsEnabled = TRUE; + + return EFI_SUCCESS; +} + +/** + Initializes the Thermal Sensor Control MSR + + This function must be AP safe. + + @param[in] Buffer Unused. + + @retval EFI_SUCCESS The function completed successfully. +**/ +VOID +EFIAPI +DigitalThermalSensorEnable ( + VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + /// + /// First, clear our log bits + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_STATUS); + if (DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) { + MsrData.Qword &= ~THERM_STATUS_LOG_MASK; + } else { + MsrData.Qword &= ~B_OUT_OF_SPEC_STATUS_LOG; + } + + AsmWriteMsr64 (EFI_MSR_IA32_THERM_STATUS, MsrData.Qword); + + /// + /// Second, configure the thermal sensor control + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_MISC_PWR_MGMT); + + /// + /// Only lock interrupts if in CMP mode + /// + if (mSmst->NumberOfCpus > 1) { + MsrData.Qword |= B_LOCK_THERMAL_INT; + } + + AsmWriteMsr64 (EFI_MSR_MISC_PWR_MGMT, MsrData.Qword); + + return; +} + +/** + Initializes the Package Thermal Sensor Control MSR + + @param[in] Buffer Unused. + + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +PackageDigitalThermalSensorEnable ( + VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + /// + /// First, clear our log bits + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS); + if (DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) { + MsrData.Qword &= ~THERM_STATUS_LOG_MASK; + } else { + MsrData.Qword &= ~B_OUT_OF_SPEC_STATUS_LOG; + } + + AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS, MsrData.Qword); + + /// + /// Second, configure the thermal sensor control + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_MISC_PWR_MGMT); + + /// + /// Only lock interrupts if in CMP mode + /// + if (mSmst->NumberOfCpus > 1) { + MsrData.Qword |= B_LOCK_THERMAL_INT; + } + + AsmWriteMsr64 (EFI_MSR_MISC_PWR_MGMT, MsrData.Qword); + + return EFI_SUCCESS; +} + +/** + Generates a _GPE._L02 SCI to an ACPI OS. +**/ +VOID +DigitalThermalSensorSetSwGpeSts ( + VOID + ) +{ + UINT8 GpeCntl; + + /// + /// Check SCI enable + /// + if (((SmmIoRead8 (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)) & B_PCH_ACPI_PM1_CNT_SCI_EN) != 0) { + /// + /// Do platform specific things before generate SCI + /// + PlatformHookBeforeGenerateSCI (); + + /// + /// Set SWGPE Status + /// + GpeCntl = SmmIoRead8 (mAcpiBaseAddr + R_ACPI_GPE_CNTL); + GpeCntl |= B_SWGPE_CTRL; + SmmIoWrite8 (mAcpiBaseAddr + R_ACPI_GPE_CNTL, GpeCntl); + } +} + +/** + Checks for a Core Thermal Event on any processor + + @param[in] EventType - DTS_EVENT_TYPE to indicate which DTS event type has been detected. + + @retval TRUE means this is a DTS Thermal event + @retval FALSE means this is not a DTS Thermal event. +**/ +BOOLEAN +DigitalThermalSensorEventCheck ( + DTS_EVENT_TYPE *EventType + ) +{ + /// + /// Clear event status + /// + *EventType = DtsEventNone; + + RunOnAllLogicalProcessors (DigitalThermalSensorEventCheckMsr, EventType); + /// + /// Return TRUE if any logical processor reported an event. + /// + if (*EventType != DtsEventNone) { + return TRUE; + } + + return FALSE; +} + +/** + Checks for a Package Thermal Event by reading MSR. + + @param[in] PkgEventType - DTS_EVENT_TYPE to indicate which DTS event type has been detected. + + @retval TRUE means this is a Package DTS Thermal event + @retval FALSE means this is not a Package DTS Thermal event. +**/ +BOOLEAN +DigitalThermalSensorEventCheckPackageMsr ( + DTS_EVENT_TYPE *PkgEventType + ) +{ + MSR_REGISTER MsrData; + + /// + /// Clear event status + /// + *PkgEventType = DtsEventNone; + + /// + /// If Processor has already been flagged as Out-Of-Spec, + /// just return. + /// + if (*PkgEventType != DtsEventOutOfSpec) { + /// + /// Read thermal status + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS); + + /// + /// Check for Out-Of-Spec status. + /// + if (MsrData.Qword & B_OUT_OF_SPEC_STATUS_LOG) { + *PkgEventType = DtsEventOutOfSpec; + + /// + /// Check thresholds. + /// + } else if ((DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) && + (MsrData.Qword & (B_THERMAL_THRESHOLD_1_STATUS_LOG | B_THERMAL_THRESHOLD_2_STATUS_LOG)) + ) { + *PkgEventType = DtsEventThreshold; + } + } + /// + /// Return TRUE if processor reported an event. + /// + if (*PkgEventType != DtsEventNone) { + return TRUE; + } + + return FALSE; + +} + +/** + Checks for a Core Thermal Event by reading MSR. + + This function must be MP safe. + + @param[in] Buffer Pointer to DTS_EVENT_TYPE +**/ +VOID +EFIAPI +DigitalThermalSensorEventCheckMsr ( + IN VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + DTS_EVENT_TYPE *EventType; + + /// + /// Cast to enhance readability. + /// + EventType = (DTS_EVENT_TYPE *) Buffer; + + /// + /// If any processor has already been flagged as Out-Of-Spec, + /// just return. + /// + if (*EventType != DtsEventOutOfSpec) { + /// + /// Read thermal status + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_STATUS); + + /// + /// Check for Out-Of-Spec status. + /// + if (MsrData.Qword & B_OUT_OF_SPEC_STATUS_LOG) { + *EventType = DtsEventOutOfSpec; + + /// + /// Check thresholds. + /// + } else if ((DTSSetupValue != DTS_OUT_OF_SPEC_ONLY) && + (MsrData.Qword & (B_THERMAL_THRESHOLD_1_STATUS_LOG | B_THERMAL_THRESHOLD_2_STATUS_LOG)) + ) { + *EventType = DtsEventThreshold; + } + } +} + +/** + Set the Out Of Spec Interrupt in all cores + This function must be AP safe. + + @param[in] Buffer Unused + + @retval EFI_SUCCESS Out Of Spec Interrupt programmed successfully +**/ +VOID +EFIAPI +DigitalThermalSensorSetOutOfSpecInterrupt ( + VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + /// + /// Enable Out Of Spec interrupt + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_INTERRUPT); + MsrData.Qword |= OVERHEAT_INTERRUPT_ENABLE; + AsmWriteMsr64 (EFI_MSR_IA32_THERM_INTERRUPT, MsrData.Qword); + + return; + +} + +/** + Set the Out Of Spec Interrupt on the package + + @param[in] Buffer Unused + + @retval EFI_SUCCESS Out Of Spec Interrupt programmed successfully +**/ +EFI_STATUS +PackageDigitalThermalSensorSetOutOfSpecInterrupt ( + VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + /// + /// Enable Out Of Spec interrupt + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT); + MsrData.Qword |= OVERHEAT_INTERRUPT_ENABLE; + AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT, MsrData.Qword); + + return EFI_SUCCESS; + +} + +/** + Read the temperature and reconfigure the thresholds. + This function must be AP safe. + + @param[in] Buffer Pointer to UINT8 to update with the current temperature + + @retval EFI_SUCCESS Digital Thermal Sensor threshold programmed successfully +**/ +VOID +EFIAPI +DigitalThermalSensorSetThreshold ( + VOID *Buffer + ) +{ + INT8 ThresholdEntry; + MSR_REGISTER MsrData; + UINT8 Temperature; + + /// + /// Read the temperature + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_STATUS); + + /// + /// If Out-Of-Spec, return the critical shutdown temperature. + /// + if (MsrData.Qword & B_OUT_OF_SPEC_STATUS) { + *((UINT8 *) Buffer) = DTS_CRITICAL_TEMPERATURE; + return; + } else if (MsrData.Qword & B_READING_VALID) { + /// + /// Find the DTS temperature. + /// + Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK); + /// + /// We only update the temperature if it is above the current temperature. + /// + if (Temperature > *((UINT8 *) Buffer)) { + *((UINT8 *) Buffer) = Temperature; + } + /// + /// Compare the current temperature to the Digital Thermal Sensor Threshold Table until + /// a matching Value is found. + /// + ThresholdEntry = 0; + while ((Temperature > mDtsThresholdTable[ThresholdEntry][0]) && (ThresholdEntry < (mNoOfThresholdRanges - 1))) { + ThresholdEntry++; + } + /// + /// Update the threshold values + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_INTERRUPT); + /// + /// Low temp is threshold #2 + /// + MsrData.Bytes.ThirdByte = mDtsThresholdTable[ThresholdEntry][1]; + /// + /// High temp is threshold #1 + /// + MsrData.Bytes.SecondByte = mDtsThresholdTable[ThresholdEntry][2]; + + /// + /// Enable interrupts + /// + MsrData.Qword |= TH1_ENABLE; + MsrData.Qword |= TH2_ENABLE; + + /// + /// If the high temp is at TjMax (offset == 0) + /// We disable the int to avoid generating a large number of SMI because of TM1/TM2 + /// causing many threshold crossings + /// + if (MsrData.Bytes.SecondByte == 0x80) { + MsrData.Qword &= ~TH1_ENABLE; + } + + AsmWriteMsr64 (EFI_MSR_IA32_THERM_INTERRUPT, MsrData.Qword); + } + /// + /// Clear the threshold log bits + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_STATUS); + MsrData.Qword &= ~THERM_STATUS_THRESHOLD_LOG_MASK; + AsmWriteMsr64 (EFI_MSR_IA32_THERM_STATUS, MsrData.Qword); + + return; +} + +/** + Read the temperature and reconfigure the thresholds on the package + + @param[in] Buffer Pointer to UINT8 to update with the current temperature + + @retval EFI_SUCCESS Digital Thermal Sensor threshold programmed successfully +**/ +EFI_STATUS +PackageDigitalThermalSensorSetThreshold ( + VOID *Buffer + ) +{ + INT8 ThresholdEntry; + MSR_REGISTER MsrData; + UINT8 Temperature; + + /// + /// Read the temperature + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS); + + /// + /// If Out-Of-Spec, return the critical shutdown temperature. + /// + if (MsrData.Qword & B_OUT_OF_SPEC_STATUS) { + *((UINT8 *) Buffer) = DTS_CRITICAL_TEMPERATURE; + return EFI_SUCCESS; + } else if (MsrData.Qword & B_READING_VALID) { + /// + /// Update temperatures for PTID + /// + DigitalThermalSensorUpdatePTID (); + + /// + /// Find the DTS temperature. + /// + Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK); + /// + /// We only update the temperature if it is above the current temperature. + /// + if (Temperature > *((UINT8 *) Buffer)) { + *((UINT8 *) Buffer) = Temperature; + } + /// + /// Compare the current temperature to the Digital Thermal Sensor Threshold Table until + /// a matching Value is found. + /// + ThresholdEntry = 0; + while ((Temperature > mDtsThresholdTable[ThresholdEntry][0]) && (ThresholdEntry < (mNoOfThresholdRanges - 1))) { + ThresholdEntry++; + } + /// + /// Update the threshold values + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT); + /// + /// Low temp is threshold #2 + /// + MsrData.Bytes.ThirdByte = mDtsThresholdTable[ThresholdEntry][1]; + /// + /// High temp is threshold #1 + /// + MsrData.Bytes.SecondByte = mDtsThresholdTable[ThresholdEntry][2]; + + /// + /// Enable interrupts + /// + MsrData.Qword |= TH1_ENABLE; + MsrData.Qword |= TH2_ENABLE; + + /// + /// If the high temp is at TjMax (offset == 0) + /// We disable the int to avoid generating a large number of SMI because of TM1/TM2 + /// causing many threshold crossings + /// + if (MsrData.Bytes.SecondByte == 0x80) { + MsrData.Qword &= ~TH1_ENABLE; + } + + AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT, MsrData.Qword); + } + /// + /// Clear the threshold log bits + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS); + MsrData.Qword &= ~THERM_STATUS_THRESHOLD_LOG_MASK; + AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS, MsrData.Qword); + + return EFI_SUCCESS; +} + +/** + Enables the Thermal Interrupt in the core Local APIC. + + @param[in] Buffer Unused + + @retval EFI_SUCCESS Enable Local APIC to generate a SMI successfully +**/ +VOID +EFIAPI +DigitalThermalSensorEnableSmi ( + VOID *Buffer + ) +{ + UINT32 ApicThermalValue; + BOOLEAN x2ApicEnabled; + + x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (EFI_MSR_XAPIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10); + /// + /// Configure the Local APIC to generate an SMI on Thermal events. First, + /// Clear BIT16, BIT10-BIT8, BIT7-BIT0. Then, set BIT9 (delivery mode). + /// Don't enable the interrupt if it's already enabled + /// + if (x2ApicEnabled) { + ApicThermalValue = (UINT32) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM); + } else { + ApicThermalValue = *(UINT32 *) (UINTN) LOCAL_APIC_THERMAL_DEF; + } + + if ((ApicThermalValue & (B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) != V_MODE_SMI) { + ApicThermalValue = (ApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | V_MODE_SMI; + if (x2ApicEnabled) { + AsmWriteMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM, ApicThermalValue); + } else { + *(UINT32 *) (UINTN) (LOCAL_APIC_THERMAL_DEF) = (UINT32) ApicThermalValue; + } + } + + return; +} + +/** + Disables the Thermal Interrupt in the core Local APIC. + + @param[in] Buffer Unused + + @retval EFI_SUCCESS Disable Local APIC to generate a SMI successfully +**/ +VOID +EFIAPI +DigitalThermalSensorDisableSmi ( + VOID *Buffer + ) +{ + UINT32 ApicThermalValue; + BOOLEAN x2ApicEnabled; + + x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (EFI_MSR_XAPIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10); + /// + /// Disable Local APIC thermal entry + /// + if (x2ApicEnabled) { + ApicThermalValue = (UINT32) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM); + } else { + ApicThermalValue = *(UINT32 *) (UINTN) LOCAL_APIC_THERMAL_DEF; + } + /// + /// Following descriptions were from SSE BIOS + /// We set the interrupt mode at the same time as the interrupt is disabled to + /// avoid the "Received Illegal Vector" being set in the Error Status Register. + /// and eax, 0FFFEF800h + /// or eax, 000010200h ; Clear Mask, Set Delivery + /// + ApicThermalValue = (ApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | (B_INTERRUPT_MASK | V_MODE_SMI); + if (x2ApicEnabled) { + AsmWriteMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM, ApicThermalValue); + } else { + *(UINT32 *) (UINTN) (LOCAL_APIC_THERMAL_DEF) = (UINT32) ApicThermalValue; + } + + return; +} + +/** + Runs the specified procedure on all logical processors, passing in the + parameter buffer to the procedure. + + @param[in] Procedure The function to be run. + @param[in] Buffer Pointer to a parameter buffer. + + @retval EFI_SUCCESS Function executed successfully. +**/ +STATIC +EFI_STATUS +RunOnAllLogicalProcessors ( + IN OUT EFI_AP_PROCEDURE Procedure, + IN OUT VOID *Buffer + ) +{ + UINTN Index; + EFI_STATUS Status; + UINT8 RetryIteration; + /// + /// Run the procedure on all logical processors. + /// + for (Index = 1; Index < mSmst->NumberOfCpus; Index++) { + Status = EFI_NOT_READY; + for (RetryIteration = 0; (RetryIteration < DTS_AP_SAFE_RETRY_LIMIT) && (Status != EFI_SUCCESS); RetryIteration++) { + Status = mSmst->SmmStartupThisAp (Procedure, Index, Buffer); + if (Status != EFI_SUCCESS) { + /// + /// SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again. + /// + PchPmTimerStall (DTS_WAIT_PERIOD); + } + } + } + PchPmTimerStall (DTS_WAIT_PERIOD); + (*Procedure)(Buffer); + return EFI_SUCCESS; +} + +/** + Runs the specified procedure on one specific logical processors, passing in the + parameter buffer to the procedure. + + @param[in] Procedure The function to be run. + @param[in] Index Indicate which logical processor should execute this procedure + @param[in] Buffer Pointer to a parameter buffer. + + @retval EFI_SUCCESS Function executed successfully. +**/ +STATIC +EFI_STATUS +RunOnSpecificLogicalProcessor ( + IN OUT EFI_AP_PROCEDURE Procedure, + IN UINTN Index, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 RetryIteration; + /// + /// Run the procedure on one specific logical processor. + /// + Status = EFI_NOT_READY; + for (RetryIteration = 0; (RetryIteration < DTS_AP_SAFE_RETRY_LIMIT) && (Status != EFI_SUCCESS); RetryIteration++) { + Status = mSmst->SmmStartupThisAp (Procedure, Index, Buffer); + if (Status != EFI_SUCCESS) { + /// + /// SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again. + /// + PchPmTimerStall (DTS_WAIT_PERIOD); + } + } + + return EFI_SUCCESS; +} + +/** + Digital Thermal Sensor (DTS) SMM driver entry point function. + + @param[in] ImageHandle Image handle for this driver image + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS Driver initialization completed successfully + @retval EFI_OUT_OF_RESOURCES Error when allocating required memory buffer. +**/ +EFI_STATUS +InstallDigitalThermalSensor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + MSR_REGISTER MsrData; + EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsAreaProtocol; + EFI_SMM_SX_DISPATCH_CONTEXT SxDispatchContext; + EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatchProtocol; + EFI_HANDLE SxDispatchHandle; + + EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL *PchIoTrap; + EFI_HANDLE PchIoTrapHandle; + EFI_SMM_IO_TRAP_DISPATCH_REGISTER_CONTEXT PchIoTrapContext; + EFI_CPUID_REGISTER Cpuid06; + + /// + /// Install DTS_INIT_STATUS_PROTOCOL protocol + /// + Handle = NULL; + mDtsInitStatusProtocol.IsDtsInitComplete = FALSE; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gDtsInitStatusProtocolGuid, + &mDtsInitStatusProtocol, + NULL + ); + + /// + /// Locate DTS platform policy. + /// + Status = gBS->LocateProtocol ( + &gDxeCpuPlatformPolicyProtocolGuid, + NULL, + (VOID **) &mPlatformCpu + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "No DTS Platform Policy Protocol available")); + } + + ASSERT_EFI_ERROR (Status); + + /// + /// Check if DTS disabled in setup. + /// + if (mPlatformCpu->CpuConfig->EnableDts == CPU_FEATURE_DISABLE) { + DEBUG ((EFI_D_WARN, "DTS not enabled/supported, so driver not loaded into SMM\n")); + return EFI_SUCCESS; + } + /// + /// Find the SMM base protocol + /// + Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase); + ASSERT_EFI_ERROR (Status); + + /// + /// Initialize global variables. + /// + Status = mSmmBase->GetSmstLocation (mSmmBase, &mSmst); + ASSERT_EFI_ERROR (Status); + /// + /// Verify the code supports the number of processors present. + /// + ASSERT (mSmst->NumberOfCpus <= MAX_NUMBER_OF_THREADS_SUPPORTED); + + /// + /// Get the ACPI Base Address + /// + mAcpiBaseAddr = MmioRead16 (MmPciExpressAddress (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_ACPI_BASE)) &~BIT0; + + /// + /// Initialize DTS setup value + /// + DTSSetupValue = mPlatformCpu->CpuConfig->EnableDts; + + /// + /// Locate our shared data area + /// + Status = gBS->LocateProtocol (&mEfiGlobalNvsAreaProtocolGuid, NULL, (VOID **) &GlobalNvsAreaProtocol); + ASSERT_EFI_ERROR (Status); + mGlobalNvsAreaPtr = GlobalNvsAreaProtocol->Area; + /// + /// CPU_ID 6, EAX bit 6 for the Package temperature MSR support + /// + ZeroMem (&Cpuid06, sizeof (Cpuid06)); + AsmCpuid (6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx); + + gIsPackageTempMsrAvailable = (BOOLEAN) ((Cpuid06.RegEax >> 6) & 0x01); + mGlobalNvsAreaPtr->IsPackageTempMSRAvailable = gIsPackageTempMsrAvailable; + /// + /// Locate Platform specific data area, or prepare platform services + /// + InitializeDtsHookLib (); + + /// + /// Initialize ASL manipulation library + /// + InitializeAslUpdateLib (); + + /// + /// Locate the PCH Trap dispatch protocol + /// + Status = gBS->LocateProtocol (&mEfiSmmIoTrapDispatchProtocolGuid, NULL, (VOID **) &PchIoTrap); + ASSERT_EFI_ERROR (Status); + + PchIoTrapContext.Type = ReadWriteTrap; + PchIoTrapContext.Length = 4; + PchIoTrapContext.Address = 0; + PchIoTrapContext.Context = NULL; + PchIoTrapContext.MergeDisable = FALSE; + Status = PchIoTrap->Register ( + PchIoTrap, + DtsIoTrapCallback, + &PchIoTrapContext, + &PchIoTrapHandle + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Update two ASL items. + /// 1: Operating Region for DTS IO Trap. + /// 2: Resource Consumption in LPC Device. + /// + ASSERT (PchIoTrapContext.Length <= (UINT8) (-1)); + Status = UpdateAslCode ( + (EFI_SIGNATURE_32 ('I', 'O', '_', 'D')), + PchIoTrapContext.Address, + (UINT8) PchIoTrapContext.Length + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Register a callback function to handle Digital Thermal Sensor SMIs. + /// + if (mPlatformCpu->CpuConfig->EnableDts != DTS_OUT_OF_SPEC_ONLY) { + Status = mSmmBase->RegisterCallback (mSmmBase, ImageHandle, DtsSmiCallback, FALSE, FALSE); + ASSERT_EFI_ERROR (Status); + } else { + Status = mSmmBase->RegisterCallback (mSmmBase, ImageHandle, DtsOutOfSpecSmiCallback, FALSE, FALSE); + ASSERT_EFI_ERROR (Status); + } + /// + /// Locate the Sx Dispatch Protocol + /// + Status = gBS->LocateProtocol ( + &gEfiSmmSxDispatchProtocolGuid, + NULL, + (VOID **) &SxDispatchProtocol + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Register the callback for S3 entry + /// + SxDispatchContext.Type = SxS3; + SxDispatchContext.Phase = SxEntry; + Status = SxDispatchProtocol->Register ( + SxDispatchProtocol, + DtsS3EntryCallBack, + &SxDispatchContext, + &SxDispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + if (mPlatformCpu->CpuConfig->EnableDts != DTS_OUT_OF_SPEC_ONLY) { + /// + /// Get the TCC Activation Temperature and use it for TjMax. + /// + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_TEMPERATURE_TARGET); + + mDtsTjMax = (MsrData.Bytes.ThirdByte); + mDtsThresholdTable = mDigitalThermalSensorThresholdTable; + mNoOfThresholdRanges = DTS_NUMBER_THRESHOLD_RANGES; + } + + if (gIsPackageTempMsrAvailable) { + /// + /// Enable the DTS on package. + /// + PackageDigitalThermalSensorEnable (NULL); + } else { + /// + /// Enable the DTS on all logical processors. + /// + RunOnAllLogicalProcessors (DigitalThermalSensorEnable, NULL); + } + /// + /// Initialize Digital Thermal Sensor Function in POST + /// + DigitalThermalSensorInit (); + + mDtsInitStatusProtocol.IsDtsInitComplete = TRUE; + + return EFI_SUCCESS; +} |