2 This module updates S3 Resume Performance Record in ACPI Firmware Performance
3 Data Table in S3 resume boot mode.
5 This module register report status code listener to collect performance data
6 for S3 Resume Performance Record on S3 resume boot path.
8 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
15 #include <Ppi/ReportStatusCodeHandler.h>
16 #include <Ppi/ReadOnlyVariable2.h>
18 #include <Guid/FirmwarePerformance.h>
19 #include <Guid/Performance.h>
20 #include <Guid/ExtendedFirmwarePerformance.h>
22 #include <Library/PeiServicesLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/TimerLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/LockBoxLib.h>
28 #include <Library/PcdLib.h>
29 #include <Library/HobLib.h>
32 Report status code listener for PEI. This is used to record the performance
33 data for S3 FullResume in FPDT.
35 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
36 @param[in] CodeType Indicates the type of status code being reported.
37 @param[in] Value Describes the current status of a hardware or software entity.
38 This included information about the class and subclass that is used to
39 classify the entity as well as an operation.
40 @param[in] Instance The enumeration of a hardware or software entity within
41 the system. Valid instance numbers start with 1.
42 @param[in] CallerId This optional parameter may be used to identify the caller.
43 This parameter allows the status code driver to apply different rules to
45 @param[in] Data This optional parameter may be used to pass additional data.
47 @retval EFI_SUCCESS Status code is what we expected.
48 @retval EFI_UNSUPPORTED Status code not supported.
53 FpdtStatusCodeListenerPei (
54 IN CONST EFI_PEI_SERVICES
**PeiServices
,
55 IN EFI_STATUS_CODE_TYPE CodeType
,
56 IN EFI_STATUS_CODE_VALUE Value
,
58 IN CONST EFI_GUID
*CallerId
,
59 IN CONST EFI_STATUS_CODE_DATA
*Data
65 EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer
;
66 S3_PERFORMANCE_TABLE
*AcpiS3PerformanceTable
;
67 EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD
*AcpiS3ResumeRecord
;
69 EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord
;
70 EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
*AcpiS3SuspendRecord
;
71 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*VariableServices
;
72 UINT8
*BootPerformanceTable
;
73 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable
;
74 EFI_HOB_GUID_TYPE
*GuidHob
;
75 FPDT_PEI_EXT_PERF_HEADER
*PeiPerformanceLogHeader
;
76 UINT8
*FirmwarePerformanceData
;
77 UINT8
*FirmwarePerformanceTablePtr
;
80 // Check whether status code is what we are interested in.
82 if (((CodeType
& EFI_STATUS_CODE_TYPE_MASK
) != EFI_PROGRESS_CODE
) ||
83 (Value
!= (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_PC_OS_WAKE
))) {
84 return EFI_UNSUPPORTED
;
88 // Retrieve current time as early as possible.
90 CurrentTime
= GetTimeInNanoSecond (GetPerformanceCounter ());
93 // Update S3 Resume Performance Record.
95 S3PerformanceTablePointer
= 0;
96 VarSize
= sizeof (EFI_PHYSICAL_ADDRESS
);
97 Status
= RestoreLockBox (&gFirmwarePerformanceS3PointerGuid
, &S3PerformanceTablePointer
, &VarSize
);
98 ASSERT_EFI_ERROR (Status
);
100 AcpiS3PerformanceTable
= (S3_PERFORMANCE_TABLE
*) (UINTN
) S3PerformanceTablePointer
;
101 ASSERT (AcpiS3PerformanceTable
!= NULL
);
102 if (AcpiS3PerformanceTable
->Header
.Signature
!= EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE
) {
103 DEBUG ((EFI_D_ERROR
, "FPDT S3 performance data in ACPI memory get corrupted\n"));
106 AcpiS3ResumeRecord
= &AcpiS3PerformanceTable
->S3Resume
;
107 AcpiS3ResumeRecord
->FullResume
= CurrentTime
;
109 // Calculate average S3 resume time.
111 S3ResumeTotal
= MultU64x32 (AcpiS3ResumeRecord
->AverageResume
, AcpiS3ResumeRecord
->ResumeCount
);
112 AcpiS3ResumeRecord
->ResumeCount
++;
113 AcpiS3ResumeRecord
->AverageResume
= DivU64x32 (S3ResumeTotal
+ AcpiS3ResumeRecord
->FullResume
, AcpiS3ResumeRecord
->ResumeCount
);
115 DEBUG ((EFI_D_INFO
, "FPDT: S3 Resume Performance - ResumeCount = %d\n", AcpiS3ResumeRecord
->ResumeCount
));
116 DEBUG ((EFI_D_INFO
, "FPDT: S3 Resume Performance - FullResume = %ld\n", AcpiS3ResumeRecord
->FullResume
));
117 DEBUG ((EFI_D_INFO
, "FPDT: S3 Resume Performance - AverageResume = %ld\n", AcpiS3ResumeRecord
->AverageResume
));
120 // Update S3 Suspend Performance Record.
122 AcpiS3SuspendRecord
= &AcpiS3PerformanceTable
->S3Suspend
;
123 VarSize
= sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
);
124 ZeroMem (&S3SuspendRecord
, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD
));
125 Status
= RestoreLockBox (
126 &gEfiFirmwarePerformanceGuid
,
130 ASSERT_EFI_ERROR (Status
);
132 AcpiS3SuspendRecord
->SuspendStart
= S3SuspendRecord
.SuspendStart
;
133 AcpiS3SuspendRecord
->SuspendEnd
= S3SuspendRecord
.SuspendEnd
;
135 DEBUG ((EFI_D_INFO
, "FPDT: S3 Suspend Performance - SuspendStart = %ld\n", AcpiS3SuspendRecord
->SuspendStart
));
136 DEBUG ((EFI_D_INFO
, "FPDT: S3 Suspend Performance - SuspendEnd = %ld\n", AcpiS3SuspendRecord
->SuspendEnd
));
138 Status
= PeiServicesLocatePpi (
139 &gEfiPeiReadOnlyVariable2PpiGuid
,
142 (VOID
**) &VariableServices
144 ASSERT_EFI_ERROR (Status
);
147 // Update S3 boot records into the basic boot performance table.
149 VarSize
= sizeof (PerformanceVariable
);
150 Status
= VariableServices
->GetVariable (
152 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
,
153 &gEfiFirmwarePerformanceGuid
,
158 if (EFI_ERROR (Status
)) {
161 BootPerformanceTable
= (UINT8
*) (UINTN
) PerformanceVariable
.BootPerformanceTablePointer
;
164 // Dump PEI boot records
166 FirmwarePerformanceTablePtr
= (BootPerformanceTable
+ sizeof (BOOT_PERFORMANCE_TABLE
));
167 GuidHob
= GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid
);
168 while (GuidHob
!= NULL
) {
169 FirmwarePerformanceData
= GET_GUID_HOB_DATA (GuidHob
);
170 PeiPerformanceLogHeader
= (FPDT_PEI_EXT_PERF_HEADER
*) FirmwarePerformanceData
;
172 CopyMem (FirmwarePerformanceTablePtr
, FirmwarePerformanceData
+ sizeof (FPDT_PEI_EXT_PERF_HEADER
), (UINTN
)(PeiPerformanceLogHeader
->SizeOfAllEntries
));
174 GuidHob
= GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid
, GET_NEXT_HOB (GuidHob
));
176 FirmwarePerformanceTablePtr
+= (UINTN
)(PeiPerformanceLogHeader
->SizeOfAllEntries
);
180 // Update Table length.
182 ((BOOT_PERFORMANCE_TABLE
*) BootPerformanceTable
)->Header
.Length
= (UINT32
)((UINTN
)FirmwarePerformanceTablePtr
- (UINTN
)BootPerformanceTable
);
188 Main entry for Firmware Performance Data Table PEIM.
190 This routine is to register report status code listener for FPDT.
192 @param[in] FileHandle Handle of the file being invoked.
193 @param[in] PeiServices Pointer to PEI Services table.
195 @retval EFI_SUCCESS Report status code listener is registered successfully.
200 FirmwarePerformancePeiEntryPoint (
201 IN EFI_PEI_FILE_HANDLE FileHandle
,
202 IN CONST EFI_PEI_SERVICES
**PeiServices
206 EFI_PEI_RSC_HANDLER_PPI
*RscHandler
;
208 if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support
)) {
210 // S3 resume - register status code listener for OS wake vector.
212 Status
= PeiServicesLocatePpi (
213 &gEfiPeiRscHandlerPpiGuid
,
216 (VOID
**) &RscHandler
218 ASSERT_EFI_ERROR (Status
);
220 Status
= RscHandler
->Register (FpdtStatusCodeListenerPei
);
221 ASSERT_EFI_ERROR (Status
);