* [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-31 23:55 ` Borislav Petkov
2026-07-30 19:48 ` [PATCH v9 2/7] RAS/AMD/ATL: Refactor PRM address translation into a common helper Yazen Ghannam
` (5 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
PRM (Platform Runtime Mechanism) is the only address translation method for
current and future AMD systems. The library should therefore always include
it.
The PRM helpers in <linux/prmt.h> already provide stubs that return an
error when CONFIG_ACPI_PRMT is disabled. This lets prm.c build and link
in all configurations. The library then falls back to native translation
at runtime when no PRM handler is available.
Drop the CONFIG_AMD_ATL_PRM option. Build prm.o unconditionally and remove
the now-unneeded stub for prm_umc_norm_to_sys_addr().
Add -EOPNOTSUPP as "PRM not available". The acpi_call_prm_handler() stub
returns this when CONFIG_ACPI_PRMT=n.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/ras/amd/atl/Kconfig | 4 ----
drivers/ras/amd/atl/Makefile | 3 +--
drivers/ras/amd/atl/internal.h | 8 --------
drivers/ras/amd/atl/prm.c | 2 +-
4 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig
index 44c2fd7febc5..29befaf2a1e2 100644
--- a/drivers/ras/amd/atl/Kconfig
+++ b/drivers/ras/amd/atl/Kconfig
@@ -19,7 +19,3 @@ config AMD_ATL
Enable this option if using DRAM ECC on Zen-based systems
and OS-based error handling.
-
-config AMD_ATL_PRM
- depends on AMD_ATL && ACPI_PRMT
- def_bool y
diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile
index b56892c0c0d9..ff52452b678f 100644
--- a/drivers/ras/amd/atl/Makefile
+++ b/drivers/ras/amd/atl/Makefile
@@ -12,9 +12,8 @@ amd_atl-y += core.o
amd_atl-y += dehash.o
amd_atl-y += denormalize.o
amd_atl-y += map.o
+amd_atl-y += prm.o
amd_atl-y += system.o
amd_atl-y += umc.o
-amd_atl-$(CONFIG_AMD_ATL_PRM) += prm.o
-
obj-$(CONFIG_AMD_ATL) += amd_atl.o
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 82a56d9c2be1..4fc4bc3c3500 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -287,15 +287,7 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
/* GUIDs for PRM handlers */
extern const guid_t norm_to_sys_guid;
-#ifdef CONFIG_AMD_ATL_PRM
unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
-#else
-static inline unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id,
- unsigned long addr)
-{
- return -ENODEV;
-}
-#endif
/*
* Make a gap in @data that is @num_bits long starting at @bit_num.
diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c
index 0f9bfa96e16a..eba9d104d09e 100644
--- a/drivers/ras/amd/atl/prm.c
+++ b/drivers/ras/amd/atl/prm.c
@@ -44,7 +44,7 @@ unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long
if (!ret)
return ret_addr;
- if (ret == -ENODEV)
+ if (ret == -ENODEV || ret == -EOPNOTSUPP)
pr_debug("PRM module/handler not available\n");
else
pr_notice_once("PRM address translation failed\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support
2026-07-30 19:48 ` [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support Yazen Ghannam
@ 2026-07-31 23:55 ` Borislav Petkov
2026-08-03 15:24 ` Yazen Ghannam
0 siblings, 1 reply; 10+ messages in thread
From: Borislav Petkov @ 2026-07-31 23:55 UTC (permalink / raw)
To: Yazen Ghannam; +Cc: linux-edac, linux-kernel, Avadhut Naik
On Thu, Jul 30, 2026 at 03:48:28PM -0400, Yazen Ghannam wrote:
> PRM (Platform Runtime Mechanism) is the only address translation method for
> current and future AMD systems. The library should therefore always include
> it.
>
> The PRM helpers in <linux/prmt.h> already provide stubs that return an
> error when CONFIG_ACPI_PRMT is disabled. This lets prm.c build and link
> in all configurations. The library then falls back to native translation
> at runtime when no PRM handler is available.
>
> Drop the CONFIG_AMD_ATL_PRM option. Build prm.o unconditionally and remove
> the now-unneeded stub for prm_umc_norm_to_sys_addr().
>
> Add -EOPNOTSUPP as "PRM not available". The acpi_call_prm_handler() stub
> returns this when CONFIG_ACPI_PRMT=n.
Please tell AI to NOT write what the patch does. :-)
New commit message:
"RAS/AMD/ATL: Make PRM address translation support builtin
PRM (Platform Runtime Mechanism) is the only address translation method for
current and future AMD systems. The library should therefore always include
it.
The PRM helpers in <linux/prmt.h> already provide stubs that return an error
when CONFIG_ACPI_PRMT is disabled. Make prm.c builtin. The library then falls
back to native translation at runtime when no PRM handler is available."
Yah, looking at prm.c, I'm wondering why we even Kconfigged it. Oh well...
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support
2026-07-31 23:55 ` Borislav Petkov
@ 2026-08-03 15:24 ` Yazen Ghannam
0 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-08-03 15:24 UTC (permalink / raw)
To: Borislav Petkov; +Cc: linux-edac, linux-kernel, Avadhut Naik
On Fri, Jul 31, 2026 at 04:55:23PM -0700, Borislav Petkov wrote:
> On Thu, Jul 30, 2026 at 03:48:28PM -0400, Yazen Ghannam wrote:
> > PRM (Platform Runtime Mechanism) is the only address translation method for
> > current and future AMD systems. The library should therefore always include
> > it.
> >
> > The PRM helpers in <linux/prmt.h> already provide stubs that return an
> > error when CONFIG_ACPI_PRMT is disabled. This lets prm.c build and link
> > in all configurations. The library then falls back to native translation
> > at runtime when no PRM handler is available.
> >
> > Drop the CONFIG_AMD_ATL_PRM option. Build prm.o unconditionally and remove
> > the now-unneeded stub for prm_umc_norm_to_sys_addr().
> >
> > Add -EOPNOTSUPP as "PRM not available". The acpi_call_prm_handler() stub
> > returns this when CONFIG_ACPI_PRMT=n.
>
> Please tell AI to NOT write what the patch does. :-)
Ha, I try, but I make the same mistake myself. :P
That's probably obvious, because I reviewed the commit message and
signed off on it. :)
>
> New commit message:
>
> "RAS/AMD/ATL: Make PRM address translation support builtin
>
> PRM (Platform Runtime Mechanism) is the only address translation method for
> current and future AMD systems. The library should therefore always include
> it.
>
> The PRM helpers in <linux/prmt.h> already provide stubs that return an error
> when CONFIG_ACPI_PRMT is disabled. Make prm.c builtin. The library then falls
> back to native translation at runtime when no PRM handler is available."
>
Looks good to me.
> Yah, looking at prm.c, I'm wondering why we even Kconfigged it. Oh well...
IIRC, it was to be more modular for custom kernel builds. Of course, now
we probably should put the 'native' translation code behind a config
option. There's a lot more of that, and it's only used for legacy
systems.
Thanks,
Yazen
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v9 2/7] RAS/AMD/ATL: Refactor PRM address translation into a common helper
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 3/7] RAS/AMD/ATL: Add unified UMC address translation interface Yazen Ghannam
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
Every PRM address translation follows the same pattern. Each fills a
parameter buffer, invokes the handler, and checks the result. Only the
handler GUID and the output buffer differ.
Factor the common sequence into prm_umc_norm_to_addr(). It takes the GUID
and output buffer as parameters. Convert prm_umc_norm_to_sys_addr() into a
thin wrapper around it.
Rename the parameter buffer struct to param_buf. It is no longer specific
to the system physical address translation.
Include the error code in the log messages. This makes a failure easier to
diagnose.
This is in preparation for adding more PRM address translation handlers.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/ras/amd/atl/internal.h | 2 ++
drivers/ras/amd/atl/prm.c | 35 +++++++++++++++++++++-------------
2 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 4fc4bc3c3500..9f4d2a5b6c14 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -287,6 +287,8 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
/* GUIDs for PRM handlers */
extern const guid_t norm_to_sys_guid;
+int prm_umc_norm_to_addr(guid_t guid, u8 socket_id, u64 umc_bank_inst_id,
+ unsigned long addr, void *out_buf);
unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
/*
diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c
index eba9d104d09e..3d5a6f5ae0a9 100644
--- a/drivers/ras/amd/atl/prm.c
+++ b/drivers/ras/amd/atl/prm.c
@@ -18,36 +18,45 @@
#include <linux/prmt.h>
-/*
- * PRM parameter buffer - normalized to system physical address, as described
- * in the "PRM Parameter Buffer" section of the AMD ACPI Porting Guide.
- */
-struct norm_to_sys_param_buf {
+/* See "PRM Parameter Buffer" in the AMD ACPI Porting Guide. */
+struct param_buf {
u64 norm_addr;
u8 socket;
u64 bank_id;
void *out_buf;
} __packed;
-unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr)
+int prm_umc_norm_to_addr(guid_t guid, u8 socket_id, u64 bank_id,
+ unsigned long addr, void *out_buf)
{
- struct norm_to_sys_param_buf p_buf;
- unsigned long ret_addr;
+ struct param_buf p_buf;
int ret;
p_buf.norm_addr = addr;
p_buf.socket = socket_id;
p_buf.bank_id = bank_id;
- p_buf.out_buf = &ret_addr;
+ p_buf.out_buf = out_buf;
- ret = acpi_call_prm_handler(norm_to_sys_guid, &p_buf);
+ ret = acpi_call_prm_handler(guid, &p_buf);
if (!ret)
- return ret_addr;
+ return 0;
if (ret == -ENODEV || ret == -EOPNOTSUPP)
- pr_debug("PRM module/handler not available\n");
+ pr_debug("PRM module/handler not available: %d\n", ret);
else
- pr_notice_once("PRM address translation failed\n");
+ pr_notice_once("PRM address translation failed: %d\n", ret);
return ret;
}
+
+unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr)
+{
+ unsigned long sys_addr;
+ int ret;
+
+ ret = prm_umc_norm_to_addr(norm_to_sys_guid, socket_id, bank_id, addr, &sys_addr);
+ if (ret)
+ return ret;
+
+ return sys_addr;
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 3/7] RAS/AMD/ATL: Add unified UMC address translation interface
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 1/7] RAS/AMD/ATL: Always build PRM address translation support Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 2/7] RAS/AMD/ATL: Refactor PRM address translation into a common helper Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 4/7] RAS/AMD, EDAC/amd64: Use unified interface for SPA translation Yazen Ghannam
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
The library exposes a single function for UMC address translation. Adding a
new translation would mean adding and plumbing another export. Callers also
have no way to request more than one representation of an address in a
single call.
Add a single entry point, amd_translate_umc_mca_addr(), that operates
entirely through struct atl_err. Expand the struct with a pair of
operation bitmaps and the per-operation output fields.
The caller provides the error inputs and requests one or more operations.
Each operation is attempted independently. The library sets a validation
bit and fills the matching output for each operation that succeeds. The
caller must check the validation bit before consuming an output value.
Group the error identifiers (normalized address, socket, and UMC bank ID)
into struct atl_umc_addr. Lay it out to match the PRM parameter buffer
inputs that every handler shares. Reuse that struct for the parameter
buffer. A caller-populated atl_err can then be handed to a PRM handler
directly.
Route the interface through the always-built RAS core so the library
remains optional. The core provides the entry point and a
register/unregister pair. The library registers its implementation on load.
The entry point does nothing (no validation bits set) when the library is
absent.
Start with a single operation, ATL_OP_SPA, that produces the System
Physical Address. Try the PRM handler first. Fall back to the native Data
Fabric translation if PRM is unavailable and the Data Fabric revision
supports it.
Leave the existing amd_convert_umc_mca_addr_to_sys_addr() interface in
place for now.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/ras/amd/atl/core.c | 2 ++
drivers/ras/amd/atl/internal.h | 4 ++--
drivers/ras/amd/atl/prm.c | 20 +++++++++---------
drivers/ras/amd/atl/umc.c | 37 ++++++++++++++++++++++++++++++++++
drivers/ras/ras.c | 28 +++++++++++++++++++++++++
include/linux/ras.h | 28 +++++++++++++++++++++++--
6 files changed, 105 insertions(+), 14 deletions(-)
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index d77dacdd4f56..b754eaef8585 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -210,6 +210,7 @@ static int __init amd_atl_init(void)
/* Increment this module's recount so that it can't be easily unloaded. */
__module_get(THIS_MODULE);
amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
+ amd_atl_register_umc_translator(amd_atl_umc_translate_addr);
pr_info("AMD Address Translation Library initialized\n");
return 0;
@@ -222,6 +223,7 @@ static int __init amd_atl_init(void)
static void __exit amd_atl_exit(void)
{
amd_atl_unregister_decoder();
+ amd_atl_unregister_umc_translator();
}
module_init(amd_atl_init);
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 9f4d2a5b6c14..0086bf0ff24f 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -280,6 +280,7 @@ int dehash_address(struct addr_ctx *ctx);
unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+void amd_atl_umc_translate_addr(struct atl_err *err);
u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
@@ -287,8 +288,7 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
/* GUIDs for PRM handlers */
extern const guid_t norm_to_sys_guid;
-int prm_umc_norm_to_addr(guid_t guid, u8 socket_id, u64 umc_bank_inst_id,
- unsigned long addr, void *out_buf);
+int prm_umc_norm_to_addr(guid_t guid, struct atl_umc_addr *addr, void *out_buf);
unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
/*
diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c
index 3d5a6f5ae0a9..a951c00f940c 100644
--- a/drivers/ras/amd/atl/prm.c
+++ b/drivers/ras/amd/atl/prm.c
@@ -20,22 +20,17 @@
/* See "PRM Parameter Buffer" in the AMD ACPI Porting Guide. */
struct param_buf {
- u64 norm_addr;
- u8 socket;
- u64 bank_id;
+ struct atl_umc_addr addr;
void *out_buf;
} __packed;
-int prm_umc_norm_to_addr(guid_t guid, u8 socket_id, u64 bank_id,
- unsigned long addr, void *out_buf)
+int prm_umc_norm_to_addr(guid_t guid, struct atl_umc_addr *addr, void *out_buf)
{
struct param_buf p_buf;
int ret;
- p_buf.norm_addr = addr;
- p_buf.socket = socket_id;
- p_buf.bank_id = bank_id;
- p_buf.out_buf = out_buf;
+ p_buf.addr = *addr;
+ p_buf.out_buf = out_buf;
ret = acpi_call_prm_handler(guid, &p_buf);
if (!ret)
@@ -51,10 +46,15 @@ int prm_umc_norm_to_addr(guid_t guid, u8 socket_id, u64 bank_id,
unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr)
{
+ struct atl_umc_addr uaddr = {
+ .addr = addr,
+ .socket_id = socket_id,
+ .ipid = bank_id,
+ };
unsigned long sys_addr;
int ret;
- ret = prm_umc_norm_to_addr(norm_to_sys_guid, socket_id, bank_id, addr, &sys_addr);
+ ret = prm_umc_norm_to_addr(norm_to_sys_guid, &uaddr, &sys_addr);
if (ret)
return ret;
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index befc616d5e8a..2d61f890e4b8 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -416,3 +416,40 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr);
}
+
+/*
+ * Translate a UMC MCA error address into one or more representations as
+ * requested by the caller.
+ *
+ * The caller sets the input values and requests one or more operations
+ * through @err->requested. @err->valid is cleared on entry. Each operation
+ * is attempted independently. The corresponding bit in @err->valid is set
+ * and the related output field is filled for each operation that succeeds.
+ * The caller must check @err->valid before consuming an output value.
+ *
+ * The PRM handlers consume @err->umc_addr directly. Only MI300 needs its
+ * MCA_ADDR value converted to a normalized address first; see get_addr().
+ * MI300 platforms provide no PRM handlers, so the conversion is left to the
+ * native fallback path.
+ *
+ * Registered with the RAS core as the UMC address translator; see
+ * amd_translate_umc_mca_addr().
+ */
+void amd_atl_umc_translate_addr(struct atl_err *err)
+{
+ err->socket_id = topology_physical_package_id(err->cpu);
+ err->valid = 0;
+
+ if (err->requested & ATL_OP_SPA) {
+ if (!prm_umc_norm_to_addr(norm_to_sys_guid, &err->umc_addr, &err->spa)) {
+ err->valid |= ATL_OP_SPA;
+ } else if (!df_cfg.flags.prm_only) {
+ unsigned long spa = convert_umc_mca_addr_to_sys_addr(err);
+
+ if (!IS_ERR_VALUE(spa)) {
+ err->spa = spa;
+ err->valid |= ATL_OP_SPA;
+ }
+ }
+ }
+}
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 03df3db62334..20e23560dee5 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -39,6 +39,34 @@ unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
return amd_atl_umc_na_to_spa(err);
}
EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
+
+/*
+ * Set by the library module when it loads. Left registered while the module is
+ * resident; consumers keep no direct dependency on the library, so translation
+ * is simply skipped when it is not loaded.
+ */
+static void (*amd_atl_umc_translate)(struct atl_err *err);
+
+void amd_atl_register_umc_translator(void (*f)(struct atl_err *))
+{
+ amd_atl_umc_translate = f;
+}
+EXPORT_SYMBOL_GPL(amd_atl_register_umc_translator);
+
+void amd_atl_unregister_umc_translator(void)
+{
+ amd_atl_umc_translate = NULL;
+}
+EXPORT_SYMBOL_GPL(amd_atl_unregister_umc_translator);
+
+void amd_translate_umc_mca_addr(struct atl_err *err)
+{
+ err->valid = 0;
+
+ if (amd_atl_umc_translate)
+ amd_atl_umc_translate(err);
+}
+EXPORT_SYMBOL_GPL(amd_translate_umc_mca_addr);
#endif /* CONFIG_AMD_ATL */
#define CREATE_TRACE_POINTS
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 468941bfe855..eac8cf39ddd5 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -3,6 +3,8 @@
#define __RAS_H__
#include <asm/errno.h>
+#include <linux/bits.h>
+#include <linux/stddef.h>
#include <linux/uuid.h>
#include <linux/cper.h>
@@ -35,10 +37,26 @@ static inline void
log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; }
#endif
+/* Operations requested and completed through amd_translate_umc_mca_addr(). */
+#define ATL_OP_SPA BIT(0) /* System Physical Address */
+
struct atl_err {
- u64 addr;
- u64 ipid;
+ /* Identifiers; layout mirrors the PRM parameter buffer inputs */
+ __struct_group(atl_umc_addr, umc_addr, __packed,
+ u64 addr;
+ u8 socket_id; /* Filled by the library from @cpu */
+ u64 ipid;
+ );
u32 cpu;
+
+ /* Requested operations (input) */
+ u8 requested;
+
+ /* Completed operations (output) */
+ u8 valid;
+
+ /* Outputs */
+ u64 spa; /* Valid if (@valid & ATL_OP_SPA) */
};
#if IS_ENABLED(CONFIG_AMD_ATL)
@@ -46,10 +64,16 @@ void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
void amd_atl_unregister_decoder(void);
void amd_retire_dram_row(struct atl_err *err);
unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+
+void amd_atl_register_umc_translator(void (*f)(struct atl_err *));
+void amd_atl_unregister_umc_translator(void);
+void amd_translate_umc_mca_addr(struct atl_err *err);
#else
static inline void amd_retire_dram_row(struct atl_err *err) { }
static inline unsigned long
amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
+static inline void
+amd_translate_umc_mca_addr(struct atl_err *err) { err->valid = 0; }
#endif /* CONFIG_AMD_ATL */
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 4/7] RAS/AMD, EDAC/amd64: Use unified interface for SPA translation
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
` (2 preceding siblings ...)
2026-07-30 19:48 ` [PATCH v9 3/7] RAS/AMD/ATL: Add unified UMC address translation interface Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 5/7] RAS/AMD/ATL: Remove the standalone SPA translation interface Yazen Ghannam
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
Switch all users of the ATL SPA translation function to the new unified
interface.
No functional change intended.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/edac/amd64_edac.c | 15 +++++++--------
drivers/edac/amd64_edac.h | 2 ++
drivers/ras/amd/atl/umc.c | 8 +++++---
drivers/ras/amd/fmpm.c | 10 +++++-----
4 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 475235c402e8..f428d815bff1 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2809,9 +2809,7 @@ static void decode_umc_error(int node_id, struct mce *m)
{
u8 ecc_type = (m->status >> 45) & 0x3;
struct mem_ctl_info *mci;
- unsigned long sys_addr;
struct amd64_pvt *pvt;
- struct atl_err a_err;
struct err_info err;
node_id = fixup_node_id(node_id, m);
@@ -2843,17 +2841,18 @@ static void decode_umc_error(int node_id, struct mce *m)
pvt->ops->get_err_info(m, &err);
- a_err.addr = m->addr;
- a_err.ipid = m->ipid;
- a_err.cpu = m->extcpu;
+ err.a_err.addr = m->addr;
+ err.a_err.ipid = m->ipid;
+ err.a_err.cpu = m->extcpu;
+ err.a_err.requested = ATL_OP_SPA;
- sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
- if (IS_ERR_VALUE(sys_addr)) {
+ amd_translate_umc_mca_addr(&err.a_err);
+ if (!(err.a_err.valid & ATL_OP_SPA)) {
err.err_code = ERR_NORM_ADDR;
goto log_error;
}
- error_address_to_page_and_offset(sys_addr, &err);
+ error_address_to_page_and_offset(err.a_err.spa, &err);
log_error:
__log_ecc_error(mci, &err, ecc_type);
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 1757c1b99fc8..b11da6fdf0fc 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -17,6 +17,7 @@
#include <linux/mmzone.h>
#include <linux/edac.h>
#include <linux/bitfield.h>
+#include <linux/ras.h>
#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include "edac_module.h"
@@ -400,6 +401,7 @@ struct err_info {
u16 syndrome;
u32 page;
u32 offset;
+ struct atl_err a_err;
};
static inline u32 get_umc_base(u8 channel)
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index 2d61f890e4b8..4d75ad4483e8 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -314,15 +314,17 @@ static void _retire_row_mi300(struct atl_err *a_err)
struct page *p;
u8 col;
+ a_err->requested = ATL_OP_SPA;
+
for (col = 0; col < MI300_NUM_COL; col++) {
a_err->addr &= ~MI300_UMC_MCA_COL;
a_err->addr |= FIELD_PREP(MI300_UMC_MCA_COL, col);
- addr = amd_convert_umc_mca_addr_to_sys_addr(a_err);
- if (IS_ERR_VALUE(addr))
+ amd_atl_umc_translate_addr(a_err);
+ if (!(a_err->valid & ATL_OP_SPA))
continue;
- addr = PHYS_PFN(addr);
+ addr = PHYS_PFN(a_err->spa);
/*
* Skip invalid or already poisoned pages to avoid unnecessary
diff --git a/drivers/ras/amd/fmpm.c b/drivers/ras/amd/fmpm.c
index 4ccaaf7b70bf..21f645197410 100644
--- a/drivers/ras/amd/fmpm.c
+++ b/drivers/ras/amd/fmpm.c
@@ -302,7 +302,6 @@ static void save_spa(struct fru_rec *rec, unsigned int entry,
{
unsigned int i, fru_idx, spa_entry;
struct atl_err a_err;
- unsigned long spa;
if (entry >= max_nr_entries) {
pr_warn_once("FRU descriptor entry %d out-of-bounds (max: %d)\n",
@@ -328,19 +327,20 @@ static void save_spa(struct fru_rec *rec, unsigned int entry,
return;
}
- memset(&a_err, 0, sizeof(struct atl_err));
+ memset(&a_err, 0, sizeof(a_err));
a_err.addr = addr;
a_err.ipid = id;
a_err.cpu = cpu;
+ a_err.requested = ATL_OP_SPA;
- spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
- if (IS_ERR_VALUE(spa)) {
+ amd_translate_umc_mca_addr(&a_err);
+ if (!(a_err.valid & ATL_OP_SPA)) {
pr_debug("Failed to get system address\n");
return;
}
- spa_entries[spa_entry] = spa;
+ spa_entries[spa_entry] = a_err.spa;
pr_debug("fru_idx: %u, entry: %u, spa_entry: %u, spa: 0x%016llx\n",
fru_idx, entry, spa_entry, spa_entries[spa_entry]);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 5/7] RAS/AMD/ATL: Remove the standalone SPA translation interface
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
` (3 preceding siblings ...)
2026-07-30 19:48 ` [PATCH v9 4/7] RAS/AMD, EDAC/amd64: Use unified interface for SPA translation Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 6/7] RAS/AMD/ATL: Add DRAM address translation via PRM Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 7/7] EDAC/amd64: Include DRAM address in output Yazen Ghannam
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
All consumers now use the unified amd_translate_umc_mca_addr() interface,
which is routed through the RAS core in the same way. The older
amd_convert_umc_mca_addr_to_sys_addr() interface and its separate
register/unregister pair are no longer used.
Remove amd_convert_umc_mca_addr_to_sys_addr() together with
amd_atl_register_decoder()/amd_atl_unregister_decoder() and the associated
function pointer.
The unified interface performs the PRM translation itself, so
convert_umc_mca_addr_to_sys_addr() is now only the native Data Fabric
fallback. Make it static and drop its PRM attempt. Have it use the socket
ID that amd_atl_umc_translate_addr() already stores in struct atl_err.
The prm_umc_norm_to_sys_addr() wrapper has no remaining users. Remove it.
No functional change intended.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/ras/amd/atl/core.c | 2 --
drivers/ras/amd/atl/internal.h | 2 --
drivers/ras/amd/atl/prm.c | 17 -----------------
drivers/ras/amd/atl/umc.c | 9 ++-------
drivers/ras/ras.c | 29 -----------------------------
include/linux/ras.h | 5 -----
6 files changed, 2 insertions(+), 62 deletions(-)
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index b754eaef8585..cb944d3473ba 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -209,7 +209,6 @@ static int __init amd_atl_init(void)
/* Increment this module's recount so that it can't be easily unloaded. */
__module_get(THIS_MODULE);
- amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
amd_atl_register_umc_translator(amd_atl_umc_translate_addr);
pr_info("AMD Address Translation Library initialized\n");
@@ -222,7 +221,6 @@ static int __init amd_atl_init(void)
*/
static void __exit amd_atl_exit(void)
{
- amd_atl_unregister_decoder();
amd_atl_unregister_umc_translator();
}
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 0086bf0ff24f..0ebab3732886 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -279,7 +279,6 @@ int denormalize_address(struct addr_ctx *ctx);
int dehash_address(struct addr_ctx *ctx);
unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
void amd_atl_umc_translate_addr(struct atl_err *err);
u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
@@ -289,7 +288,6 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
extern const guid_t norm_to_sys_guid;
int prm_umc_norm_to_addr(guid_t guid, struct atl_umc_addr *addr, void *out_buf);
-unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
/*
* Make a gap in @data that is @num_bits long starting at @bit_num.
diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c
index a951c00f940c..b6b2d12a2a66 100644
--- a/drivers/ras/amd/atl/prm.c
+++ b/drivers/ras/amd/atl/prm.c
@@ -43,20 +43,3 @@ int prm_umc_norm_to_addr(guid_t guid, struct atl_umc_addr *addr, void *out_buf)
return ret;
}
-
-unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr)
-{
- struct atl_umc_addr uaddr = {
- .addr = addr,
- .socket_id = socket_id,
- .ipid = bank_id,
- };
- unsigned long sys_addr;
- int ret;
-
- ret = prm_umc_norm_to_addr(norm_to_sys_guid, &uaddr, &sys_addr);
- if (ret)
- return ret;
-
- return sys_addr;
-}
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index 4d75ad4483e8..a3f611a4a9f8 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -401,21 +401,16 @@ static u8 get_coh_st_inst_id(struct atl_err *err)
return FIELD_GET(UMC_CHANNEL_NUM, err->ipid);
}
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+static unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
{
- u8 socket_id = topology_physical_package_id(err->cpu);
u8 coh_st_inst_id = get_coh_st_inst_id(err);
unsigned long addr = get_addr(err->addr);
+ u8 socket_id = err->socket_id;
u8 die_id = get_die_id(err);
- unsigned long ret_addr;
pr_debug("socket_id=0x%x die_id=0x%x coh_st_inst_id=0x%x addr=0x%016lx",
socket_id, die_id, coh_st_inst_id, addr);
- ret_addr = prm_umc_norm_to_sys_addr(socket_id, err->ipid, addr);
- if (!IS_ERR_VALUE(ret_addr) || df_cfg.flags.prm_only)
- return ret_addr;
-
return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr);
}
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 20e23560dee5..c92b6d599792 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -11,35 +11,6 @@
#include <linux/uuid.h>
#if IS_ENABLED(CONFIG_AMD_ATL)
-/*
- * Once set, this function pointer should never be unset.
- *
- * The library module will set this pointer if it successfully loads. The module
- * should not be unloaded except for testing and debug purposes.
- */
-static unsigned long (*amd_atl_umc_na_to_spa)(struct atl_err *err);
-
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *))
-{
- amd_atl_umc_na_to_spa = f;
-}
-EXPORT_SYMBOL_GPL(amd_atl_register_decoder);
-
-void amd_atl_unregister_decoder(void)
-{
- amd_atl_umc_na_to_spa = NULL;
-}
-EXPORT_SYMBOL_GPL(amd_atl_unregister_decoder);
-
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
-{
- if (!amd_atl_umc_na_to_spa)
- return -EINVAL;
-
- return amd_atl_umc_na_to_spa(err);
-}
-EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
-
/*
* Set by the library module when it loads. Left registered while the module is
* resident; consumers keep no direct dependency on the library, so translation
diff --git a/include/linux/ras.h b/include/linux/ras.h
index eac8cf39ddd5..f0afacdcebcf 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -60,18 +60,13 @@ struct atl_err {
};
#if IS_ENABLED(CONFIG_AMD_ATL)
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
-void amd_atl_unregister_decoder(void);
void amd_retire_dram_row(struct atl_err *err);
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
void amd_atl_register_umc_translator(void (*f)(struct atl_err *));
void amd_atl_unregister_umc_translator(void);
void amd_translate_umc_mca_addr(struct atl_err *err);
#else
static inline void amd_retire_dram_row(struct atl_err *err) { }
-static inline unsigned long
-amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
static inline void
amd_translate_umc_mca_addr(struct atl_err *err) { err->valid = 0; }
#endif /* CONFIG_AMD_ATL */
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 6/7] RAS/AMD/ATL: Add DRAM address translation via PRM
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
` (4 preceding siblings ...)
2026-07-30 19:48 ` [PATCH v9 5/7] RAS/AMD/ATL: Remove the standalone SPA translation interface Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
2026-07-30 19:48 ` [PATCH v9 7/7] EDAC/amd64: Include DRAM address in output Yazen Ghannam
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
From: Avadhut Naik <avadhut.naik@amd.com>
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 <avadhut.naik@amd.com>
Co-developed-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
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
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 7/7] EDAC/amd64: Include DRAM address in output
2026-07-30 19:48 [PATCH v9 0/7] Incorporate DRAM address in EDAC messages Yazen Ghannam
` (5 preceding siblings ...)
2026-07-30 19:48 ` [PATCH v9 6/7] RAS/AMD/ATL: Add DRAM address translation via PRM Yazen Ghannam
@ 2026-07-30 19:48 ` Yazen Ghannam
6 siblings, 0 replies; 10+ messages in thread
From: Yazen Ghannam @ 2026-07-30 19:48 UTC (permalink / raw)
To: bp, linux-edac; +Cc: linux-kernel, Avadhut Naik, Yazen Ghannam
From: Avadhut Naik <avadhut.naik@amd.com>
The DRAM address of an error is used by tooling to find failure patterns,
e.g. for off-system analysis or to offline a page affected by a bad row.
Other EDAC modules (GHES and SKX) already provide it. AMD64 could not,
because the translation is system-specific.
Request the DRAM address in addition to the System Physical Address when
translating a UMC error. The SPA is required to log the error. The DRAM
address is best-effort and only added when its translation succeeds.
Add the DRAM address to the EDAC "other_detail" field, along with the
socket and IPID that tooling needs to translate it back into an SPA.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Avadhut Naik <avadhut.naik@amd.com>
Co-developed-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
drivers/edac/amd64_edac.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index f428d815bff1..7d7d116dbb75 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2704,11 +2704,15 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
}
+#define MSG_SIZE 256
static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
u8 ecc_type)
{
enum hw_event_mc_err_type err_type;
const char *string;
+ char s[MSG_SIZE];
+
+ s[0] = '\0';
if (ecc_type == 2)
err_type = HW_EVENT_ERR_CORRECTED;
@@ -2745,10 +2749,27 @@ static void __log_ecc_error(struct mem_ctl_info *mci, struct err_info *err,
break;
}
+ if (err->a_err.valid & ATL_OP_DA) {
+ struct atl_dram_addr *da = &err->a_err.da;
+ char *p = s, *end = p + sizeof(s);
+
+ /* Include a version prefix in case the format needs to change later. */
+ p += scnprintf(p, end - p, "[AMDv1]");
+ p += scnprintf(p, end - p, " SocketId:0x%x", err->a_err.socket_id);
+ p += scnprintf(p, end - p, " IPID:0x%llx", err->a_err.ipid);
+ p += scnprintf(p, end - p, " ChipSelect:0x%x", da->chip_select);
+ p += scnprintf(p, end - p, " Row:0x%x", da->row_addr);
+ p += scnprintf(p, end - p, " Column:0x%x", da->col_addr);
+ p += scnprintf(p, end - p, " Bank:0x%x", da->bank_addr);
+ p += scnprintf(p, end - p, " BankGroup:0x%x", da->bank_group);
+ p += scnprintf(p, end - p, " RankMul:0x%x", da->rank_mul);
+ p += scnprintf(p, end - p, " SubChannel:0x%x", da->sub_ch);
+ }
+
edac_mc_handle_error(err_type, mci, 1,
err->page, err->offset, err->syndrome,
err->csrow, err->channel, -1,
- string, "");
+ string, s);
}
static inline void decode_bus_error(int node_id, struct mce *m)
@@ -2844,7 +2865,7 @@ static void decode_umc_error(int node_id, struct mce *m)
err.a_err.addr = m->addr;
err.a_err.ipid = m->ipid;
err.a_err.cpu = m->extcpu;
- err.a_err.requested = ATL_OP_SPA;
+ err.a_err.requested = ATL_OP_SPA | ATL_OP_DA;
amd_translate_umc_mca_addr(&err.a_err);
if (!(err.a_err.valid & ATL_OP_SPA)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread