[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