/** @file | |
This module updates S3 Resume Performance Record in ACPI Firmware Performance | |
Data Table in S3 resume boot mode. | |
This module register report status code listener to collect performance data | |
for S3 Resume Performance Record on S3 resume boot path. | |
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiPei.h> | |
#include <Ppi/ReportStatusCodeHandler.h> | |
#include <Ppi/ReadOnlyVariable2.h> | |
#include <Guid/FirmwarePerformance.h> | |
#include <Guid/Performance.h> | |
#include <Guid/ExtendedFirmwarePerformance.h> | |
#include <Library/PeiServicesLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/TimerLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/LockBoxLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/HobLib.h> | |
/** | |
Report status code listener for PEI. This is used to record the performance | |
data for S3 FullResume in FPDT. | |
@param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. | |
@param[in] CodeType Indicates the type of status code being reported. | |
@param[in] Value Describes the current status of a hardware or software entity. | |
This included information about the class and subclass that is used to | |
classify the entity as well as an operation. | |
@param[in] Instance The enumeration of a hardware or software entity within | |
the system. Valid instance numbers start with 1. | |
@param[in] CallerId This optional parameter may be used to identify the caller. | |
This parameter allows the status code driver to apply different rules to | |
different callers. | |
@param[in] Data This optional parameter may be used to pass additional data. | |
@retval EFI_SUCCESS Status code is what we expected. | |
@retval EFI_UNSUPPORTED Status code not supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FpdtStatusCodeListenerPei ( | |
IN CONST EFI_PEI_SERVICES **PeiServices, | |
IN EFI_STATUS_CODE_TYPE CodeType, | |
IN EFI_STATUS_CODE_VALUE Value, | |
IN UINT32 Instance, | |
IN CONST EFI_GUID *CallerId, | |
IN CONST EFI_STATUS_CODE_DATA *Data | |
) | |
{ | |
EFI_STATUS Status; | |
UINT64 CurrentTime; | |
UINTN VarSize; | |
EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer; | |
S3_PERFORMANCE_TABLE *AcpiS3PerformanceTable; | |
EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD *AcpiS3ResumeRecord; | |
UINT64 S3ResumeTotal; | |
EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord; | |
EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD *AcpiS3SuspendRecord; | |
EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; | |
UINT8 *BootPerformanceTable; | |
FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable; | |
EFI_HOB_GUID_TYPE *GuidHob; | |
FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; | |
UINT8 *FirmwarePerformanceData; | |
UINT8 *FirmwarePerformanceTablePtr; | |
// | |
// Check whether status code is what we are interested in. | |
// | |
if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) || | |
(Value != (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE))) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Retrieve current time as early as possible. | |
// | |
CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ()); | |
// | |
// Update S3 Resume Performance Record. | |
// | |
S3PerformanceTablePointer = 0; | |
VarSize = sizeof (EFI_PHYSICAL_ADDRESS); | |
Status = RestoreLockBox (&gFirmwarePerformanceS3PointerGuid, &S3PerformanceTablePointer, &VarSize); | |
ASSERT_EFI_ERROR (Status); | |
AcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *)(UINTN)S3PerformanceTablePointer; | |
ASSERT (AcpiS3PerformanceTable != NULL); | |
if (AcpiS3PerformanceTable->Header.Signature != EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE) { | |
DEBUG ((DEBUG_ERROR, "FPDT S3 performance data in ACPI memory get corrupted\n")); | |
return EFI_ABORTED; | |
} | |
AcpiS3ResumeRecord = &AcpiS3PerformanceTable->S3Resume; | |
AcpiS3ResumeRecord->FullResume = CurrentTime; | |
// | |
// Calculate average S3 resume time. | |
// | |
S3ResumeTotal = MultU64x32 (AcpiS3ResumeRecord->AverageResume, AcpiS3ResumeRecord->ResumeCount); | |
AcpiS3ResumeRecord->ResumeCount++; | |
if (AcpiS3ResumeRecord->ResumeCount > 0) { | |
AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount); | |
DEBUG ((DEBUG_INFO, "\nFPDT: S3 Resume Performance - AverageResume = 0x%x\n", AcpiS3ResumeRecord->AverageResume)); | |
} else { | |
DEBUG ((DEBUG_ERROR, "\nFPDT: S3 ResumeCount reaches the MAX_UINT32 value. S3 ResumeCount record reset to Zero.")); | |
} | |
DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - ResumeCount = 0x%x\n", AcpiS3ResumeRecord->ResumeCount)); | |
DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - FullResume = 0x%x\n", AcpiS3ResumeRecord->FullResume)); | |
// | |
// Update S3 Suspend Performance Record. | |
// | |
AcpiS3SuspendRecord = &AcpiS3PerformanceTable->S3Suspend; | |
VarSize = sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD); | |
ZeroMem (&S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD)); | |
Status = RestoreLockBox ( | |
&gEfiFirmwarePerformanceGuid, | |
&S3SuspendRecord, | |
&VarSize | |
); | |
ASSERT_EFI_ERROR (Status); | |
AcpiS3SuspendRecord->SuspendStart = S3SuspendRecord.SuspendStart; | |
AcpiS3SuspendRecord->SuspendEnd = S3SuspendRecord.SuspendEnd; | |
DEBUG ((DEBUG_INFO, "FPDT: S3 Suspend Performance - SuspendStart = %ld\n", AcpiS3SuspendRecord->SuspendStart)); | |
DEBUG ((DEBUG_INFO, "FPDT: S3 Suspend Performance - SuspendEnd = %ld\n", AcpiS3SuspendRecord->SuspendEnd)); | |
Status = PeiServicesLocatePpi ( | |
&gEfiPeiReadOnlyVariable2PpiGuid, | |
0, | |
NULL, | |
(VOID **)&VariableServices | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Update S3 boot records into the basic boot performance table. | |
// | |
VarSize = sizeof (PerformanceVariable); | |
Status = VariableServices->GetVariable ( | |
VariableServices, | |
EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME, | |
&gEfiFirmwarePerformanceGuid, | |
NULL, | |
&VarSize, | |
&PerformanceVariable | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
BootPerformanceTable = (UINT8 *)(UINTN)PerformanceVariable.BootPerformanceTablePointer; | |
// | |
// Dump PEI boot records | |
// | |
FirmwarePerformanceTablePtr = (BootPerformanceTable + sizeof (BOOT_PERFORMANCE_TABLE)); | |
GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid); | |
while (GuidHob != NULL) { | |
FirmwarePerformanceData = GET_GUID_HOB_DATA (GuidHob); | |
PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)FirmwarePerformanceData; | |
CopyMem (FirmwarePerformanceTablePtr, FirmwarePerformanceData + sizeof (FPDT_PEI_EXT_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries)); | |
GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob)); | |
FirmwarePerformanceTablePtr += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries); | |
} | |
// | |
// Update Table length. | |
// | |
((BOOT_PERFORMANCE_TABLE *)BootPerformanceTable)->Header.Length = (UINT32)((UINTN)FirmwarePerformanceTablePtr - (UINTN)BootPerformanceTable); | |
return EFI_SUCCESS; | |
} | |
/** | |
Main entry for Firmware Performance Data Table PEIM. | |
This routine is to register report status code listener for FPDT. | |
@param[in] FileHandle Handle of the file being invoked. | |
@param[in] PeiServices Pointer to PEI Services table. | |
@retval EFI_SUCCESS Report status code listener is registered successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FirmwarePerformancePeiEntryPoint ( | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN CONST EFI_PEI_SERVICES **PeiServices | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PEI_RSC_HANDLER_PPI *RscHandler; | |
if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) { | |
// | |
// S3 resume - register status code listener for OS wake vector. | |
// | |
Status = PeiServicesLocatePpi ( | |
&gEfiPeiRscHandlerPpiGuid, | |
0, | |
NULL, | |
(VOID **)&RscHandler | |
); | |
ASSERT_EFI_ERROR (Status); | |
Status = RscHandler->Register (FpdtStatusCodeListenerPei); | |
ASSERT_EFI_ERROR (Status); | |
} | |
return EFI_SUCCESS; | |
} |