From e91e23d74df05e6c52b2099428e2258a108f658d Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 10:49:27 +0800 Subject: BroxtonSiPkg: Add PowerManagement Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Cpu/PowerManagement/Dxe/MiscFunctions.c | 428 +++++++ .../Cpu/PowerManagement/Dxe/PerformanceStates.c | 249 ++++ .../Cpu/PowerManagement/Dxe/PowerMgmtCommon.h | 263 ++++ .../Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf | 67 ++ .../Cpu/PowerManagement/Dxe/PowerMgmtInit.c | 273 +++++ .../Cpu/PowerManagement/Dxe/PowerMgmtInit.h | 75 ++ .../Cpu/PowerManagement/Smm/PowerMgmtDts.c | 1267 ++++++++++++++++++++ .../Cpu/PowerManagement/Smm/PowerMgmtDts.h | 369 ++++++ .../Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h | 32 + .../Cpu/PowerManagement/Smm/PowerMgmtS3.c | 221 ++++ .../Cpu/PowerManagement/Smm/PowerMgmtSmm.c | 102 ++ .../Cpu/PowerManagement/Smm/PowerMgmtSmm.h | 117 ++ .../Cpu/PowerManagement/Smm/PowerMgmtSmm.inf | 63 + 13 files changed, 3526 insertions(+) create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf (limited to 'Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement') diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c new file mode 100644 index 0000000000..a0dc451a84 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c @@ -0,0 +1,428 @@ +/** @file + This file contains Processor Power Management ACPI related functions for + processors. + + Acronyms: + PPM: Processor Power Management + TM: Thermal Monitor + IST: Intel(R) Speedstep technology + HT: Hyper-Threading Technology + + Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtCommon.h" + +/** + Update the SSDT table pointers and config DWORD CFGD with the PpmFlags current configuration value + +**/ +VOID +PatchCpuSsdtTable ( + VOID + ) +{ + UINT8 *CurrPtr; + UINT32 *Signature; + SSDT_LAYOUT *SsdtPackage; + + // + // Locate the SSDT package + // + SsdtPackage = NULL; + CurrPtr = (UINT8 *) mCpuSsdtTable; + for (CurrPtr = (UINT8 *) mCpuSsdtTable; CurrPtr <= ((UINT8 *) mCpuSsdtTable + mCpuSsdtTable->Length); CurrPtr++) { + Signature = (UINT32 *) (CurrPtr + 1); + if ((*CurrPtr == AML_NAME_OP) && *Signature == SIGNATURE_32 ('S', 'S', 'D', 'T')) { + // + // Update the SSDT table pointers for dynamically loaded tables + // + SsdtPackage = (SSDT_LAYOUT *) CurrPtr; + // + // Set the P-State SSDT table information + // + SsdtPackage->Cpu0IstAddr = (UINT32) (UINTN) mCpu0IstTable; + SsdtPackage->Cpu0IstLen = mCpu0IstTable->Length; + SsdtPackage->ApIstAddr = (UINT32) (UINTN) mApIstTable; + SsdtPackage->ApIstLen = mApIstTable->Length; + // + // Set the C-State SSDT table information + // + SsdtPackage->Cpu0CstAddr = (UINT32) (UINTN) mCpu0CstTable; + SsdtPackage->Cpu0CstLen = mCpu0CstTable->Length; + SsdtPackage->ApCstAddr = (UINT32) (UINTN) mApCstTable; + SsdtPackage->ApCstLen = mApCstTable->Length; + DEBUG ((DEBUG_INFO, "\n Cpu0Ist :%x :%x \n",SsdtPackage->Cpu0IstAddr,SsdtPackage->Cpu0CstLen)); + DEBUG ((DEBUG_INFO, "\n Cpu0Cst :%x :%x \n",SsdtPackage->Cpu0CstAddr,SsdtPackage->Cpu0CstLen)); + } + // + // Update the CPU GlobalNvs area + // + if ((*CurrPtr == AML_EXT_REGION_OP) && *Signature == SIGNATURE_32 ('P', 'N', 'V', 'S')) { + ASSERT_EFI_ERROR (*(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) == 0xFFFF0000); + ASSERT_EFI_ERROR (*(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55); + // + // CPU Global NVS Area address + // + *(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) = (UINT32) (UINTN) gCpuGlobalNvsAreaProtocol->Area; + // + // CPU Global NVS Area size + // + *(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) = sizeof (CPU_GLOBAL_NVS_AREA); + break; + } + } + // + // Assert if we didn't update the SSDT table + // + ASSERT (SsdtPackage != NULL); + + return; +} + + +/** + Locate the PPM ACPI tables data file and read ACPI SSDT tables. + Publish the appropriate SSDT based on current configuration and capabilities. + + @retval EFI_SUCCESS On success + @retval EFI_NOT_FOUND Required firmware volume not found + @retval EFI_OUT_OF_RESOURCES No enough resoruces (such as out of memory). + @retval Appropiate failure code on error + +**/ +EFI_STATUS +InitCpuAcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_FV_FILETYPE FileType; + UINT32 FvStatus; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN i; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; + INTN Instance; + EFI_ACPI_TABLE_VERSION Version; + EFI_ACPI_COMMON_HEADER *CurrentTable; + EFI_ACPI_DESCRIPTION_HEADER *TempTable; + UINTN AcpiTableHandle; + + FwVol = NULL; + + // + // Locate Firmware volume protocol. + // There is little chance we can't find an FV protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + // + // Look for FV with ACPI storage file + // + FwVol = NULL; + for (i = 0; i < NumberOfHandles; i++) { + // + // Get the protocol on this handle + // This should not fail because of LocateHandleBuffer + // + Status = gBS->HandleProtocol ( + HandleBuffer[i], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FwVol + ); + ASSERT_EFI_ERROR (Status); + // + // See if it has the ACPI storage file + // + Size = 0; + FvStatus = 0; + Status = FwVol->ReadFile ( + FwVol, + &gCpuAcpiTableStorageGuid, + NULL, + &Size, + &FileType, + &Attributes, + &FvStatus + ); + // + // If we found it, then we are done + // + if (Status == EFI_SUCCESS) { + break; + } + } + // + // Our exit status is determined by the success of the previous operations + // If the protocol was found, Instance already points to it. + // Free any allocated buffers + // + FreePool (HandleBuffer); + // + // Sanity check that we found our data file + // + ASSERT (FwVol != NULL); + if (FwVol == NULL) { + return EFI_NOT_FOUND; + } + // + // By default, a table belongs in all ACPI table versions published. + // + Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0; + // + // Read tables from the storage file. + // + Instance = 0; + CurrentTable = NULL; + while (Status == EFI_SUCCESS) { + Status = FwVol->ReadSection ( + FwVol, + &gCpuAcpiTableStorageGuid, + EFI_SECTION_RAW, + Instance, + (VOID **) &CurrentTable, + &Size, + &FvStatus + ); + if (!EFI_ERROR (Status)) { + // + // Check the table ID to modify the table + // + switch (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId) { + case (SIGNATURE_64 ('C', 'p', 'u', '0', 'I', 's', 't', 0)): + mCpu0IstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) { + // + // Patch the native _PSS package with the EIST values + // + Status = AcpiPatchPss (); + if (EFI_ERROR (Status)) { + return Status; + } + } + break; + case (SIGNATURE_64 ('C', 'p', 'u', '0', 'C', 's', 't', 0)): + mCpu0CstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + case (SIGNATURE_64 ('C', 'p', 'u', '0', 'T', 's', 't', 0)): + mCpu0TstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + case (SIGNATURE_64 ('A', 'p', 'I', 's', 't', 0, 0, 0)): + mApIstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + case (SIGNATURE_64 ('A', 'p', 'C', 's', 't', 0, 0, 0)): + mApCstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + case (SIGNATURE_64 ('A', 'p', 'T', 's', 't', 0, 0, 0)): + mApTstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + case (SIGNATURE_64 ('C', 'p', 'u', 'S', 's', 'd', 't', 0)): + mCpuSsdtTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + break; + default: + break; + } + Instance++; // Increment the instance + CurrentTable = NULL; + } + } + // + // Copy CpuoIst SSDT if EIST is enabled + // + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) { + TempTable = AllocateReservedPool (mCpu0IstTable->Length); + if (TempTable == NULL) { + ASSERT (TempTable != NULL); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (TempTable, mCpu0IstTable, mCpu0IstTable->Length); + FreePool (mCpu0IstTable); + mCpu0IstTable = TempTable; + AcpiChecksum (mCpu0IstTable, mCpu0IstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum)); + AcpiTableHandle = 0; + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + mCpu0IstTable, + mCpu0IstTable->Length, + &AcpiTableHandle + ); + } + // + // If we are CMP, then the PPM tables are dynamically loaded: + // We need to publish the CpuPm table to the ACPI tables, and move the CST + // tables that are dynamically loaded to a separate location so that we can fix the + // addresses in the CpuPm table. + // Otherwise (non-CMP): + // We need to publish CPU 0 tables only, and CST tables only if CST is enabled + // + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) { + // + // Copy tables to our own location and checksum them + // + TempTable = AllocateReservedPool (mApIstTable->Length); + if (TempTable == NULL) { + ASSERT (TempTable != NULL); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (TempTable, mApIstTable, mApIstTable->Length); + FreePool (mApIstTable); + mApIstTable = TempTable; + AcpiChecksum (mApIstTable, mApIstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum)); + TempTable = AllocateReservedPool (mCpu0CstTable->Length); + if (TempTable == NULL) { + ASSERT (TempTable != NULL); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (TempTable, mCpu0CstTable, mCpu0CstTable->Length); + FreePool (mCpu0CstTable); + mCpu0CstTable = TempTable; + AcpiChecksum (mCpu0CstTable, mCpu0CstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum)); + TempTable = AllocateReservedPool (mApCstTable->Length); + if (TempTable == NULL) { + ASSERT (TempTable != NULL); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (TempTable, mApCstTable, mApCstTable->Length); + FreePool (mApCstTable); + mApCstTable = TempTable; + AcpiChecksum (mApCstTable, mApCstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum)); + } else { + // + // CMP disabled, so statically load the tables + // + // Add CST SSDT if C states are enabled + // + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) { + AcpiTableHandle = 0; + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + mCpu0CstTable, + mCpu0CstTable->Length, + &AcpiTableHandle + ); + } + // + // Since we are UP, there is no need for the CPU 1 tables + // + // + // Free all tables, since they have been copied into ACPI tables by ACPI support protocol + // + FreePool (mCpu0CstTable); + FreePool (mApIstTable); + FreePool (mApCstTable); + } + // + // Update the CpuSsdt SSDT table in the ACPI tables. + // + PatchCpuSsdtTable (); + AcpiTableHandle = 0; + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + mCpuSsdtTable, + mCpuSsdtTable->Length, + &AcpiTableHandle + ); + FreePool (mCpuSsdtTable); + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TSTATES) { + // + // Load the Cpu0Tst SSDT table in the ACPI tables + // + AcpiTableHandle = 0; + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + mCpu0TstTable, + mCpu0TstTable->Length, + &AcpiTableHandle + ); + FreePool (mCpu0TstTable); + // + // If the CMP is enabled then load the ApTst SSDT table in the ACPI tables + // + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) { + AcpiTableHandle = 0; + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + mApTstTable, + mApTstTable->Length, + &AcpiTableHandle + ); + } + } + FreePool (mApTstTable); + + return Status; +} + + +/** + 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; + UINTN Handle; + + // + // Locate table with matching ID + // + InitializeAslUpdateLib (); + + Handle = 0; + Status = LocateAcpiTableBySignature ( + EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + (EFI_ACPI_DESCRIPTION_HEADER **) &Table, + &Handle + ); + // + // 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; + + // + // Configure C states + // + if (gCpuGlobalNvsAreaProtocol->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; +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c new file mode 100644 index 0000000000..b4307ba872 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c @@ -0,0 +1,249 @@ +/** @file + This file contains P States and Turbo Power Management configuration functions for + processors. + + Acronyms: + PPM: Processor Power Management + TM: Thermal Monitor + IST: Intel(R) Speedstep technology + HT: Hyper-Threading Technology + + Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtCommon.h" +#include + +extern UINT16 mCpuConfigTdpBootRatio; + +// +// Update ACPI PerfomanceStates tables +// + +/** + Patch the native _PSS package with the EIST values + Uses ratio/VID values from the FVID table to fix up the control values in the _PSS. + + (1) Find _PSS package: + (1.1) Find the _PR_CPU0 scope. + (1.2) Save a pointer to the package length. + (1.3) Find the _PSS AML name object. + (2) Resize the _PSS package. + (3) Fix up the _PSS package entries + (3.1) Check Turbo mode support. + (3.2) Check Dynamic FSB support. + (4) Fix up the Processor block and \_PR_CPU0 Scope length. + (5) Update SSDT Header with new length. + + @retval EFI_SUCCESS On success + @retval EFI_NOT_FOUND If _PR_.CPU0 scope is not foud in the ACPI tables + +**/ +EFI_STATUS +AcpiPatchPss ( + VOID + ) +{ + UINT8 *CurrPtr; + UINT8 *EndOfTable; + UINT8 index; + UINT16 NewPackageLength; + UINT16 MaxPackageLength; + UINT16 Temp; + UINT16 *PackageLength; + UINT16 *ScopePackageLengthPtr; + UINT32 *Signature; + PSS_PACKAGE_LAYOUT *PssPackage; + MSR_REGISTER TempMsr; + UINT16 MinBusRatio; + UINT16 MaxNonTurboRatio; + UINT16 NumberOfStatesTurbo; + UINT16 Turbo; + + ScopePackageLengthPtr = NULL; + PssPackage = NULL; + + // + // Get Maximum Efficiency bus ratio (LFM) from Platform Info MSR Bits[47:40] + // Get Maximum Non Turbo bus ratio from Platform Info MSR Bits[15:8] + // + TempMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO); + MinBusRatio = TempMsr.Bytes.SixthByte; + MaxNonTurboRatio = TempMsr.Bytes.SecondByte; + mNumberOfStates = mFvidPointer[0].FvidHeader.EistStates; + NumberOfStatesTurbo = mNumberOfStates - (MaxNonTurboRatio - MinBusRatio + 1); + Turbo = ((gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) ? 1 : 0); + + DEBUG ((EFI_D_INFO, "mNumberOfStates = %x\n", mNumberOfStates)); + DEBUG ((EFI_D_INFO, "NumberOfStatesTurbo = %x\n", NumberOfStatesTurbo)); + + // + // Locate the SSDT package in the IST table + // + CurrPtr = (UINT8 *) mCpu0IstTable; + EndOfTable = (UINT8 *) (CurrPtr + mCpu0IstTable->Length); + for (CurrPtr = (UINT8 *) mCpu0IstTable; CurrPtr <= EndOfTable; CurrPtr++) { + Signature = (UINT32 *) (CurrPtr + 1); + // + // If we find the _PR_CPU0 scope, save a pointer to the package length + // + if ((*CurrPtr == AML_SCOPE_OP) && + (*(Signature + 1) == SIGNATURE_32 ('_', 'P', 'R', '_')) && + (*(Signature + 2) == SIGNATURE_32 ('C', 'P', 'U', '0')) + ) { + ScopePackageLengthPtr = (UINT16 *) (CurrPtr + 1); + } + // + // Patch the NPSS package for Windows usage + // + if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('N', 'P', 'S', 'S'))) { + DEBUG ((EFI_D_INFO, "N P S S start here\n")); + /// + /// Calculate new package length + /// + NewPackageLength = Temp = (UINT16) ((Turbo + MaxNonTurboRatio - MinBusRatio + 1) * sizeof (PSS_PACKAGE_LAYOUT) + 3); + MaxPackageLength = (UINT16) (FVID_MAX_STATES * sizeof (PSS_PACKAGE_LAYOUT) + 3); + // + // Check table dimensions. + // PSS package reserve space for FVID_MAX_STATES number of P-states so check if the + // current number of P- states is more than FVID_MAX_STATES. Also need to update the SSDT contents + // if the current number of P-states is less than FVID_MAX_STATES. + // + ASSERT (mNumberOfStates <= FVID_MAX_STATES); + if (mNumberOfStates <= FVID_MAX_STATES) { + *(CurrPtr + 8) = (UINT8) (Turbo + MaxNonTurboRatio - MinBusRatio + 1); + PackageLength = (UINT16 *) (CurrPtr + 6); + // + // Update the Package length in AML package length format + // + *PackageLength = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00); + // + // Move SSDT contents + // + CopyMem ( + (CurrPtr + NewPackageLength), + (CurrPtr + MaxPackageLength), + EndOfTable - (CurrPtr + MaxPackageLength) + ); + // + // Save the new end of the SSDT + // + EndOfTable = EndOfTable - (MaxPackageLength - NewPackageLength); + } + PssPackage = (PSS_PACKAGE_LAYOUT *) (CurrPtr + 9); + for (index = 1; index <= (Turbo + MaxNonTurboRatio - MinBusRatio + 1); index++) { + // + // If Turbo mode is supported, add one to the Max Non-Turbo frequency + // + if ((gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) && (index == 1)) { + PssPackage->CoreFrequency = (UINT32) ((mFvidPointer[index + NumberOfStatesTurbo].FvidState.BusRatio)* 100) + 1; + PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power; + } else if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) { + PssPackage->CoreFrequency = (UINT32) (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio) * 100; + PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio, 8); + PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio, 8); + PssPackage->Power = (UINT32) mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.Power; + } else { + PssPackage->CoreFrequency = (UINT32) (mFvidPointer[index].FvidState.BusRatio) * 100; + PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power; + } + + PssPackage->TransLatency = NATIVE_PSTATE_LATENCY; + PssPackage->BMLatency = PSTATE_BM_LATENCY; + + // + // Check Pss Package + // + DEBUG ((EFI_D_INFO, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency)); + DEBUG ((EFI_D_INFO, "PssPackage->Control = %x\n", PssPackage->Control)); + DEBUG ((EFI_D_INFO, "PssPackage->Power = %x\n", PssPackage->Power)); + + PssPackage++; + } + } + if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('S', 'P', 'S', 'S'))) { + DEBUG ((EFI_D_INFO, "S P S S start here\n")); + // + // Calculate new package length + // + NewPackageLength = Temp = (UINT16) (mNumberOfStates * sizeof (PSS_PACKAGE_LAYOUT) + 3); + MaxPackageLength = (UINT16) (FVID_MAX_STATES * sizeof (PSS_PACKAGE_LAYOUT) + 3); + // + // Check table dimensions. + // PSS package reserve space for FVID_MAX_STATES number of P-states so check if the + // current number of P- states is more than FVID_MAX_STATES. Also need to update the SSDT contents + // if the current number of P-states is less than FVID_MAX_STATES. + // + ASSERT (mNumberOfStates <= FVID_MAX_STATES); + if (mNumberOfStates <= FVID_MAX_STATES) { + *(CurrPtr + 8) = (UINT8) mNumberOfStates; + PackageLength = (UINT16 *) (CurrPtr + 6); + // + // Update the Package length in AML package length format + // + *PackageLength = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00); + // + // Move SSDT contents + // + CopyMem ( + (CurrPtr + NewPackageLength), + (CurrPtr + MaxPackageLength), + EndOfTable - (CurrPtr + MaxPackageLength) + ); + // + // Save the new end of the SSDT + // + EndOfTable = EndOfTable - (MaxPackageLength - NewPackageLength); + } + PssPackage = (PSS_PACKAGE_LAYOUT *) (CurrPtr + 9); + for (index = 1; index <= mNumberOfStates; index++) { + // + // If Turbo mode is supported, expose all entries + // + PssPackage->CoreFrequency = (UINT32)((mFvidPointer[index].FvidState.BusRatio)* 100); + PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8); + PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power; + PssPackage->TransLatency = NATIVE_PSTATE_LATENCY; + PssPackage->BMLatency = PSTATE_BM_LATENCY; + + // + // Check Pss Package + // + DEBUG ((EFI_D_INFO, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency)); + DEBUG ((EFI_D_INFO, "PssPackage->Control = %x\n", PssPackage->Control)); + DEBUG ((EFI_D_INFO, "PssPackage->Power = %x\n", PssPackage->Power)); + + PssPackage++; + } + } + } + ASSERT (ScopePackageLengthPtr != NULL); + if (ScopePackageLengthPtr == NULL) { + return EFI_NOT_FOUND; + } + // + // Update the Package length in AML package length format + // + CurrPtr = (UINT8 *) ScopePackageLengthPtr; + NewPackageLength = Temp = (UINT16) (EndOfTable - CurrPtr); + *ScopePackageLengthPtr = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00); + mCpu0IstTable->Length = (UINT32) (EndOfTable - (UINT8 *) mCpu0IstTable); + + return EFI_SUCCESS; +} + + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h new file mode 100644 index 0000000000..8ff281ff48 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h @@ -0,0 +1,263 @@ +/** @file + This header file contains the processor power management definitions. + + Acronyms: + PPM Processor Power Management + TM Thermal Monitor + IST Intel(R) Speedstep technology + HT Hyper-Threading Technology + + Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _POWER_MGMT_COMMON_H_ +#define _POWER_MGMT_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PM_CST_LVL2 0x14 + +#define FADT_C3_LATENCY 57 +#define FADT_C3_LATENCY_DISABLED 1001 + +#define NATIVE_PSTATE_LATENCY 10 +#define PSTATE_BM_LATENCY 10 +#define MP_TIMEOUT_FOR_STARTUP_ALL_APS 0 ///< Set 0 for BSP always wait for APs + +/// +/// Limit the number of P-states to 16. Up to Windows 7, the OS allocates 1KB buffer for the PSS package. +/// So the maximum number of P-state OS can handle is 19. This is not an OS issue. Having too many P-states +/// is not good for the system performance. +/// +#define FVID_MAX_STATES 20 +#define FVID_MIN_STEP_SIZE 1 + +/// +/// Cpu Brandstring length +/// +#define MAXIMUM_CPU_BRAND_STRING_LENGTH 48 +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) +#define EFI_IDIV_ROUND(r, s) ((r) / (s) + (((2 * ((r) % (s))) < (s)) ? 0 : 1)) + +/// +/// Global variables +/// +extern EFI_GUID gCpuAcpiTableStorageGuid; + +/// +/// SiCpuPolicy Revision +/// +extern UINT8 mCpuPolicyRevision; + +extern POWER_MGMT_CONFIG *mPowerMgmtConfig; ///< Power Managment policy configurations +extern EFI_CPUID_REGISTER mCpuid01; // CPUID 01 values +/// +/// Values for FVID table calculate. +/// +extern UINT16 mTurboBusRatio; +extern UINT16 mMaxBusRatio; +extern UINT16 mMinBusRatio; +extern UINT16 mProcessorFlavor; +extern UINT16 mBspBootRatio; +extern UINT16 mPackageTdp; +extern UINT16 mPackageTdpWatt; +extern UINT16 mCpuConfigTdpBootRatio; +extern UINT16 mCustomPowerUnit; +extern UINT16 mCpuCacheSize; +/// +/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit) +/// +extern UINT8 mProcessorPowerUnit; +/// +/// Fractional part of Processor Time Unit in seconds. (i.e Unit is 1/mProcessorTimeUnit) +/// +extern UINT8 mProcessorTimeUnit; +/// +/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +extern UINT16 mPackageMaxPower; +/// +/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +extern UINT16 mPackageMinPower; +extern UINT8 mControllableTdpEnable; ///< Controllable TDP Enable/Disable +extern UINT8 mRatioLimitProgrammble; ///< Programmable Ratio Limit +extern UINT8 mTdpLimitProgrammble; ///< Programmable TDP Limit +extern CPU_GLOBAL_NVS_AREA_PROTOCOL *gCpuGlobalNvsAreaProtocol; ///< CPU GlobalNvs Protocol +extern EFI_MP_SERVICES_PROTOCOL *mMpService; ///< EFI MP SERVICES PROTOCOL + +/// +/// Globals to support updating ACPI Tables +/// +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mApIstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mApCstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCpuSsdtTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mApTstTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCtdpTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0HwpTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mApHwpTable; +extern EFI_ACPI_DESCRIPTION_HEADER *mHwpLvtTable; + +/// +/// ASL SSDT structure layout +/// +#pragma pack(1) +typedef struct { + UINT8 NameOp; ///< First opcode is a NameOp. + UINT32 NameString; ///< 'TDSS' ; Name of object. + UINT8 PackageOp; ///< db 12h ; Sixth OpCode is PackageOp. + UINT16 PackageLen; ///< dw 0h ; Seventh/Eighth OpCode is PackageLength. + UINT8 PackageEntryNum; ///< db 0Ch ; Ninth OpCode is number of package entries. + UINT8 StringPrefix1; ///< 0Dh + UINT64 Cpu0IstStr; ///< 00h + UINT8 StringNull1; ///< 00h + UINT8 DwordPrefix1a; ///< 0Ch + UINT32 Cpu0IstAddr; ///< 00h + UINT8 DwordPrefix1b; ///< 0Ch + UINT32 Cpu0IstLen; ///< 00h + UINT8 StringPrefix2; ///< 0Dh + UINT64 Cpu1IstStr; ///< 00h + UINT8 StringNull2; ///< 00h + UINT8 DwordPrefix2a; ///< 0Ch + UINT32 ApIstAddr; ///< 00h + UINT8 DwordPrefix2b; ///< 0Ch + UINT32 ApIstLen; ///< 00h + UINT8 StringPrefix3; ///< 0Dh + UINT64 Cpu0CstStr; ///< 00h + UINT8 StringNull3; ///< 00h + UINT8 DwordPrefix3a; ///< 0Ch + UINT32 Cpu0CstAddr; ///< 00h + UINT8 DwordPrefix3b; ///< 0Ch + UINT32 Cpu0CstLen; ///< 00h + UINT8 StringPrefix4; ///< 0Dh + UINT64 ApCstStr; ///< 00h + UINT8 StringNull4; ///< 00h + UINT8 DwordPrefix4a; ///< 0Ch + UINT32 ApCstAddr; ///< 00h + UINT8 DwordPrefix4b; ///< 0Ch + UINT32 ApCstLen; ///< 00h + UINT8 StringPrefix5; ///< 0Dh + UINT64 Cpu0HwpStr; ///< 00h + UINT8 StringNull5; ///< 00h + UINT8 DwordPrefix5a; ///< 0Ch + UINT32 Cpu0HwpAddr; ///< 00h + UINT8 DwordPrefix5b; ///< 0Ch + UINT32 Cpu0HwpLen; ///< 00h + UINT8 StringPrefix6; ///< 0Dh + UINT64 ApHwpStr; ///< 00h + UINT8 StringNull6; ///< 00h + UINT8 DwordPrefix6a; ///< 0Ch + UINT32 ApHwpAddr; ///< 00h + UINT8 DwordPrefix6b; ///< 0Ch + UINT32 ApHwpLen; ///< 00h + UINT8 StringPrefix7; ///< 0Dh + UINT64 HwpLvtStr; ///< 00h + UINT8 StringNull7; ///< 00h + UINT8 DwordPrefix7a; ///< 0Ch + UINT32 HwpLvtAddr; ///< 00h + UINT8 DwordPrefix7b; ///< 0Ch + UINT32 HwpLvtLen; ///< 00h +} SSDT_LAYOUT; +#pragma pack() + +// +// FVID Table Information +// Default FVID table +// One header field plus states +// +extern UINT16 mNumberOfStates; +extern FVID_TABLE *mFvidPointer; + +// +// Function prototypes +// + +/** + Patch the native _PSS package with the EIST values + Uses ratio/VID values from the FVID table to fix up the control values in the _PSS. + + (1) Find _PSS package: + (1.1) Find the _PR_CPU0 scope. + (1.2) Save a pointer to the package length. + (1.3) Find the _PSS AML name object. + (2) Resize the _PSS package. + (3) Fix up the _PSS package entries + (3.1) Check Turbo mode support. + (3.2) Check Dynamic FSB support. + (4) Fix up the Processor block and \_PR_CPU0 Scope length. + (5) Update SSDT Header with new length. + + @retval EFI_SUCCESS On success + @retval EFI_NOT_FOUND If _PR_.CPU0 scope is not foud in the ACPI tables + +**/ +EFI_STATUS +AcpiPatchPss ( + VOID + ); + +/** + Configure the FACP for C state support + +**/ +VOID +ConfigureFadtCStates ( + VOID + ); + +/** + Locate the CPU ACPI tables data file and read ACPI SSDT tables. + Publish the appropriate SSDT based on current configuration and capabilities. + + @retval EFI_SUCCESS - On success + @retval EFI_NOT_FOUND - Required firmware volume not found + @retval EFI_OUT_OF_RESOURCES - No enough resoruces (such as out of memory). + @retval Appropiate failure code on error + +**/ +EFI_STATUS +InitCpuAcpiTable ( + VOID + ); + +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf new file mode 100644 index 0000000000..470a0b1b4d --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf @@ -0,0 +1,67 @@ +## @file +# Power Management module. +# +# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = PowerMgmtDxe + FILE_GUID = f7731b4c-58a2-4df4-8980-5645d39ece58 + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + ENTRY_POINT = InitPowerManagement + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + IoLib + PciLib + HobLib + AslUpdateLib + PcdLib + S3BootScriptLib + CpuPlatformLib + MmPciLib + TimerLib + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + BroxtonSiPkg/BroxtonSiPrivate.dec + +[Pcd] + +[Sources] + PowerMgmtInit.h + PowerMgmtInit.c + PowerMgmtCommon.h + PerformanceStates.c + MiscFunctions.c + +[Protocols] + gPowerMgmtInitDoneProtocolGuid ## PRODUCES + gEfiMpServiceProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + gCpuGlobalNvsAreaProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gCpuInfoProtocolGuid ## CONSUMES + +[Guids] + gCpuAcpiTableStorageGuid ## UNDEFINED + gCpuInitDataHobGuid ## UNDEFINED + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiMpServiceProtocolGuid AND + gCpuGlobalNvsAreaProtocolGuid AND + gEfiGlobalNvsAreaProtocolGuid diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c new file mode 100644 index 0000000000..71392c9de6 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c @@ -0,0 +1,273 @@ +/** @file + Processor Power Management initialization code. This code determines current + user configuration and modifies and loads ASL as well as initializing chipset + and processor features to enable the proper power management. + + Acronyms: + PPM: Processor Power Management + TM: Thermal Monitor + IST: Intel(R) Speedstep technology + HT: Hyper-Threading Technology + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtInit.h" +#include "PowerMgmtCommon.h" +#include +#include + +/// +/// Global variables +/// + +/// +/// Power Managment policy configurations +/// +GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig = NULL; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_CPUID_REGISTER mCpuid01 = { 0, 0, 0, 0 }; // CPUID 01 values + +/// +/// Values for FVID table calculate. +/// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTurboBusRatio = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMaxBusRatio = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMinBusRatio = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mProcessorFlavor = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mBspBootRatio = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageTdp = 0; ///< Processor TDP value in MSR_PACKAGE_POWER_SKU. +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageTdpWatt = 0; ///< Processor TDP value in Watts. +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCpuConfigTdpBootRatio = 0; ///< Config TDP Boot settings +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCustomPowerUnit = 1; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCpuCacheSize = 0; ///< Cache Size in KB +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mCpuPolicyRevision = 0; + +/// +/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit) +/// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mProcessorPowerUnit = 0; + +/// +/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageMaxPower = 0; + +/// +/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR +/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR +/// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageMinPower = 0; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mControllableTdpEnable = 0; ///< Controllable TDP enable/Disable +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mRatioLimitProgrammble = 0; ///< Programmable Ratio Limit +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTdpLimitProgrammble = 0; ///< Porgrammable TDP Limit +GLOBAL_REMOVE_IF_UNREFERENCED CPU_GLOBAL_NVS_AREA_PROTOCOL *gCpuGlobalNvsAreaProtocol = NULL; ///< CPU GlobalNvs Protocol +GLOBAL_REMOVE_IF_UNREFERENCED EFI_MP_SERVICES_PROTOCOL *mMpService = NULL; + +/// +/// FVID Table Information +/// Default FVID table +/// One header field plus states +/// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mNumberOfStates = 0; +GLOBAL_REMOVE_IF_UNREFERENCED FVID_TABLE *mFvidPointer = NULL; + +/// +/// Globals to support updating ACPI Tables +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApIstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApCstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpuSsdtTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApTstTable = NULL; +GLOBAL_REMOVE_IF_UNREFERENCED CPU_INIT_DATA_HOB *mCpuInitDataHob = NULL; + +/** + Initialize the power management support. + This function will do boot time configuration: + Detect HW capabilities and SW configuration + Initialize HW and software state (primarily MSR and ACPI tables) + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The driver installes/initialized correctly. + @retval Driver will ASSERT in debug builds on error. + PPM functionality is considered critical for mobile systems. + +**/ +EFI_STATUS +EFIAPI +InitPowerManagement ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + VOID *Hob; + + Handle = NULL; + // + // Get CPU Init Data Hob + // + Hob = GetFirstGuidHob (&gCpuInitDataHobGuid); + if (Hob == NULL) { + DEBUG ((DEBUG_ERROR, "CPU Data HOB not available\n")); + return EFI_NOT_FOUND; + } + mCpuInitDataHob = (CPU_INIT_DATA_HOB *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE)); + + // + // Initialize the Global pointer for Power Managment Policy + // + mPowerMgmtConfig = (POWER_MGMT_CONFIG *) (UINTN) mCpuInitDataHob->PowerMgmtConfig; + mFvidPointer = (FVID_TABLE *) (UINTN) mCpuInitDataHob->FvidTable; + + // + // Initialize Power management Global variables + // + InitPowerManagementGlobalVariables (); + + // + // Initialize CPU Power management code (Patch and install CPU ACPI tables, save S3 boot script info) + // + Status = InitPpmDxe (); + ASSERT_EFI_ERROR (Status); + + // + // Install the PowerMgmtInitDone Protocol so that PowerMgmtS3 driver can load to save the MSRs for S3 resume + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gPowerMgmtInitDoneProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +/** + Initializes the platform power management global variable. + This must be called prior to any of the functions being used. + +**/ +VOID +InitPowerManagementGlobalVariables ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Locate CPU GlobalNvs Protocol. + // + Status = gBS->LocateProtocol ( + &gCpuGlobalNvsAreaProtocolGuid, + NULL, + (VOID **) &gCpuGlobalNvsAreaProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "CPU GloableNvs protocol not found")); + } + ASSERT_EFI_ERROR (Status); + if (gCpuGlobalNvsAreaProtocol != NULL) { + gCpuGlobalNvsAreaProtocol->Area->Cpuid = GetCpuFamily () | GetCpuStepping (); + } + + // + // Locate MP service protocol + // + Status = gBS->LocateProtocol ( + &gEfiMpServiceProtocolGuid, + NULL, + (VOID **) &mMpService + ); + ASSERT_EFI_ERROR (Status); + + // + // Locate ACPI table protocol + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable); + ASSERT_EFI_ERROR (Status); + + return; +} + + +/** + Initialize the processor power management based on hardware capabilities + and user configuration settings. + + @retval EFI_SUCCESS On success + @retval Appropiate failure code on error + +**/ +EFI_STATUS +InitPpmDxe ( + VOID + ) +{ + EFI_STATUS Status; +#if (ENBDT_PF_ENABLE == 1) + UINT8 Data8; +#endif + UINTN MaximumNumberOfCpus; + UINTN NumberOfEnabledCpus; + + Status = EFI_SUCCESS; + + // + // Update Fadt table for C State support. + // + if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) { + ConfigureFadtCStates (); + } + + Status = InitCpuAcpiTable (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update Logical Processor Count + // + mMpService->GetNumberOfProcessors ( + mMpService, + &MaximumNumberOfCpus, + &NumberOfEnabledCpus + ); + gCpuGlobalNvsAreaProtocol->Area->LogicalProcessorCount = (UINT8) MaximumNumberOfCpus; + + // + // Save the SW SMI number to trigger SMI to restore the MSRs when resuming from S3 + // +#if (ENBDT_PF_ENABLE == 1) + Data8 = mPowerMgmtConfig->S3RestoreMsrSwSmiNumber; + S3BootScriptSaveIoWrite ( + S3BootScriptWidthUint8, + (UINTN) (R_PCH_APM_CNT), + 1, + &Data8 + ); +#endif + + return Status; +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h new file mode 100644 index 0000000000..3062c92a31 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h @@ -0,0 +1,75 @@ +/** @file + This header file contains processors power management definitions. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef _POWER_MANAGEMENT_H_ +#define _POWER_MANAGEMENT_H_ + +#include "PowerMgmtCommon.h" + +// +// Function prototypes +// +/** + Initialize the power management support. + This function will do boot time configuration: + Install into SMRAM/SMM + Detect HW capabilities and SW configuration + Initialize HW and software state (primarily MSR and ACPI tables) + Install SMI handlers for runtime interfacess + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The driver installed/initialized correctly. + @retval Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems. + +**/ +EFI_STATUS +EFIAPI +InitPowerManagement ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Initializes the CPU power management global variable. + This must be called prior to any of the functions being used. + +**/ +VOID +InitPowerManagementGlobalVariables ( + VOID + ); + +/** + Initialize the platform power management based on hardware capabilities + and user configuration settings. + + This includes creating FVID table, updating ACPI tables, + and updating processor and chipset hardware configuration. + + This should be called prior to any Px, Cx, Tx activity. + + @retval EFI_SUCCESS On success + @retval Appropiate failure code on error + +**/ +EFI_STATUS +InitPpmDxe ( + VOID + ); +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c new file mode 100644 index 0000000000..7a2bb7f76b --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c @@ -0,0 +1,1267 @@ +/** @file + Digital Thermal Sensor (DTS) driver. + This SMM driver configures and supports the Digital Thermal Sensor features for the platform. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtSmm.h" +#include "PowerMgmtDts.h" + +// +// Global variables +// +GLOBAL_REMOVE_IF_UNREFERENCED CPU_GLOBAL_NVS_AREA *mCpuGlobalNvsAreaPtr; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDtsValue; + +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mDtsEnabled; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDtsTjMax; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mUpdateDtsInEverySmi; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mNoOfThresholdRanges; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 (*mDtsThresholdTable)[3]; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mIsPackageTempMsrAvailable; +/// +/// The table is updated for the current CPU. +/// +GLOBAL_REMOVE_IF_UNREFERENCED 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 ( + IN VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + UINT8 Temperature; + UINT8 DefApicId; + EFI_CPUID_REGISTER CpuidRegisters; + UINT8 *TempPointer; + + AsmCpuid ( + 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 (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; +} + + +/** + 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] ContextData Pointer to data buffer to be used for handler. + @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message + @param[in, out] 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 CONST VOID *ContextData, OPTIONAL + IN OUT VOID *CommunicationBuffer, OPTIONAL + IN OUT UINTN *SourceSize OPTIONAL + ) +{ + 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 (mIsPackageTempMsrAvailable) { + // + // 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. + // + mCpuGlobalNvsAreaPtr->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 + +**/ +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) && (mCpuGlobalNvsAreaPtr->DtsAcpiEnable == 0)) { + + } + // + // Set the thermal trip toints as needed. + // + mCpuGlobalNvsAreaPtr->PackageDTSTemperature = 0; + + // + // Set the Package thermal sensor thresholds + // + PackageDigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->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] ContextData Pointer to data buffer to be used for handler. + @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message + @param[in, out] 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 CONST VOID *ContextData, OPTIONAL + IN OUT VOID *CommunicationBuffer, OPTIONAL + IN OUT UINTN *SourceSize OPTIONAL + ) +{ + 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 (mIsPackageTempMsrAvailable) { + 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 < gSmst->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 + // + + // + // 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. + // + mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + + // + // Set the BSP thermal sensor thresholds + // + DigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature); + + // + // Set the AP thermal sensor thresholds and update temperatures + // + for (Index = 1; Index < gSmst->NumberOfCpus / 2; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature + ); + } + + for (Index = gSmst->NumberOfCpus / 2; Index < gSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mCpuGlobalNvsAreaPtr->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 function executes DTS procedures for preparing to enter S3. + + @param[in] Handle Handle of the callback + @param[in] Context The dispatch context + @param[in, out] CommBuffer Pointer to the buffer that contains the communication Message + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS DTS disabled + +**/ +EFI_STATUS +EFIAPI +DtsS3EntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + + // + // Clear the Digital Thermal Sensor flag in ACPI NVS. + // + mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_DISABLE; + + // + // Clear the enable flag. + // + mDtsEnabled = FALSE; + + return EFI_SUCCESS; +} + + +/** + Performs initialization of the threshold table. + + @retval EFI_SUCCESS Threshold tables initialized successfully. + +**/ +EFI_STATUS +InitThresholdTable ( + 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 +InitDigitalThermalSensor ( + VOID + ) +{ + UINTN Index; + + if (mDtsValue != DTS_OUT_OF_SPEC_ONLY) { + // + // Initialize the DTS threshold table. + // + InitThresholdTable (); + + // + // 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. + // + mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0; + mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0; + mCpuGlobalNvsAreaPtr->PackageDTSTemperature = 0; + if (mIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->PackageDTSTemperature); + } else { + DigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature); + for (Index = 1; Index < gSmst->NumberOfCpus / 2; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature + ); + } + for (Index = gSmst->NumberOfCpus / 2; Index < gSmst->NumberOfCpus; Index++) { + RunOnSpecificLogicalProcessor ( + DigitalThermalSensorSetThreshold, + Index, + &mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature + ); + } + } + mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_ENABLE; + } else { + // + // Enable Out Of Spec Interrupt + // + if (mIsPackageTempMsrAvailable) { + PackageDigitalThermalSensorSetOutOfSpecInterrupt (NULL); + } else { + RunOnAllLogicalProcessors (DigitalThermalSensorSetOutOfSpecInterrupt, NULL); + } + + mCpuGlobalNvsAreaPtr->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 ( + IN VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + // + // First, clear our log bits + // + MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS); + if (mDtsValue != DTS_OUT_OF_SPEC_ONLY) { + MsrData.Qword &= (UINT64) ~THERM_STATUS_LOG_MASK; + } else { + MsrData.Qword &= (UINT64) ~B_OUT_OF_SPEC_STATUS_LOG; + } + + AsmWriteMsr64 (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 (gSmst->NumberOfCpus > 1) { + MsrData.Qword |= (UINT64) 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 ( + IN VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + // + // First, clear our log bits + // + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS); + if (mDtsValue != 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 (gSmst->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 + ) +{ + EFI_STATUS Status; + UINT8 Pm1Cntl; + UINT8 GpeCntl; + + // + // Check SCI enable + // + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + SMM_IO_UINT8, + mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, + 1, + &Pm1Cntl + ); + + if ((Pm1Cntl & B_PCH_ACPI_PM1_CNT_SCI_EN) != 0) { + // + // Set SWGPE Status + // + Status = gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + SMM_IO_UINT8, + mAcpiBaseAddr + R_ACPI_GPE_CNTL, + 1, + &GpeCntl + ); + GpeCntl |= B_SWGPE_CTRL; + Status = gSmst->SmmIo.Io.Write ( + &gSmst->SmmIo, + SMM_IO_UINT8, + mAcpiBaseAddr + R_ACPI_GPE_CNTL, + 1, + &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 ( + IN 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 ( + IN 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 ((mDtsValue != 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 (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 ((mDtsValue != 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 + +**/ +VOID +EFIAPI +DigitalThermalSensorSetOutOfSpecInterrupt ( + IN VOID *Buffer + ) +{ + MSR_REGISTER MsrData; + + // + // Enable Out Of Spec interrupt + // + MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_INTERRUPT); + MsrData.Qword |= (UINT64) 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 ( + IN 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 + +**/ +VOID +EFIAPI +DigitalThermalSensorSetThreshold ( + IN VOID *Buffer + ) +{ + UINT8 ThresholdEntry; + MSR_REGISTER MsrData; + UINT8 Temperature; + + // + // Read the temperature + // + MsrData.Qword = AsmReadMsr64 (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]; + DEBUG ((DEBUG_INFO, "CPU DTS Threshold #1 - %x\n", MsrData.Bytes.SecondByte)); + DEBUG ((DEBUG_INFO, "CPU DTS Threshold #2 - %x\n", MsrData.Bytes.ThirdByte)); + // + // Enable interrupts + // + MsrData.Qword |= (UINT64) TH1_ENABLE; + MsrData.Qword |= (UINT64) 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 &= (UINT64) ~TH1_ENABLE; + } + + AsmWriteMsr64 (EFI_MSR_IA32_THERM_INTERRUPT, MsrData.Qword); + } + + // + // Clear the threshold log bits + // + MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS); + MsrData.Qword &= (UINT64) ~THERM_STATUS_THRESHOLD_LOG_MASK; + AsmWriteMsr64 (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 ( + IN VOID *Buffer + ) +{ + UINT8 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) { + // + // 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 ( + IN 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 ( + IN 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 one specific logical processors, passing in the + parameter buffer to the procedure. + + @param[in, out] Procedure The function to be run. + @param[in] Index Indicate which logical processor should execute this procedure + @param[in, out] 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 = gSmst->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. + // + MicroSecondDelay (DTS_WAIT_PERIOD); + } + } + + return EFI_SUCCESS; +} + + +/** + Digital Thermal Sensor (DTS) SMM driver function. + + @param[in] ImageHandle Image handle for this driver image + + @retval EFI_SUCCESS Driver initialization completed successfully + @retval EFI_OUT_OF_RESOURCES Error when allocating required memory buffer. + +**/ +EFI_STATUS +EFIAPI +InstallDigitalThermalSensor ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + MSR_REGISTER MsrData; + CPU_GLOBAL_NVS_AREA_PROTOCOL *CpuGlobalNvsAreaProtocol; + EFI_HANDLE SxDispatchHandle; + EFI_CPUID_REGISTER Cpuid06; + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext; + EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatchProtocol; + VOID *Hob; + CPU_INIT_DATA_HOB *mCpuInitDataHob; + CPU_CONFIG *mCpuConfig; + + Handle = NULL; + + // + // Get CPU Init Data Hob + // + Hob = GetFirstGuidHob (&gCpuInitDataHobGuid); + if (Hob == NULL) { + DEBUG ((DEBUG_ERROR, "CPU Data HOB not available\n")); + return EFI_NOT_FOUND; + } + mCpuInitDataHob = (CPU_INIT_DATA_HOB *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE)); + mCpuConfig = (CPU_CONFIG *) ((UINTN) mCpuInitDataHob->CpuConfig); + + // + // Check if DTS disabled in setup. + // + if (mCpuConfig->EnableDts == CPU_FEATURE_DISABLE) { + DEBUG ((DEBUG_WARN, "DTS not enabled/supported, so driver not loaded into SMM\n")); + return EFI_SUCCESS; + } + + // + // Verify the code supports the number of processors present. + // + ASSERT_EFI_ERROR (gSmst->NumberOfCpus <= MAX_NUMBER_OF_THREADS_SUPPORTED); + + // + // Get the ACPI Base Address + // + mAcpiBaseAddr = (UINT16)PcdGet16(PcdScAcpiIoPortBaseAddress); + + // + // Initialize DTS setup value + // + mDtsValue = (UINT8) mCpuConfig->EnableDts; + + // + // Locate CPU Global NVS area + // + Status = gBS->LocateProtocol (&gCpuGlobalNvsAreaProtocolGuid, NULL, (VOID **) &CpuGlobalNvsAreaProtocol); + ASSERT_EFI_ERROR (Status); + mCpuGlobalNvsAreaPtr = CpuGlobalNvsAreaProtocol->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); + + mIsPackageTempMsrAvailable = (((UINT8) (mCpuConfig->PackageDts) && ((Cpuid06.RegEax >> 6) & 0x01) ) ? 1: 0); + DEBUG ((DEBUG_INFO, "Is Package DTS Supported: %x\n", mIsPackageTempMsrAvailable)); + mCpuGlobalNvsAreaPtr->IsPackageTempMSRAvailable = mIsPackageTempMsrAvailable; + + // + // Register a callback function to handle Digital Thermal Sensor SMIs. + // + if (mCpuConfig->EnableDts != DTS_OUT_OF_SPEC_ONLY) { + Status = gSmst->SmiHandlerRegister (DtsSmiCallback, NULL, &Handle); + ASSERT_EFI_ERROR (Status); + } else { + Status = gSmst->SmiHandlerRegister (DtsOutOfSpecSmiCallback, NULL, &Handle); + ASSERT_EFI_ERROR (Status); + } + + // + // Locate the Sx Dispatch Protocol + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmSxDispatch2ProtocolGuid, 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 (mCpuConfig->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 (mIsPackageTempMsrAvailable) { + // + // 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 + // + InitDigitalThermalSensor (); + + return EFI_SUCCESS; +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h new file mode 100644 index 0000000000..b8a5c54538 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h @@ -0,0 +1,369 @@ +/** @file + Defines and prototypes for the Digital Thermal Sensor SMM driver. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _POWER_MGMT_DTS_H_ +#define _POWER_MGMT_DTS_H_ + +// +// Include files +// +#include +#include +#include +#include +#include +#include +#include +#include "PowerMgmtDtsLib.h" + +#define MSR_IA32_THERM_STATUS 0x0000019C +/// +/// Stall period in microseconds +/// +#define DTS_WAIT_PERIOD 1 +#define DTS_AP_SAFE_RETRY_LIMIT 3 +/// +/// Define module definitions +/// +#define TJ_MAX 110 +#define DTS_CRITICAL_TEMPERATURE 255 + +// +// Generic definitions for DTS +// +#define DTS_OUT_OF_SPEC_ONLY 2 +#define DTS_OUT_OF_SPEC_OCCURRED 3 + +#define DTS_SAMPLE_RATE 0x10 +#define EFI_MSR_XAPIC_BASE 0x1B +#define TH1_VALUE 8 +#define TH1_ENABLE (1 << 15) +#define TH2_VALUE 16 +#define TH2_ENABLE (1 << 23) +#define OFFSET_MASK (0x7F) +#define OVERHEAT_INTERRUPT_ENABLE (1 << 4) + +#define B_OUT_OF_SPEC_STATUS (1 << 4) +#define B_OUT_OF_SPEC_STATUS_LOG (1 << 5) +#define B_THERMAL_THRESHOLD_1_STATUS (1 << 6) +#define B_THERMAL_THRESHOLD_1_STATUS_LOG (1 << 7) +#define B_THERMAL_THRESHOLD_2_STATUS (1 << 8) +#define B_THERMAL_THRESHOLD_2_STATUS_LOG (1 << 9) +#define B_READING_VALID (1 << 31) + +#define EFI_MSR_IA32_TEMPERATURE_TARGET 0x1A2 +#define EFI_MSR_EXT_XAPIC_LVT_THERM 0x833 +#define EFI_MSR_MISC_PWR_MGMT 0x1AA +#define B_LOCK_THERMAL_INT (1 << 22) + +#define THERM_STATUS_LOG_MASK (B_THERMAL_THRESHOLD_2_STATUS_LOG | B_THERMAL_THRESHOLD_1_STATUS_LOG | B_OUT_OF_SPEC_STATUS_LOG) +#define THERM_STATUS_THRESHOLD_LOG_MASK (B_THERMAL_THRESHOLD_2_STATUS_LOG | B_THERMAL_THRESHOLD_1_STATUS_LOG) + +#define EFI_MSR_IA32_PACKAGE_THERM_STATUS 0x1B1 +#define EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT 0x1B2 + +#define B_DTS_IO_TRAP (1 << 2) +#define B_SWGPE_CTRL (1 << 1) +#define DTS_IO_TRAP_REGISTER_LOW_DWORD (0x00040001 + ICH_DTS_IO_TRAP_BASE_ADDRESS) ///< DigitalThermalSensor IO Trap High DWord value +#define DTS_IO_TRAP_REGISTER_HIGH_DWORD 0x000200F0 ///< DigitalThermalSensor IO Trap High DWord value +#define LOCAL_APIC_THERMAL_DEF 0xFEE00330 +#define B_INTERRUPT_MASK (1 << 16) +#define B_DELIVERY_MODE (0x07 << 8) +#define V_MODE_SMI (0x02 << 8) +#define B_VECTOR (0xFF << 0) + +#define DTS_NUMBER_THRESHOLD_RANGES 9 ///< How many ranges are in the threshold table +#define IO_TRAP_INIT_AP_DTS_FUNCTION 0x0A ///< Enable AP DigitalThermalSensor function +#define IO_TRAP_INIT_DTS_FUNCTION_AFTER_S3 0x14 ///< Enable Digital Thermal Sensor function after resume from S3 +#define IO_TRAP_DISABLE_UPDATE_DTS 0x1E ///< Disable update DTS temperature and threshold value in every SMI +#define INIT_DTS_SCF_MIN 0x10 ///< SCF Minimum value. +#define INIT_DTS_SCF_UNITY 0x20 ///< SCF Unity Value. +#define INIT_DTS_SCF_MAX 0x30 ///< SCF Maximum value. +#define UPDATE_DTS_EVERY_SMI TRUE ///< Update DTS temperature and threshold value in every SMI +#define R_PCH_ACPI_PM1_CNT 0x04 +#define B_PCH_ACPI_PM1_CNT_SCI_EN 0x00000001 +#define R_PCH_LPC_ACPI_BASE 0x40 +#define PCI_DEVICE_NUMBER_PCH_LPC 31 +#define MAX_NUMBER_OF_THREADS_SUPPORTED 8 ///< Max number of threads supported by processor. + + +/// +/// Enumerate a DTS event type +/// +typedef enum { + DtsEventNone, + DtsEventThreshold, + DtsEventOutOfSpec, + DtsEventMax +} DTS_EVENT_TYPE; + +// +// Function declarations +// +/** + Runs the specified procedure on one specific logical processors, passing in the + parameter buffer to the procedure. + + @param[in, out] Procedure The function to be run. + @param[in] Index Indicate which logical processor should execute this procedure + @param[in, out] 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 + ); + +/** + 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] ContextData Pointer to data buffer to be used for handler. + @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message + @param[in, out] 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 CONST VOID *ContextData, OPTIONAL + IN OUT VOID *CommunicationBuffer, OPTIONAL + IN OUT UINTN *SourceSize OPTIONAL + ); + +/** + 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 + ); + +/** + Perform first time initialization of the Digital Thermal Sensor + + @retval EFI_SUCCESS Init Digital Thermal Sensor successfully + +**/ +EFI_STATUS +InitDigitalThermalSensor ( + VOID + ); + +/** + Initializes the Thermal Sensor Control MSR + + This function must be AP safe. + + @param[in] Buffer Unused. + +**/ +VOID +EFIAPI +DigitalThermalSensorEnable ( + IN VOID *Buffer + ); + +/** + Initializes the Package Thermal Sensor Control MSR + + @param[in] Buffer Unused. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +PackageDigitalThermalSensorEnable ( + IN VOID *Buffer + ); + +/** + Generates a _GPE._L02 SCI to an ACPI OS. + +**/ +VOID +DigitalThermalSensorSetSwGpeSts ( + VOID + ); + +/** + 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 + ); + +/** + 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 ( + IN DTS_EVENT_TYPE *PkgEventType + ); + +/** + 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 ( + IN DTS_EVENT_TYPE *EventType + ); + +/** + 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 ( + IN VOID *Buffer + ); + +/** + 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 ( + IN VOID *Buffer + ); + +/** + 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 ( + IN VOID *Buffer + ); + +/** + 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 ( + IN VOID *Buffer + ); + +/** + 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 ( + IN VOID *Buffer + ); + +/** + Disables the Thermal Interrupt in the core Local APIC. + + @param[in] Buffer Unused + +**/ +VOID +EFIAPI +DigitalThermalSensorDisableSmi ( + IN VOID *Buffer + ); + +/** + Performs initialization of the threshold table. + + @retval EFI_SUCCESS Threshold tables initialized successfully. + +**/ +EFI_STATUS +InitThresholdTable ( + VOID + ); + +/** + This function executes DTS procedures for preparing to enter S3. + + @param[in] Handle Handle of the callback + @param[in] Context The dispatch context + @param[in, out] CommBuffer Pointer to the buffer that contains the communication Message + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS DTS disabled + +**/ +EFI_STATUS +EFIAPI +DtsS3EntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ); +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h new file mode 100644 index 0000000000..f66f90bbb2 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h @@ -0,0 +1,32 @@ +/** @file + Defines and prototypes for the DigitalThermalSensor SMM driver. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _POWER_MGMT_DTS_LIB_H_ +#define _POWER_MGMT_DTS_LIB_H_ + + +/** + Read CPU temperature from platform diode + + @retval TemperatureOfDiode Return the CPU temperature of platform diode + +**/ +UINT8 +ReadPlatformThermalDiode ( + VOID + ); + +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c new file mode 100644 index 0000000000..4385320544 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c @@ -0,0 +1,221 @@ +/** @file + This is the SMM driver for saving and restoring the powermanagement related MSRs. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtSmm.h" + +/// +/// MSR table for S3 resume +/// +STATIC EFI_MSR_VALUES mMsrValues[] = { + { MSR_IA32_PERF_CTRL, 0, B_IA32_PERF_CTRLP_STATE_TARGET, TRUE }, + { MSR_PMG_IO_CAPTURE_BASE, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PMG_CST_CONFIG, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_MISC_PWR_MGMT, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_IA32_MISC_ENABLE, 0, B_CPUID_POWER_MANAGEMENT_EAX_TURBO | B_MSR_IA32_MISC_DISABLE_TURBO | B_MSR_IA32_MISC_ENABLE_MONITOR | B_MSR_IA32_MISC_ENABLE_TME | B_MSR_IA32_MISC_ENABLE_EIST, TRUE }, + { MSR_POWER_CTL, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PACKAGE_POWER_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_PL3_CONTROL, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_IA32_ENERGY_PERFORMANCE_BIAS, 0, 0xFFFFFFFFFFFFFFFF, TRUE }, + { MSR_DDR_RAPL_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, FALSE }, + { MSR_TURBO_RATIO_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE } +}; + +/** + Save processor MSR runtime settings for S3. + + @retval EFI_SUCCESS Processor MSR setting is saved. + +**/ +EFI_STATUS +S3SaveMsr ( + VOID + ) +{ + UINT32 Index; + EFI_CPUID_REGISTER Cpuid06 = { 0, 0, 0, 0 }; + UINT64 MsrValue; + + for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) { + DEBUG ((DEBUG_INFO, " MSR Number: %x\n", mMsrValues[Index].Index)); + if (mMsrValues[Index].Index == MSR_IA32_ENERGY_PERFORMANCE_BIAS) { + // + // MSR_IA32_ENERGY_PERFORMANCE_BIAS (1B0h) is accessible only if CPUID(6), ECX[3] = 1 to indicate feature availability. + // + AsmCpuid (CPUID_FUNCTION_6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx); + if (!(Cpuid06.RegEcx & B_CPUID_POWER_MANAGEMENT_ECX_ENERGY_EFFICIENT_POLICY_SUPPORT)) { + mMsrValues[Index].RestoreFlag = FALSE; + continue; + } + } + // + // Read Platform Info MSR + // + MsrValue = AsmReadMsr64 (MSR_PLATFORM_INFO); + + // + // Check PLATFORM_INFO MSR[34:33] > 0 before accessing the MSR_CONFIG_TDP_CONTROL + // + if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && + ((RShiftU64 (MsrValue, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET) & 0x03)) + ) { + mMsrValues[Index].RestoreFlag = TRUE; + } + + if (mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) { + mMsrValues[Index].RestoreFlag = TRUE; + } + if (mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) { + mMsrValues[Index].RestoreFlag = TRUE; + } + + // + // PL3 is supported + // + if (mMsrValues[Index].Index == MSR_PL3_CONTROL) { + mMsrValues[Index].RestoreFlag = TRUE; + } + + if (mMsrValues[Index].RestoreFlag == TRUE) { + mMsrValues[Index].Value = AsmReadMsr64 (mMsrValues[Index].Index); + DEBUG ((DEBUG_INFO, " MSR Number %x read Done \n", mMsrValues[Index].Index)); + } + } + + return EFI_SUCCESS; +} + + +/** + Restore processor MSR runtime settings for S3. + + @param[in] DispatchHandle The handle of this callback, obtained when registering + @param[in] DispatchContex Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + +**/ +VOID +S3RestoreMsr ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext + ) +{ + // + // Restore MSR's on all logical processors. + // + RunOnAllLogicalProcessors (ApSafeRestoreMsr, NULL); +} + + +/** + Runs the specified procedure on all logical processors, passing in the + parameter buffer to the procedure. + + @param[in, out] Procedure The function to be run. + @param[in, out] Buffer Pointer to a parameter buffer. + + @retval EFI_SUCCESS Run the procedure on all logical processors + +**/ +EFI_STATUS +RunOnAllLogicalProcessors ( + IN OUT EFI_AP_PROCEDURE Procedure, + IN OUT VOID *Buffer + ) +{ + UINTN Index; + EFI_STATUS Status; + + // + // Run the procedure on all logical processors. + // + (*Procedure) (Buffer); + for (Index = 1; Index < gSmst->NumberOfCpus; Index++) { + Status = EFI_NOT_READY; + while (Status != EFI_SUCCESS) { + Status = gSmst->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. + // + MicroSecondDelay (PPM_WAIT_PERIOD); + } + } + } + + return EFI_SUCCESS; +} + + +/** + This function will restore MSR settings. + + This function must be MP safe. + + @param[in, out] Buffer Unused + +**/ +VOID +EFIAPI +ApSafeRestoreMsr ( + IN OUT VOID *Buffer + ) +{ + UINT32 Index; + UINT64 MsrValue; + + for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) { + // + // Check RestoreFlag and skip restoring the MSR if it is set to FALSE + // + if (mMsrValues[Index].RestoreFlag == FALSE) { +#ifdef EFI_DEBUG + if (IsBsp ()) { + DEBUG ((DEBUG_INFO, "Skipping MSR : %x as RestoreFalg is set to FALSE \n", mMsrValues[Index].Index)); + } +#endif + continue; + } + // + // Check for Lock bits before programming + // + MsrValue = AsmReadMsr64 (mMsrValues[Index].Index); + if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && (MsrValue & CONFIG_TDP_CONTROL_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) && (MsrValue & MSR_TURBO_ACTIVATION_RATIO_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_PACKAGE_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_PL3_CONTROL) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + if ((mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) { + continue; + } + + MsrValue = AsmReadMsr64 (mMsrValues[Index].Index); + MsrValue &= ~mMsrValues[Index].BitMask; + MsrValue |= (mMsrValues[Index].Value & mMsrValues[Index].BitMask); + AsmWriteMsr64 (mMsrValues[Index].Index, MsrValue); + } + + return; +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c new file mode 100644 index 0000000000..f27b0de904 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c @@ -0,0 +1,102 @@ +/** @file + This is the SMM driver for saving and restoring the powermanagement related MSRs. + + Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PowerMgmtSmm.h" + +/// +/// Global variables +/// +GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG *mCpuConfig; +GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig; + +/** + Initialize the SMM power management Handler. + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS The driver installes/initialized correctly. + @retval EFI_NOT_FOUND CPU Data HOB not available. + +**/ +EFI_STATUS +EFIAPI +PowerMgmtSmmEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + EFI_STATUS Status; + EFI_HANDLE SwHandle; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + VOID *Hob; + CPU_INIT_DATA_HOB *mCpuInitDataHob; + + SwHandle = 0; + DEBUG ((DEBUG_INFO, " PpmSmmEntryPoint Started\n")); + + // + // Get CPU Init Data Hob + // + Hob = GetFirstGuidHob (&gCpuInitDataHobGuid); + if (Hob == NULL) { + DEBUG ((DEBUG_ERROR, "CPU Data HOB not available\n")); + return EFI_NOT_FOUND; + } + mCpuInitDataHob = (CPU_INIT_DATA_HOB *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE)); + mCpuConfig = (CPU_CONFIG *) (UINTN) mCpuInitDataHob->CpuConfig; + mPowerMgmtConfig = (POWER_MGMT_CONFIG *) (UINTN)mCpuInitDataHob->PowerMgmtConfig; + + // + // Locate the ICH SMM SW dispatch protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSwDispatch2ProtocolGuid, + NULL, + (VOID**) &SwDispatch + ); + + // + // Register ACPI S3 MSR restore handler + // + SwContext.SwSmiInputValue = mPowerMgmtConfig->S3RestoreMsrSwSmiNumber; + + Status = SwDispatch->Register ( + SwDispatch, + (EFI_SMM_HANDLER_ENTRY_POINT2) S3RestoreMsr, + &SwContext, + &SwHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Digital Thermal Sensor + // + if (mCpuConfig->EnableDts > 0) { + DEBUG ((DEBUG_INFO, " Install Digital Thermal Sensor \n")); + InstallDigitalThermalSensor (); + } + + // + // Save MSRs for S3 Resume. + // + DEBUG ((DEBUG_INFO, " Saving Processor MSR for S3 Resume \n")); + S3SaveMsr (); + + return EFI_SUCCESS; +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h new file mode 100644 index 0000000000..5261ad5a36 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h @@ -0,0 +1,117 @@ +/** @file + Header file for PowerMgmt Smm Driver. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _POWER_MGMT_SMM_H_ +#define _POWER_MGMT_SMM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPM_WAIT_PERIOD 15 + +extern POWER_MGMT_CONFIG *PowerMgmtConfig; + +typedef struct _EFI_MSR_VALUES { + UINT16 Index; + UINT64 Value; + UINT64 BitMask; + BOOLEAN RestoreFlag; +} EFI_MSR_VALUES; + +/** + Save processor MSR runtime settings for S3. + + @retval EFI_SUCCESS Processor MSR setting is saved. + +**/ +EFI_STATUS +S3SaveMsr ( + VOID + ); + +/** + Runs the specified procedure on all logical processors, passing in the + parameter buffer to the procedure. + + @param[in, out] Procedure The function to be run. + @param[in, out] Buffer Pointer to a parameter buffer. + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +RunOnAllLogicalProcessors ( + IN OUT EFI_AP_PROCEDURE Procedure, + IN OUT VOID *Buffer + ); + +/** + This function will restore MSR settings. + + This function must be MP safe. + + @param[in, out] Buffer Unused + +**/ +VOID +EFIAPI +ApSafeRestoreMsr ( + IN OUT VOID *Buffer + ); + +/** + Restore processor MSR runtime settings for S3. + + @param[in] DispatchHandle The handle of this callback, obtained when registering + @param[in] DispatchContex Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + +**/ +VOID +S3RestoreMsr ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext + ); + +/** + Digital Thermal Sensor (DTS) SMM driver function. + + @param[in] ImageHandle Image handle for this driver image + + @retval EFI_SUCCESS Driver initialization completed successfully + @retval EFI_OUT_OF_RESOURCES Error when allocating required memory buffer. + +**/ +EFI_STATUS +EFIAPI +InstallDigitalThermalSensor ( + VOID + ); +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf new file mode 100644 index 0000000000..a598e91df2 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf @@ -0,0 +1,63 @@ +## @file +# Component description file for PowerManagementSmm driver. +# +# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = PowerMgmtSmm + FILE_GUID = 8F0B5301-C79B-44f1-8FD3-26D73E316700 + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION = 1.10 + ENTRY_POINT = PowerMgmtSmmEntryPoint + +[LibraryClasses] + UefiDriverEntryPoint + HobLib + DebugLib + TimerLib + BaseMemoryLib + CpuPlatformLib + SmmServicesTableLib + AslUpdateLib + MmPciLib + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + BroxtonSiPkg/BroxtonSiPrivate.dec + +[Sources] + PowerMgmtSmm.h + PowerMgmtSmm.c + PowerMgmtS3.c + PowerMgmtDts.h + PowerMgmtDts.c + PowerMgmtDtsLib.h + +[Protocols] + gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES + gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gCpuGlobalNvsAreaProtocolGuid ## CONSUMES + +[Pcd] + gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress ## SOMETIMES_CONSUMES + +[Guids] + gCpuInitDataHobGuid ## UNDEFINED + +[Depex] + gEfiSmmControl2ProtocolGuid AND + gPowerMgmtInitDoneProtocolGuid -- cgit v1.2.3