Matt Papageorge has uploaded this change for review.

View Change

soc/amd/common/bloc: Code to digest FSP PerformanceLib timestamps

The PEI PerformanceLib is capable of collecting timestamps from
anywhere during FSP execution and store that data within GUID HOBs.
This change adds code that can understand the HOBs. Long term plan
is to add this data to cbmem as well as add more measurement
checkpoints within FSP. Currently just the EDK defaults are
generated. Note that you need a corresponding FSP change to trigger
these HOBs to be generated.

BUG=todo
TEST=Verify output matches what can be dumped within FSP

Change-Id: Ic064b9cb205154662280a3b2a5bc02d33a779fc7
Signed-off-by: Matt Papageorge <matthewpapa07@gmail.com>
---
M src/drivers/intel/fsp2_0/hand_off_block.c
M src/drivers/intel/fsp2_0/include/fsp/util.h
A src/soc/amd/common/block/fsp_stats/Kconfig
A src/soc/amd/common/block/fsp_stats/Makefile.inc
A src/soc/amd/common/block/fsp_stats/fsp_stats.c
5 files changed, 248 insertions(+), 4 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/56/48256/1
diff --git a/src/drivers/intel/fsp2_0/hand_off_block.c b/src/drivers/intel/fsp2_0/hand_off_block.c
index 60ab7cb..ece3037 100644
--- a/src/drivers/intel/fsp2_0/hand_off_block.c
+++ b/src/drivers/intel/fsp2_0/hand_off_block.c
@@ -183,15 +183,16 @@
die("9.1: FSP_RESERVED_MEMORY_RESOURCE_HOB missing!\n");
}

