[PATCH 2/3] efi/cper, cxl: Decode CXL Component Events DRAM Event Record

From: Smita Koralahalli
Date: Thu Oct 12 2023 - 19:04:33 EST


Add support for decoding CXL Component Events DRAM Event Record
as defined in CXL rev 3.0 section 8.2.9.2.1.2.

Signed-off-by: Smita Koralahalli <Smita.KoralahalliChannabasappa@xxxxxxx>
---
drivers/firmware/efi/cper.c | 8 ++++
drivers/firmware/efi/cper_cxl.c | 79 +++++++++++++++++++++++++++++++++
drivers/firmware/efi/cper_cxl.h | 28 ++++++++++++
3 files changed, 115 insertions(+)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index b911b1f574db..1d182487fa13 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -615,6 +615,14 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
cper_print_gen_media(newpfx, gmer);
else
goto err_section_too_small;
+ } else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM)) {
+ struct cper_sec_comp_event *dram = acpi_hest_get_payload(gdata);
+
+ printk("%ssection_type: CXL DRAM Event\n", newpfx);
+ if (gdata->error_data_length >= sizeof(*dram))
+ cper_print_dram(newpfx, dram);
+ else
+ goto err_section_too_small;
} else {
const void *err = acpi_hest_get_payload(gdata);

diff --git a/drivers/firmware/efi/cper_cxl.c b/drivers/firmware/efi/cper_cxl.c
index 8f7b88cc574b..3fba360b7dc6 100644
--- a/drivers/firmware/efi/cper_cxl.c
+++ b/drivers/firmware/efi/cper_cxl.c
@@ -30,6 +30,15 @@
#define GMER_VALID_DEVICE BIT_ULL(2)
#define GMER_VALID_COMP_ID BIT_ULL(3)

+#define DRAM_VALID_CHANNEL BIT_ULL(0)
+#define DRAM_VALID_RANK BIT_ULL(1)
+#define DRAM_VALID_NIBBLE_MASK BIT_ULL(2)
+#define DRAM_VALID_BANK_GROUP BIT_ULL(3)
+#define DRAM_VALID_BANK BIT_ULL(4)
+#define DRAM_VALID_ROW BIT_ULL(5)
+#define DRAM_VALID_COLUMN BIT_ULL(6)
+#define DRAM_VALID_CORRECTION_MASK BIT_ULL(7)
+
/* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */
struct cxl_ras_capability_regs {
u32 uncor_status;
@@ -103,6 +112,13 @@ static const char * const transaction_type_strs[] = {
"internal media management",
};

+static const char * const dram_mem_type_strs[] = {
+ "media ECC error",
+ "scrub media ECC error",
+ "invalid address",
+ "data path error",
+};
+
void cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err)
{
if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_TYPE)
@@ -330,3 +346,66 @@ void cper_print_gen_media(const char *pfx, const struct cper_sec_comp_event *eve
sizeof(gmer->comp_id), 0);
}
}
+
+void cper_print_dram(const char *pfx, const struct cper_sec_comp_event *event)
+{
+ struct cper_sec_dram *dram;
+
+ cper_print_comp_event(pfx, event);
+
+ if (!(event->valid_bits & COMP_EVENT_VALID_EVENT_LOG))
+ return;
+
+ dram = (struct cper_sec_dram *)(event + 1);
+
+ cper_print_event_record(pfx, &dram->record);
+
+ pr_info("%s device physical address: 0x%016llx\n", pfx, dram->dpa);
+ pr_info("%s memory event descriptor: 0x%02x\n", pfx, dram->descriptor);
+ cper_print_bits(pfx, dram->descriptor, mem_evt_descriptor_strs,
+ ARRAY_SIZE(mem_evt_descriptor_strs));
+
+ pr_info("%s memory event type: %d, %s\n", pfx, dram->type,
+ dram->type < ARRAY_SIZE(dram_mem_type_strs)
+ ? dram_mem_type_strs[dram->type] : "unknown");
+
+ pr_info("%s transaction type: %d, %s\n", pfx, dram->transaction_type,
+ dram->transaction_type < ARRAY_SIZE(transaction_type_strs)
+ ? transaction_type_strs[dram->transaction_type] : "unknown");
+
+ if (dram->validity_flags & DRAM_VALID_CHANNEL)
+ pr_info("%s channel: 0x%02x\n", pfx, dram->channel);
+
+ if (dram->validity_flags & DRAM_VALID_RANK)
+ pr_info("%s rank: 0x%02x\n", pfx, dram->rank);
+
+ if (dram->validity_flags & DRAM_VALID_NIBBLE_MASK) {
+ const __u8 *nibble;
+
+ nibble = dram->nibble_mask;
+ pr_info("%s nibble mask: %02x%02x%02x\n", pfx, nibble[2],
+ nibble[1], nibble[0]);
+ }
+
+ if (dram->validity_flags & DRAM_VALID_BANK_GROUP)
+ pr_info("%s bank group: 0x%02x\n", pfx, dram->bank_group);
+
+ if (dram->validity_flags & DRAM_VALID_BANK)
+ pr_info("%s bank: 0x%02x\n", pfx, dram->bank);
+
+ if (dram->validity_flags & DRAM_VALID_ROW) {
+ const __u8 *row;
+
+ row = dram->row;
+ pr_info("%s row: %02x%02x%02x\n", pfx, row[2], row[1], row[0]);
+ }
+
+ if (dram->validity_flags & DRAM_VALID_COLUMN)
+ pr_info("%s column: 0x%04x\n", pfx, dram->column);
+
+ if (dram->validity_flags & DRAM_VALID_CORRECTION_MASK) {
+ pr_info("%s correction mask :\n", pfx);
+ print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4,
+ dram->cor_mask, sizeof(dram->cor_mask), 0);
+ }
+}
diff --git a/drivers/firmware/efi/cper_cxl.h b/drivers/firmware/efi/cper_cxl.h
index 94528db208de..967847b571cb 100644
--- a/drivers/firmware/efi/cper_cxl.h
+++ b/drivers/firmware/efi/cper_cxl.h
@@ -20,6 +20,11 @@
GUID_INIT(0xFBCD0A77, 0xC260, 0x417F, 0x85, 0xA9, 0x08, 0x8B, \
0x16, 0x21, 0xEB, 0xA6)

