[PATCH v7 1/3] RAS/AMD/ATL: Directly export address translation helper
From: Yazen Ghannam
Date: Tue Jun 30 2026 - 17:08:13 EST
Currently, the address translation function is accessed indirectly
through a function pointer set at module init. This is useful to allow
the translation library to be built as an optional module independent of
its consumers.
However, it becomes cumbersome to add new functions in this way.
Remove the indirection and export the current helper function.
This introduces a linker issue when AMD_ATL=m and a consumer module is
built-in. Address this issue by using the IS_REACHABLE() config guard.
Also, shorten the helper function name a bit.
Assisted-by: Claude:claude-opus-4-8
Originally-by: Borislav Petkov <bp@xxxxxxxxx>
Signed-off-by: Yazen Ghannam <yazen.ghannam@xxxxxxx>
---
drivers/edac/amd64_edac.c | 2 +-
drivers/ras/amd/atl/core.c | 17 ++++++-----------
drivers/ras/amd/atl/umc.c | 2 +-
drivers/ras/amd/fmpm.c | 2 +-
drivers/ras/ras.c | 31 -------------------------------
include/linux/ras.h | 8 +++-----
6 files changed, 12 insertions(+), 50 deletions(-)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index c6aa69dbd9fb..880036599456 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2847,7 +2847,7 @@ static void decode_umc_error(int node_id, struct mce *m)
a_err.ipid = m->ipid;
a_err.cpu = m->extcpu;
- sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+ sys_addr = amd_convert_umc_addr_to_sys_addr(&a_err);
if (IS_ERR_VALUE(sys_addr)) {
err.err_code = ERR_NORM_ADDR;
goto log_error;
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index 0f7cd6dab0b0..49695313f850 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -192,6 +192,12 @@ static const struct x86_cpu_id amd_atl_cpuids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, amd_atl_cpuids);
+unsigned long amd_convert_umc_addr_to_sys_addr(struct atl_err *err)
+{
+ return convert_umc_mca_addr_to_sys_addr(err);
+}
+EXPORT_SYMBOL_GPL(amd_convert_umc_addr_to_sys_addr);
+
static int __init amd_atl_init(void)
{
int ret;
@@ -210,23 +216,12 @@ 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);
pr_info("AMD Address Translation Library initialized\n");
return 0;
}
-/*
- * Exit function is only needed for testing and debug. Module unload must be
- * forced to override refcount check.
- */
-static void __exit amd_atl_exit(void)
-{
- amd_atl_unregister_decoder();
-}
-
module_init(amd_atl_init);
-module_exit(amd_atl_exit);
MODULE_DESCRIPTION("AMD Address Translation Library");
MODULE_LICENSE("GPL");
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index befc616d5e8a..b59556ded2c8 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -318,7 +318,7 @@ static void _retire_row_mi300(struct atl_err *a_err)
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);
+ addr = amd_convert_umc_addr_to_sys_addr(a_err);
if (IS_ERR_VALUE(addr))
continue;
diff --git a/drivers/ras/amd/fmpm.c b/drivers/ras/amd/fmpm.c
index 4ccaaf7b70bf..48ca7f598387 100644
--- a/drivers/ras/amd/fmpm.c
+++ b/drivers/ras/amd/fmpm.c
@@ -334,7 +334,7 @@ static void save_spa(struct fru_rec *rec, unsigned int entry,
a_err.ipid = id;
a_err.cpu = cpu;
- spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+ spa = amd_convert_umc_addr_to_sys_addr(&a_err);
if (IS_ERR_VALUE(spa)) {
pr_debug("Failed to get system address\n");
return;
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 03df3db62334..011de2c257b1 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -10,37 +10,6 @@
#include <linux/ras.h>
#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);
-#endif /* CONFIG_AMD_ATL */
-
#define CREATE_TRACE_POINTS
#define TRACE_INCLUDE_PATH ../../include/ras
#include <ras/ras_event.h>
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 468941bfe855..4b095ddb9071 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -41,15 +41,13 @@ struct atl_err {
u32 cpu;
};
-#if IS_ENABLED(CONFIG_AMD_ATL)
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
-void amd_atl_unregister_decoder(void);
+#if IS_REACHABLE(CONFIG_AMD_ATL)
void amd_retire_dram_row(struct atl_err *err);
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+unsigned long amd_convert_umc_addr_to_sys_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; }
+amd_convert_umc_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
#endif /* CONFIG_AMD_ATL */
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
--
2.53.0