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

Reply via email to