395 lines
14 KiB
C
395 lines
14 KiB
C
/** @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
|
|
- ITBM: Intel(R) Turbo Boost Max Technology 3.0
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 1999 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
#include "PowerMgmtInit.h"
|
|
#include <Protocol/CpuInfo.h>
|
|
#include <Protocol/MpService.h>
|
|
#include <Register/CommonMsr.h>
|
|
#include <Register/Cpuid.h>
|
|
#include <Library/CpuInfoFruLib.h>
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CPU_NVS_AREA_PROTOCOL *gCpuNvsAreaProtocol = NULL; ///< CPU GlobalNvs Protocol
|
|
#if FixedPcdGetBool(PcdBiosGuardEnable) == 1
|
|
GLOBAL_REMOVE_IF_UNREFERENCED BIOSGUARD_NVS_AREA_PROTOCOL *gBiosGuardNvsAreaProtocol = NULL; ///< BIOS Guard GlobalNvs Protocol
|
|
#endif
|
|
|
|
//
|
|
// 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 EFI_ACPI_DESCRIPTION_HEADER *mCpu0HwpTable = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApHwpTable = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0PsdTable = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApPsdTable = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CPU_INIT_DATA_HOB *mCpuInitDataHob = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_MP_SERVICES_PROTOCOL *mMpService = NULL;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mCoreIndex = 0;
|
|
|
|
typedef struct _MAILBOX_READ {
|
|
UINT32 *MailboxDataPtr;
|
|
UINT32 *MailboxStatus;
|
|
} MAILBOX_READ;
|
|
|
|
/**
|
|
This function to be used with StartUpAllAps for retrieving
|
|
the Max Core Frequency of all Cores.
|
|
|
|
@param[in] VOID *Buffer
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
MailboxReadFavoredCore (
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
MAILBOX_READ *MailboxReadParameters;
|
|
UINT32 FuseCoreMax;
|
|
UINT32 MailboxStatus;
|
|
OC_MAILBOX_INTERFACE MailboxCommand;
|
|
|
|
MailboxReadParameters = (MAILBOX_READ *) Buffer;
|
|
|
|
MailboxCommand.InterfaceData = 0;
|
|
MailboxCommand.Fields.CommandCompletion = MAILBOX_OC_CMD_READ_PER_CORE_RATIO_LIMITS_CMD;
|
|
MailboxRead (MAILBOX_TYPE_OC, MailboxCommand.InterfaceData, &FuseCoreMax, &MailboxStatus);
|
|
MailboxReadParameters->MailboxDataPtr[mCoreIndex] = FuseCoreMax;
|
|
MailboxReadParameters->MailboxStatus[mCoreIndex] = MailboxStatus;
|
|
}
|
|
|
|
/**
|
|
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;
|
|
VOID *Hob;
|
|
|
|
///
|
|
/// 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 VID Table
|
|
///
|
|
mFvidPointer = (FVID_TABLE *) &(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);
|
|
|
|
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;
|
|
UINT32 Index;
|
|
MAILBOX_READ MailboxReadParameters;
|
|
UINTN NumberOfCores;
|
|
UINTN LogProcNum;
|
|
UINTN BspIndex;
|
|
MSR_CORE_THREAD_COUNT_REGISTER MsrCoreThreadCount;
|
|
UINT8 LowestMaxPerf;
|
|
UINT8 EnableItbm;
|
|
EFI_PROCESSOR_INFORMATION MpContext;
|
|
UINT32 BigCoreNumber;
|
|
UINT32 AtomCoreNumber;
|
|
UINT8 ApCoreType;
|
|
|
|
#if FixedPcdGetBool(PcdBiosGuardEnable) == 1
|
|
BIOSGUARD_HOB *BiosGuardHobPtr;
|
|
#endif
|
|
|
|
NumberOfCores = 0;
|
|
LogProcNum = 0;
|
|
MailboxReadParameters.MailboxDataPtr = NULL;
|
|
BspIndex = 0;
|
|
BigCoreNumber = 0;
|
|
AtomCoreNumber = 0;
|
|
|
|
///
|
|
/// Locate CPU Nvs Protocol.
|
|
///
|
|
Status = gBS->LocateProtocol (
|
|
&gCpuNvsAreaProtocolGuid,
|
|
NULL,
|
|
(VOID **) &gCpuNvsAreaProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "CPU GloableNvs protocol not found"));
|
|
}
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (gCpuNvsAreaProtocol != NULL) {
|
|
gCpuNvsAreaProtocol->Area->Cpuid = GetCpuFamily () | GetCpuStepping ();
|
|
}
|
|
|
|
#if FixedPcdGetBool(PcdBiosGuardEnable) == 1
|
|
///
|
|
/// Get BIOS Guard Config Hob
|
|
///
|
|
BiosGuardHobPtr = GetFirstGuidHob (&gBiosGuardHobGuid);
|
|
if (BiosGuardHobPtr != NULL) {
|
|
///
|
|
/// Locate BIOS Guard Nvs Protocol.
|
|
///
|
|
Status = gBS->LocateProtocol (
|
|
&gBiosGuardNvsAreaProtocolGuid,
|
|
NULL,
|
|
(VOID **) &gBiosGuardNvsAreaProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "BIOS Guard Global Nvs protocol not found"));
|
|
}
|
|
}else {
|
|
DEBUG ((DEBUG_ERROR, "BIOS Guard Hob not found, BIOS Guard Global Nvs protocol not initialized"));
|
|
}
|
|
#endif
|
|
|
|
///
|
|
/// Intel Turbo Boost Technology support, locate MP services
|
|
///
|
|
if (IsItbmSupported ()) {
|
|
//
|
|
// Locate the MP services protocol
|
|
// Find the MP Protocol. This is an MP platform, so MP protocol must be there.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &mMpService);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Located MP protocol Status = %r\n", Status));
|
|
return;
|
|
}
|
|
|
|
ZeroMem (&MpContext, sizeof (EFI_PROCESSOR_INFORMATION));
|
|
|
|
MsrCoreThreadCount.Uint64 = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
|
|
NumberOfCores = (UINTN) MsrCoreThreadCount.Bits.Corecount;
|
|
LogProcNum = (UINTN) MsrCoreThreadCount.Bits.Threadcount;
|
|
|
|
|
|
MailboxReadParameters.MailboxDataPtr = AllocateZeroPool (sizeof (UINT32) * NumberOfCores);
|
|
MailboxReadParameters.MailboxStatus = AllocateZeroPool (sizeof (EFI_STATUS) * NumberOfCores);
|
|
|
|
if ((MailboxReadParameters.MailboxDataPtr == NULL) || (MailboxReadParameters.MailboxStatus == NULL)) {
|
|
return;
|
|
}
|
|
|
|
Status = mMpService->WhoAmI (mMpService, &BspIndex);
|
|
//
|
|
// Read Favored Core Information from each core index
|
|
//
|
|
for (Index = 0; Index < LogProcNum; Index++) {
|
|
Status = mMpService->GetProcessorInfo (
|
|
mMpService,
|
|
(UINTN)Index,
|
|
&MpContext
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
if (MpContext.Location.Thread != 0) {
|
|
// Continue when the processor is not 1st thread of Core, i.e. the 2nd, 3rd or 4th thread of Core.
|
|
continue;
|
|
}
|
|
|
|
if (Index == BspIndex){
|
|
MailboxReadFavoredCore ((VOID*) &MailboxReadParameters);
|
|
mCoreIndex++;
|
|
BigCoreNumber++;
|
|
} else {
|
|
mMpService->StartupThisAP (
|
|
mMpService,
|
|
(EFI_AP_PROCEDURE) MailboxReadFavoredCore,
|
|
Index,
|
|
NULL,
|
|
0,
|
|
(VOID*) &MailboxReadParameters,
|
|
NULL
|
|
);
|
|
mCoreIndex++;
|
|
|
|
ApCoreType = 0;
|
|
mMpService->StartupThisAP (
|
|
mMpService,
|
|
(EFI_AP_PROCEDURE) DetectCoreType,
|
|
Index,
|
|
NULL,
|
|
0,
|
|
(UINT8 *) &ApCoreType,
|
|
NULL
|
|
);
|
|
if (ApCoreType == CPUID_CORE_TYPE_INTEL_CORE) {
|
|
BigCoreNumber++;
|
|
} else if (ApCoreType == CPUID_CORE_TYPE_INTEL_ATOM) {
|
|
AtomCoreNumber++;
|
|
}
|
|
}
|
|
}
|
|
///
|
|
/// Find the lowest of core max ratio from OCMB 0x1C[15:8] FusedP0 max ratio
|
|
///
|
|
LowestMaxPerf = 0xFF;
|
|
for (Index = 0; Index < BigCoreNumber; Index++) {
|
|
DEBUG((DEBUG_INFO, "Itbm: Highest performance fused ratio [%d] = %d \n",Index, ((MailboxReadParameters.MailboxDataPtr [Index] >> 8) & 0xFF)));
|
|
DEBUG((DEBUG_INFO, "Itbm: Highest performance current ratio [%d] = %d \n",Index, (MailboxReadParameters.MailboxDataPtr [Index] & 0xFF)));
|
|
|
|
if (LowestMaxPerf > (UINT8) ((MailboxReadParameters.MailboxDataPtr [Index] >> 8) & 0xFF)) {
|
|
LowestMaxPerf = (UINT8) ((MailboxReadParameters.MailboxDataPtr [Index] >> 8) & 0xFF);
|
|
}
|
|
}
|
|
DEBUG((DEBUG_INFO, "Itbm: Highest performance of slowest core LowestMaxPerf = 0x%x \n", LowestMaxPerf));
|
|
|
|
if (gCpuNvsAreaProtocol != NULL) {
|
|
///
|
|
/// We check OCMB 0x1C[15:8] FusedP0 max ratio to identify ITBMT supported
|
|
/// non-ITBMT: All cores are the same value
|
|
/// ITBMT: Difference value among all cores
|
|
///
|
|
EnableItbm = 0;
|
|
if (gCpuNvsAreaProtocol->Area->EnableItbm) {
|
|
for (Index = 0; Index < BigCoreNumber; Index++) {
|
|
if (LowestMaxPerf < (UINT8) ((MailboxReadParameters.MailboxDataPtr [Index] >> 8) & 0xFF)) {
|
|
EnableItbm = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
DEBUG((DEBUG_INFO, "Itbm: Itbm Supported = 0x%x \n", EnableItbm));
|
|
|
|
//
|
|
// Update NVS with ITBMT support and Highest Performance of the slowest core.
|
|
//
|
|
gCpuNvsAreaProtocol->Area->EnableItbm = EnableItbm;
|
|
gCpuNvsAreaProtocol->Area->LowestMaxPerf = LowestMaxPerf;
|
|
}
|
|
}
|
|
///
|
|
/// 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;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Status = InitCpuAcpiTable ();
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
///
|
|
/// Initialise Miscellaneous features
|
|
///
|
|
InitMiscFeatures ();
|
|
|
|
return Status;
|
|
}
|