summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c')
-rw-r--r--ReferenceCode/Haswell/DTS/Smm/DigitalThermalSensorSmm.c1536
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;
+}