+/* CXL DRAM Section */
+#define CPER_SEC_CXL_DRAM \
+ GUID_INIT(0x601DCBB3, 0x9C06, 0x4EAB, 0xB8, 0xAF, 0x4E, 0x9B, \
+ 0xFB, 0x5C, 0x96, 0x24)
+
#pragma pack(1)

/* Compute Express Link Protocol Error Section, UEFI v2.10 sec N.2.13 */
@@ -120,9 +125,32 @@ struct cper_sec_gen_media {
u8 reserved[46];
};

+/*
+ * CXL DRAM Event Record
+ * CXL rev 3.0 sec 8.2.9.2.1.2; Table 8-44
+ */
+struct cper_sec_dram {
+ struct common_event_record record;
+ u64 dpa;
+ u8 descriptor;
+ u8 type;
+ u8 transaction_type;
+ u16 validity_flags;
+ u8 channel;
+ u8 rank;
+ u8 nibble_mask[3];
+ u8 bank_group;
+ u8 bank;
+ u8 row[3];
+ u16 column;
+ u8 cor_mask[32];
+ u8 reserved[23];
+};
+
#pragma pack()

void cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err);
void cper_print_gen_media(const char *pfx, const struct cper_sec_comp_event *event);
+void cper_print_dram(const char *pfx, const struct cper_sec_comp_event *event);

#endif //__CPER_CXL_
--
2.17.1