[PATCH 085/109] drm/amd/ras: add BERT CPER table helpers

Alex Deucher <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Xiang Liu <[email protected]>

Add local HEST status and data entry layouts. Also add local helpers for
revision-aware payload access, entry walking, and basic status
validation.

Move the BERT record processing prototype into a dedicated BERT header
so the parser interface stays local to the BERT parser code.

Signed-off-by: Xiang Liu <[email protected]>
Reviewed-by: Hawking Zhang <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/ras/core/ras.h        |   4 +-
 drivers/gpu/drm/amd/ras/core/ras_bert.c   | 106 ++++++++++++++++++++--
 drivers/gpu/drm/amd/ras/core/ras_bert.h   |  33 +++++++
 drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h |   4 -
 4 files changed, 131 insertions(+), 16 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/ras/core/ras_bert.h

diff --git a/drivers/gpu/drm/amd/ras/core/ras.h b/drivers/gpu/drm/amd/ras/core/ras.h
index 6aad1d8779e21..238a587447ff4 100644
--- a/drivers/gpu/drm/amd/ras/core/ras.h
+++ b/drivers/gpu/drm/amd/ras/core/ras.h
@@ -38,6 +38,7 @@
 #include "log_ring.h"
 #include "eeprom_fw.h"
 #include "ras_mce.h"
+#include "ras_bert.h"
 
 #define RAS_HW_ERR		"[Hardware Error]: "
 
@@ -477,7 +478,4 @@ bool ras_core_poison_supported(struct ras_core_context *ras_core);
 bool ras_core_in_early_init(struct ras_core_context *ras_core);
 bool ras_core_early_init_service_enabled(struct ras_core_context *ras_core);
 int ras_core_eeprom_early_init_service(struct ras_core_context *ras_core);
-#if defined(CONFIG_X86_MCE_AMD) && defined(CONFIG_ACPI_APEI)
-int ras_bert_process_records(struct ras_core_context *ras_core, const void *bert, u32 bert_len);
-#endif
 #endif
diff --git a/drivers/gpu/drm/amd/ras/core/ras_bert.c b/drivers/gpu/drm/amd/ras/core/ras_bert.c
index 5d11b7d0d0c08..991c3fa164b27 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_bert.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_bert.c
@@ -25,21 +25,109 @@
 #include "ras.h"
 
 #if defined(CONFIG_X86_MCE_AMD) && defined(CONFIG_ACPI_APEI)
+struct ras_bert_hest_generic_status {
+	u32 block_status;
+	u32 raw_data_offset;
+	u32 raw_data_length;
+	u32 data_length;
+	u32 error_severity;
+};
+
+struct ras_bert_hest_generic_data {
+	u8 section_type[16];
+	u32 error_severity;
+	u16 revision;
+	u8 validation_bits;
+	u8 flags;
+	u32 error_data_length;
+	u8 fru_id[16];
+	u8 fru_text[20];
+};
+
+struct ras_bert_hest_generic_data_v300 {
+	u8 section_type[16];
+	u32 error_severity;
+	u16 revision;
+	u8 validation_bits;
+	u8 flags;
+	u32 error_data_length;
+	u8 fru_id[16];
+	u8 fru_text[20];
+	u64 time_stamp;
+};
+
+static inline int ras_bert_get_version(struct ras_bert_hest_generic_data *gdata)
+{
+	return gdata->revision >> 8;
+}
+
+static inline void *ras_bert_get_payload(struct ras_bert_hest_generic_data *gdata)
+{
+	if (ras_bert_get_version(gdata) >= 3)
+		return (void *)(((struct ras_bert_hest_generic_data_v300 *)(gdata)) + 1);
+
+	return gdata + 1;
+}
+
+static inline int ras_bert_get_size(struct ras_bert_hest_generic_data *gdata)
+{
+	if (ras_bert_get_version(gdata) >= 3)
+		return sizeof(struct ras_bert_hest_generic_data_v300);
+
+	return sizeof(struct ras_bert_hest_generic_data);
+}
+
+static inline void *ras_bert_get_next(struct ras_bert_hest_generic_data *gdata)
+{
+	return (void *)gdata + ras_bert_get_size(gdata) + gdata->error_data_length;
+}
+
+static int ras_bert_estatus_check(const struct ras_bert_hest_generic_status *estatus)
+{
+	struct ras_bert_hest_generic_data *gdata;
+	unsigned int data_len, record_size;
+
+	if (estatus->data_length &&
+	    estatus->data_length < sizeof(struct ras_bert_hest_generic_data))
+		return -EINVAL;
+	if (estatus->raw_data_length &&
+	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
+		return -EINVAL;
+
+	data_len = estatus->data_length;
+	gdata = (struct ras_bert_hest_generic_data *)(estatus + 1);
+	while ((void *)gdata - (void *)(estatus + 1) < estatus->data_length) {
+		if (ras_bert_get_size(gdata) > data_len)
+			return -EINVAL;
+
+		record_size = ras_bert_get_size(gdata) + gdata->error_data_length;
+		if (record_size > data_len)
+			return -EINVAL;
+
+		data_len -= record_size;
+		gdata = ras_bert_get_next(gdata);
+	}
+	if (data_len)
+		return -EINVAL;
+
+	return 0;
+}
+
 int ras_bert_process_records(struct ras_core_context *ras_core,
 			     const void *bert, u32 bert_len)
 {
-	struct acpi_hest_generic_status *estatus;
-	struct acpi_hest_generic_data *gdata;
+	struct ras_bert_hest_generic_status *estatus;
+	struct ras_bert_hest_generic_data *gdata;
 	u32 estatus_len;
 	int remain;
 
-	if (!ras_core || !bert || bert_len < sizeof(struct acpi_hest_generic_status))
+	if (!ras_core || !bert || bert_len < sizeof(struct ras_bert_hest_generic_status))
 		return -EINVAL;
 
-	estatus = (struct acpi_hest_generic_status *)bert;
+	estatus = (struct ras_bert_hest_generic_status *)bert;
 	remain = bert_len;
 
-	while (remain >= sizeof(struct acpi_hest_generic_status)) {
+	while (remain >= sizeof(struct ras_bert_hest_generic_status)) {
 		estatus_len = estatus->raw_data_length ?
 			      estatus->raw_data_offset + estatus->raw_data_length :
 			      sizeof(*estatus) + estatus->data_length;
@@ -57,19 +145,19 @@ int ras_bert_process_records(struct ras_core_context *ras_core,
 		 * parse the cached BERT payload, so do not use block_status to
 		 * decide whether this status block contains records.
 		 */
-		if (cper_estatus_check(estatus)) {
+		if (ras_bert_estatus_check(estatus)) {
 			RAS_DEV_ERR(ras_core->dev, "invalid error record.\n");
 			return -EINVAL;
 		}
 
-		gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+		gdata = (struct ras_bert_hest_generic_data *)(estatus + 1);
 		while ((void *)gdata - (void *)(estatus + 1) < estatus->data_length) {
 			RAS_DEV_INFO(ras_core->dev, "unknown section: %pUl\n",
 				     gdata->section_type);
 
-			gdata = acpi_hest_get_next(gdata);
+			gdata = ras_bert_get_next(gdata);
 		}
-		estatus = (struct acpi_hest_generic_status *)((u8 *)estatus + estatus_len);
+		estatus = (struct ras_bert_hest_generic_status *)((u8 *)estatus + estatus_len);
 		remain -= estatus_len;
 	}
 
diff --git a/drivers/gpu/drm/amd/ras/core/ras_bert.h b/drivers/gpu/drm/amd/ras/core/ras_bert.h
new file mode 100644
index 0000000000000..523281afe0d00
--- /dev/null
+++ b/drivers/gpu/drm/amd/ras/core/ras_bert.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __RAS_BERT_H__
+#define __RAS_BERT_H__
+
+struct ras_core_context;
+
+int ras_bert_process_records(struct ras_core_context *ras_core,
+			     const void *bert, u32 bert_len);
+
+#endif
diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
index 351864a1dd40d..2775c7bf41b7e 100644
--- a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
+++ b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h
@@ -28,10 +28,6 @@
 #include <linux/printk.h>
 #include <linux/dev_printk.h>
 #include <linux/mempool.h>
-#if defined(CONFIG_X86_MCE_AMD) && defined(CONFIG_ACPI_APEI)
-#include <linux/cper.h>
-#include <acpi/ghes.h>
-#endif
 #include "amdgpu.h"
 
 /* inject address is 52 bits */
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.