[RFC PATCH v2 11/11] EDAC/amd64: Harden Hygon Family 0x18 UMC SMN base against bad DFID
From: Aichun Shi
Date: Wed May 27 2026 - 23:57:41 EST
hygon_get_umc_base() uses hygon_get_dfid() to place the UMC register
block on compute dies (DFID >= 4). On read failure the DFID was left
uninitialized, and DFID < 4 (I/O die) would underflow (df_id - 4) and
produce a bogus SMN window.
Validate NB misc, check hygon_get_dfid() return, and reject DFID < 4
with a warning; fall back to the default UMC base without the Hygon
offset. Use unsigned arithmetic to avoid signed integer overflow when
computing the base offset for DFID values >= 12.
- Define HYGON_CDD_DFID_BASE in hygon_edac.c with a TODO noting it will
move to <asm/hygon/node.h> in Hygon Node RFC next version.
Signed-off-by: Aichun Shi <shiaichun@xxxxxxxxxxxxxx>
---
drivers/edac/hygon_edac.c | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/drivers/edac/hygon_edac.c b/drivers/edac/hygon_edac.c
index 92504edac1f9..f4d25841fecd 100644
--- a/drivers/edac/hygon_edac.c
+++ b/drivers/edac/hygon_edac.c
@@ -11,29 +11,55 @@
*/
#include <linux/pci.h>
-#include <asm/amd/nb.h>
#include <asm/hygon/node.h>
#include "amd64_edac.h"
#include "hygon_edac.h"
+/*
+ * TODO: Will move to <asm/hygon/node.h> in Hygon Node RFC next version.
+ */
+/* Hygon compute dies (CDD) start at DFID 4; IO dies occupy DFIDs 0-3. */
+#define HYGON_CDD_DFID_BASE 4
+
/*
* Hygon Family 0x18 models 0x4-0x8: UMC config is behind an SMN window derived
* from the compute-die DFID.
*/
u32 hygon_get_umc_base(struct amd64_pvt *pvt, u8 channel)
{
- struct amd_northbridge *nb = node_to_amd_nb(pvt->mc_node_id);
+ u8 df_id = 0;
+ int ret;
u32 base = get_umc_base(channel);
- u8 df_id;
if (!hygon_f18h_model_in_range(0x4, 0x8))
return base;
- if (hygon_get_dfid(nb->misc, &df_id))
+ if (!pvt->F3) {
+ amd64_warn("Hygon: no DF misc for MC node %u, using default UMC base\n",
+ pvt->mc_node_id);
+ return base;
+ }
+
+ ret = hygon_get_dfid(pvt->F3, &df_id);
+ if (ret) {
+ amd64_warn("Hygon: hygon_get_dfid failed for %s (node %u): %d, using default UMC base\n",
+ pci_name(pvt->F3), pvt->mc_node_id, ret);
return base;
+ }
+
+ /*
+ * UMCs exist only on compute dies (CDD), DFID >= HYGON_CDD_DFID_BASE.
+ * I/O dies use DFID < HYGON_CDD_DFID_BASE; the UMC base offset
+ * calculation must not run on I/O dies.
+ */
+ if (df_id < HYGON_CDD_DFID_BASE) {
+ amd64_warn("Hygon: DFID %u on %s (node %u) is not a compute die, using default UMC base\n",
+ df_id, pci_name(pvt->F3), pvt->mc_node_id);
+ return base;
+ }
- return base + (0x80000000U + (0x10000000U * (df_id - 4)));
+ return base + (0x80000000U + (0x10000000U * (df_id - HYGON_CDD_DFID_BASE)));
}
/*
--
2.47.3