-const void *fsp_find_extension_hob_by_guid(const uint8_t *guid, size_t *size)
+const void *fsp_find_extension_hob_inst_by_guid(const uint8_t *guid, size_t *size, const uint8_t instance_num)
{
const uint8_t *hob_guid;
const struct hob_header *hob = fsp_get_hob_list();
+ uint8_t hob_num;

if (!hob)
return NULL;

- for (; hob->type != HOB_TYPE_END_OF_HOB_LIST;
+ for (hob_num = 0; hob->type != HOB_TYPE_END_OF_HOB_LIST;
hob = fsp_next_hob(hob)) {

if (hob->type != HOB_TYPE_GUID_EXTENSION)
@@ -199,14 +200,24 @@

hob_guid = hob_header_to_struct(hob);
if (fsp_guid_compare(hob_guid, guid)) {
- *size = hob->length - (HOB_HEADER_LEN + 16);
- return hob_header_to_extension_hob(hob);
+ if (hob_num == instance_num) {
+ *size = hob->length - (HOB_HEADER_LEN + 16);
+ return hob_header_to_extension_hob(hob);
+ }
+ hob_num++;
}
}

return NULL;
}

+const void *fsp_find_extension_hob_by_guid(const uint8_t *guid, size_t *size)
+{
+ return fsp_find_extension_hob_inst_by_guid (guid, size, 0);
+}
+
+
+
static void display_fsp_version_info_hob(const void *hob)
{
#if CONFIG(DISPLAY_FSP_VERSION_INFO)
diff --git a/src/drivers/intel/fsp2_0/include/fsp/util.h b/src/drivers/intel/fsp2_0/include/fsp/util.h
index f154a34..ac1374c 100644
--- a/src/drivers/intel/fsp2_0/include/fsp/util.h
+++ b/src/drivers/intel/fsp2_0/include/fsp/util.h
@@ -77,6 +77,7 @@
const void *fsp_get_hob_list(void);
void *fsp_get_hob_list_ptr(void);
const void *fsp_find_extension_hob_by_guid(const uint8_t *guid, size_t *size);
+const void *fsp_find_extension_hob_inst_by_guid(const uint8_t *guid, size_t *size, const uint8_t instance_num);
const void *fsp_find_nv_storage_data(size_t *size);
enum cb_err fsp_fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
int fsp_find_range_hob(struct range_entry *re, const uint8_t guid[16]);
diff --git a/src/soc/amd/common/block/fsp_stats/Kconfig b/src/soc/amd/common/block/fsp_stats/Kconfig
new file mode 100644
index 0000000..5001cd9
--- /dev/null
+++ b/src/soc/amd/common/block/fsp_stats/Kconfig
@@ -0,0 +1,5 @@
+config SOC_AMD_COMMON_BLOCK_FSP_STATS
+ bool
+ default y
+ help
+ Parse FSP PerfromanceLib statistics
diff --git a/src/soc/amd/common/block/fsp_stats/Makefile.inc b/src/soc/amd/common/block/fsp_stats/Makefile.inc
new file mode 100644
index 0000000..c6ada9b
--- /dev/null
+++ b/src/soc/amd/common/block/fsp_stats/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_FSP_STATS) += fsp_stats.c
diff --git a/src/soc/amd/common/block/fsp_stats/fsp_stats.c b/src/soc/amd/common/block/fsp_stats/fsp_stats.c
new file mode 100644
index 0000000..ec4df1f
--- /dev/null
+++ b/src/soc/amd/common/block/fsp_stats/fsp_stats.c
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <string.h>
+#include <lib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <fsp/util.h>
+#include <bootstate.h>
+#include <console/console.h>
+#include <cbmem.h>
+
+#define AMD_FSP_PERFORMANCELIB_HOB \
+ { \
+ 0x3b387bfd, 0x7abc, 0x4cf2, \
+ { \
+ 0xa0, 0xca, 0xb6, 0xa1, 0x6c, 0x1b, 0x1b, 0x25 \
+ } \
+ }
+
+//
+// FPDT Record Types
+//
+#define FPDT_GUID_EVENT_TYPE 0x1010
+#define FPDT_DYNAMIC_STRING_EVENT_TYPE 0x1011
+#define FPDT_DUAL_GUID_STRING_EVENT_TYPE 0x1012
+#define FPDT_GUID_QWORD_EVENT_TYPE 0x1013
+#define FPDT_GUID_QWORD_STRING_EVENT_TYPE 0x1014
+// todo : AMD specific types
+
+typedef struct __packed {
+ uint32_t SizeOfAllEntries;
+ uint32_t LoadImageCount;
+ uint32_t HobIsFull;
+} FPDT_PEI_EXT_PERF_HEADER;
+
+///
+/// FPDT Performance Record header
+///
+typedef struct __packed {
+ uint16_t Type;
+ uint8_t Length;
+ uint8_t Revision;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ uint16_t ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as
+ /// 0.
+ ///
+ uint32_t ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion
+ /// of processor reset.
+ ///
+ uint64_t Timestamp;
+ ///
+ /// If ProgressID < 0x10, GUID of the referenced module; otherwise, GUID of the module
+ /// logging the event.
+ ///
+ uint8_t Guid[16];
+} FPDT_PERF_RECORD_HEADER;
+
+//
+// FPDT Boot Performance Guid Event Record Structure
+//
+typedef struct __packed {
+ FPDT_PERF_RECORD_HEADER Header;
+} FPDT_GUID_EVENT_RECORD;
+
+//
+// FPDT Boot Performance Dynamic String Event Record Structure
+//
+typedef struct __packed {
+ FPDT_PERF_RECORD_HEADER Header;
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with
+ /// null characters (0x00). It may be module name, function name, or token name.
+ ///
+ char String[0];
+} FPDT_DYNAMIC_STRING_EVENT_RECORD;
+
+//
+// FPDT Boot Performance Dual GUID String Event Record Structure
+//
+typedef struct __packed {
+ FPDT_PERF_RECORD_HEADER Header;
+ ///
+ /// Event or Ppi or Protocol GUID for Callback.
+ ///
+ uint8_t Guid2[16];
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with
+ /// null characters (0x00). It is the function name.
+ ///
+ char String[0];
+} FPDT_DUAL_GUID_STRING_EVENT_RECORD;
+
+//
+// FPDT Boot Performance GUID Qword Event Record Structure
+//
+typedef struct __packed {
+ FPDT_PERF_RECORD_HEADER Header;
+ ///
+ /// Qword of misc data, meaning depends on the ProgressId
+ ///
+ uint64_t Qword;
+} FPDT_GUID_QWORD_EVENT_RECORD;
+
+//
+// FPDT Boot Performance GUID Qword String Event Record Structure
+//
+typedef struct __packed {
+ FPDT_PERF_RECORD_HEADER Header;
+ ///
+ /// Qword of misc data, meaning depends on the ProgressId
+ ///
+ uint64_t Qword;
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with
+ /// null characters (0x00).
+ ///
+ char String[0];
+} FPDT_GUID_QWORD_STRING_EVENT_RECORD;
+
+
+typedef union {
+ FPDT_PERF_RECORD_HEADER RecordHeader;
+ FPDT_GUID_EVENT_RECORD GuidEvent;
+ FPDT_DYNAMIC_STRING_EVENT_RECORD DynamicStringEvent;
+ FPDT_DUAL_GUID_STRING_EVENT_RECORD DualGuidStringEvent;
+ FPDT_GUID_QWORD_EVENT_RECORD GuidQwordEvent;
+ FPDT_GUID_QWORD_STRING_EVENT_RECORD GuidQwordStringEvent;
+} FPDT_RECORD_PTR;
+
+static void print_entries(uintptr_t buffer, size_t size)
+{
+ FPDT_RECORD_PTR *CurrentRecord, *EndOfRecords;
+ FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader;
+ uint8_t records;
+ uint64_t new_timestamp, old_timestamp;
+
+ records = 0;
+ new_timestamp = 0;
+ old_timestamp = 0;
+ printk(BIOS_DEBUG, "%s : Offset of ProgressID %ld ApicID %ld timestamp %ld guid %ld\n",
+ __func__, offsetof(FPDT_PERF_RECORD_HEADER, ProgressID),
+ offsetof(FPDT_PERF_RECORD_HEADER, ApicID),
+ offsetof(FPDT_PERF_RECORD_HEADER, Timestamp),
+ offsetof(FPDT_PERF_RECORD_HEADER, Guid));
+
+ // todo check signature header
+ PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)buffer;
+ CurrentRecord = (FPDT_RECORD_PTR *)(buffer + sizeof(FPDT_PEI_EXT_PERF_HEADER));
+ EndOfRecords = (FPDT_RECORD_PTR *)((uint32_t)PeiPerformanceLogHeader->SizeOfAllEntries
+ + (uint32_t)CurrentRecord);
+
+ while (CurrentRecord < EndOfRecords) {
+ printk(BIOS_DEBUG, "%s : Record num %d found type 0x%x loc 0x%x\n", __func__,
+ records, CurrentRecord->RecordHeader.Type, (uint32_t)CurrentRecord);
+ printk(BIOS_DEBUG, "Progress ID 0x%x Timestamp 0x%llx\n",
+ CurrentRecord->RecordHeader.ProgressID,
+ CurrentRecord->RecordHeader.Timestamp);
+ fsp_print_guid((EFI_GUID *)CurrentRecord->RecordHeader.Guid);
+ new_timestamp = CurrentRecord->RecordHeader.Timestamp;
+
+ switch (CurrentRecord->RecordHeader.Type) {
+ case FPDT_GUID_EVENT_TYPE:
+ break;
+ case FPDT_DYNAMIC_STRING_EVENT_TYPE:
+ printk(BIOS_DEBUG, "Output string %.50s\n",
+ CurrentRecord->DynamicStringEvent.String);
+ break;
+ case FPDT_DUAL_GUID_STRING_EVENT_TYPE:
+ break;
+ case FPDT_GUID_QWORD_EVENT_TYPE:
+ break;
+ case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
+ break;
+ default:
+ break;
+ }
+
+ printk(BIOS_DEBUG, "Times 0x%llx 0x%llx\n", old_timestamp, new_timestamp);
+ printk(BIOS_DEBUG, "Time Delta 0x%llx\n", new_timestamp - old_timestamp);
+ old_timestamp = new_timestamp;
+ records++;
+ CurrentRecord = (FPDT_RECORD_PTR *)((uint32_t)CurrentRecord
+ + CurrentRecord->RecordHeader.Length);
+ }
+}
+
+static void locate_performance_hob(void *unused)
+{
+ uintptr_t buffer;
+ size_t amd_fsp_performancelib_hob_size;
+ const EFI_GUID amd_fsp_performancelib_hob_guid = AMD_FSP_PERFORMANCELIB_HOB;
+ uint8_t instance_num;
+
+ instance_num = 0;
+
+ while (true) {
+ buffer = (uintptr_t)fsp_find_extension_hob_inst_by_guid(
+ (const uint8_t *)&amd_fsp_performancelib_hob_guid,
+ &amd_fsp_performancelib_hob_size, instance_num);
+
+ if (buffer == 0 || amd_fsp_performancelib_hob_size == 0) {
+ printk(BIOS_DEBUG, "PerformanceLib HOB %d not found! \n", instance_num);
+ return;
+ }
+
+ printk(BIOS_DEBUG, "PerformanceLib HOB %d found at location 0x%lx \n",
+ instance_num, buffer);
+ print_entries(buffer, amd_fsp_performancelib_hob_size);
+ instance_num++;
+ }
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, locate_performance_hob, NULL);
+

To view, visit change 48256. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ic064b9cb205154662280a3b2a5bc02d33a779fc7
Gerrit-Change-Number: 48256
Gerrit-PatchSet: 1
Gerrit-Owner: Matt Papageorge <matthewpapa07@gmail.com>
Gerrit-MessageType: newchange