[PATCH v9 6/7] RAS/AMD/ATL: Add DRAM address translation via PRM
Yazen Ghannam <[email protected]> Thu, 30 Jul 2026 15:48:33 -0400
| Newsgroups | org.kernel.vger.linux-edac,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Avadhut Naik <[email protected]> On AMD's Zen-based SoCs, a Unified Memory Controller (UMC) relative "normalized" address is reported through the MCA_ADDR of UMC SMCA banks on occurrence of a DRAM ECC error. This address can be converted into a DRAM address to decode additional information about the error. Add support to convert a normalized address into a DRAM address using the appropriate PRM handler. Expose it as a new operation, ATL_OP_DA, on the unified interface. Link: https://bugzilla.kernel.org/show_bug.cgi?id=220577 Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Avadhut Naik <[email protected]> Co-developed-by: Yazen Ghannam <[email protected]> Signed-off-by: Yazen Ghannam <[email protected]> --- drivers/ras/amd/atl/internal.h | 1 + drivers/ras/amd/atl/system.c | 4 ++++ drivers/ras/amd/atl/umc.c | 4 ++++ include/linux/ras.h | 13 +++++++++++++ 4 files changed, 22 insertions(+) diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index 0ebab3732886..86879f5632c1 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -286,6 +286,7 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr); /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; +extern const guid_t norm_to_dram_guid; int prm_umc_norm_to_addr(guid_t guid, struct atl_umc_addr *addr, void *out_buf); diff --git a/drivers/ras/amd/atl/system.c b/drivers/ras/amd/atl/system.c index 812a30e21d3a..1315bcc63e30 100644 --- a/drivers/ras/amd/atl/system.c +++ b/drivers/ras/amd/atl/system.c @@ -18,6 +18,10 @@ const guid_t norm_to_sys_guid = GUID_INIT(0xE7180659, 0xA65D, 0x451D, 0x92, 0xCD, 0x2B, 0x56, 0xF1, 0x2B, 0xEB, 0xA6); +const guid_t norm_to_dram_guid = GUID_INIT(0x7626C6AE, 0xF973, 0x429C, + 0xA9, 0x1C, 0x10, 0x7D, 0x7B, + 0xE2, 0x98, 0xB0); + int determine_node_id(struct addr_ctx *ctx, u8 socket_id, u8 die_id) { u16 socket_id_bits, die_id_bits; diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c index a3f611a4a9f8..1ab321a04cf1 100644 --- a/drivers/ras/amd/atl/umc.c +++ b/drivers/ras/amd/atl/umc.c @@ -449,4 +449,8 @@ void amd_atl_umc_translate_addr(struct atl_err *err) } } } + + if ((err->requested & ATL_OP_DA) && + !prm_umc_norm_to_addr(norm_to_dram_guid, &err->umc_addr, &err->da)) + err->valid |= ATL_OP_DA; } diff --git a/include/linux/ras.h b/include/linux/ras.h index f0afacdcebcf..6589b4e3ff0c 100644 --- a/include/linux/ras.h +++ b/include/linux/ras.h @@ -37,8 +37,20 @@ static inline void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; } #endif +/* See "NA to DA Output Buffer" in the AMD ACPI Porting Guide. */ +struct atl_dram_addr { + u8 chip_select; + u8 bank_group; + u8 bank_addr; + u32 row_addr; + u16 col_addr; + u8 rank_mul; + u8 sub_ch; +} __packed; + /* Operations requested and completed through amd_translate_umc_mca_addr(). */ #define ATL_OP_SPA BIT(0) /* System Physical Address */ +#define ATL_OP_DA BIT(1) /* DRAM address components */ struct atl_err { /* Identifiers; layout mirrors the PRM parameter buffer inputs */ @@ -57,6 +69,7 @@ struct atl_err { /* Outputs */ u64 spa; /* Valid if (@valid & ATL_OP_SPA) */ + struct atl_dram_addr da; /* Valid if (@valid & ATL_OP_DA) */ }; #if IS_ENABLED(CONFIG_AMD_ATL) -- 2.53.0