From 7de99818be601b1e6a7248431c59072b94adca77 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 15:28:46 +0800 Subject: [PATCH 01/13] x86/amd_nb: Add helper function to identify Hygon family 18h model 10h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN2NP CVE: NA --------------------------- Add hygon_f18h_m10h() to identify Hygon family 18h model 10h processors. Signed-off-by: Wenhui Fan --- arch/x86/include/asm/amd_nb.h | 2 ++ arch/x86/kernel/amd_nb.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index b6e5db1069e9..e48a7e2ba40c 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -85,6 +85,7 @@ bool amd_nb_has_feature(unsigned int feature); struct amd_northbridge *node_to_amd_nb(int node); bool hygon_f18h_m4h(void); +bool hygon_f18h_m10h(void); u16 hygon_nb_num(void); int get_df_id(struct pci_dev *misc, u8 *id); @@ -126,6 +127,7 @@ static inline bool amd_gart_present(void) #define amd_gart_present(x) false #define hygon_f18h_m4h false +#define hygon_f18h_m10h false #define hygon_nb_num(x) 0 #define get_df_id(x, y) NULL diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 2e098ea71759..4681cf9f9b33 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -257,6 +257,20 @@ bool hygon_f18h_m4h(void) } EXPORT_SYMBOL_GPL(hygon_f18h_m4h); +bool hygon_f18h_m10h(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) + return false; + + if (boot_cpu_data.x86 == 0x18 && + boot_cpu_data.x86_model >= 0x10 && + boot_cpu_data.x86_model <= 0x1f) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(hygon_f18h_m10h); + u16 hygon_nb_num(void) { return nb_num; -- Gitee From 93406a2f44663431b00025f5f43772d8684679c3 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 15:30:28 +0800 Subject: [PATCH 02/13] EDAC/amd64: Check if umc channel is enabled for Hygon family 18h model 10h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN2NP CVE: NA --------------------------- For Hygon family 18h model 10h processor, channels without memory are gated. As a result, all bits in relevant registers are set to 1, which cause the edac driver initializing incorrectly. So add support to check if the umc channel is effectively enabled. Signed-off-by: Wenhui Fan --- drivers/edac/amd64_edac.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5c6586845b91..c131f8d61ddc 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -867,12 +867,29 @@ static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) } } +static bool hygon_umc_channel_enabled(u16 nid, int channel) +{ + u32 enable; + + if (hygon_f18h_m10h()) { + amd_df_indirect_read(nid, 1, 0x32c, 0xc, &enable); + if ((enable & BIT(channel))) + return true; + return false; + } + + return true; +} + static void __dump_misc_regs_df(struct amd64_pvt *pvt) { struct amd64_umc *umc; u32 i, tmp, umc_base; for_each_umc(i) { + if (!hygon_umc_channel_enabled(pvt->mc_node_id, i)) + continue; + if (hygon_f18h_m4h()) umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i); else @@ -1000,6 +1017,9 @@ static void read_umc_base_mask(struct amd64_pvt *pvt) int cs, umc; for_each_umc(umc) { + if (!hygon_umc_channel_enabled(pvt->mc_node_id, umc)) + continue; + if (hygon_f18h_m4h()) umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, umc); else @@ -2921,6 +2941,9 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt) /* Read registers from each UMC */ for_each_umc(i) { + if (!hygon_umc_channel_enabled(pvt->mc_node_id, i)) + continue; + if (hygon_f18h_m4h()) umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i); else @@ -3388,6 +3411,9 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) else base = get_umc_base(i); + if (!hygon_umc_channel_enabled(nid, i)) + continue; + /* Only check enabled UMCs. */ if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value)) continue; -- Gitee From f4628df3f044b06b1d7a7aff5fedc9e40be58fa4 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 15:33:41 +0800 Subject: [PATCH 03/13] EDAC/amd64: Get correct memory type for Hygon family 18h model 10h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN2NP CVE: NA --------------------------- Get the correct DDR memory types for Hygon family 18h model 10h. Signed-off-by: Wenhui Fan --- drivers/edac/amd64_edac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c131f8d61ddc..80090a7fc171 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1133,7 +1133,9 @@ static void determine_memory_type_df(struct amd64_pvt *pvt) * Check if the system supports the "DDR Type" field in UMC Config * and has DDR5 DIMMs in use. */ - if ((fam_type->flags.zn_regs_v2 || hygon_f18h_m4h()) && + if ((fam_type->flags.zn_regs_v2 || + hygon_f18h_m4h() || + hygon_f18h_m10h()) && ((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) { if (umc->dimm_cfg & BIT(5)) umc->dram_type = MEM_LRDDR5; -- Gitee From a51411e2f17e495839671ebc9033e89331c94498 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Fri, 14 Feb 2025 17:28:50 +0800 Subject: [PATCH 04/13] x86/MCE/AMD: Fix the calculation of cs id for Hygon family 18h model 4h hygon inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBMDWA CVE: NA --------------------------- Get the correct cs id in die interleave scenario for Hygon family 18h model 4h. Fixes: 08fdc64fd095 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: Wenhui Fan --- arch/x86/kernel/cpu/mce/amd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 6ae54119205a..797100f8c168 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -785,12 +785,14 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (hygon_f18h_m4h()) { die_id_shift = (tmp >> 12) & 0xF; die_id_mask = tmp & 0x7FF; + cs_id |= (((cs_fabric_id & die_id_mask) >> die_id_shift) - 4) << + die_id_bit; } else { die_id_shift = (tmp >> 24) & 0xF; die_id_mask = (tmp >> 8) & 0xFF; + cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << + die_id_bit; } - - cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit; } /* If interleaved over more than 1 socket. */ -- Gitee From fe6e5426547d6e0e631510bacf6800cfa54875aa Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Fri, 14 Feb 2025 17:41:36 +0800 Subject: [PATCH 05/13] x86/MCE/AMD: Use u16 for some umc variables for Hygon family 18h model 4h hygon inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBME2Y CVE: NA --------------------------- The width of die/socket id mask and cs fabric id is extended to 11 bits since Hygon family 18h model 4h, so use u16 for those variables which are also suitable for all other older generation Hygon processors. Fixes: 08fdc64fd095 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: Wenhui Fan --- arch/x86/kernel/cpu/mce/amd.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 797100f8c168..29910b01aee1 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -643,7 +643,12 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) u32 tmp; - u8 die_id_shift, die_id_mask, socket_id_shift, socket_id_mask; + u8 die_id_shift, socket_id_shift; +#ifdef CONFIG_CPU_SUP_HYGON + u16 die_id_mask, socket_id_mask; +#else + u8 die_id_mask, socket_id_mask; +#endif u8 intlv_num_dies, intlv_num_chan, intlv_num_sockets; u8 intlv_addr_sel, intlv_addr_bit; u8 num_intlv_bits, hashed_bit; @@ -748,7 +753,12 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (num_intlv_bits > 0) { u64 temp_addr_x, temp_addr_i, temp_addr_y; - u8 die_id_bit, sock_id_bit, cs_fabric_id; + u8 die_id_bit, sock_id_bit; +#ifdef CONFIG_CPU_SUP_HYGON + u16 cs_fabric_id; +#else + u8 cs_fabric_id; +#endif /* * Read FabricBlockInstanceInformation3_CS[BlockFabricID]. -- Gitee From 4871d23675c409efac7008ab1ac44dfafe40ff0c Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 14:19:23 +0800 Subject: [PATCH 06/13] x86/MCE/AMD: Get intlv_num_dies from F0x60 for Hygon family 18h model 6h hygon inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBN1BI CVE: NA --------------------------- The intlv_num_dies should be get from F0x60[1:0] for Hygon family 18h model 6h. Fixes: 08fdc64fd095 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: Wenhui Fan --- arch/x86/kernel/cpu/mce/amd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 29910b01aee1..5785fb51c9e3 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -710,6 +710,12 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) intlv_addr_bit = intlv_addr_sel + 8; + if (hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) { + if (amd_df_indirect_read(nid, 0, 0x60, umc, &tmp)) + goto out_err; + intlv_num_dies = tmp & 0x3; + } + /* Re-use intlv_num_chan by setting it equal to log2(#channels) */ switch (intlv_num_chan) { case 0: intlv_num_chan = 0; break; -- Gitee From 5d7a8dd8c846995f74747f09e572130578c04166 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 15:29:35 +0800 Subject: [PATCH 07/13] EDAC/amd64: Adjust address translation for Hygon family 18h model 10h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN2NP CVE: NA --------------------------- Add umc address translation support for Hygon family 18h model 10h. Signed-off-by: Wenhui Fan --- arch/x86/kernel/cpu/mce/amd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 5785fb51c9e3..dbb3647cea24 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -657,7 +657,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) bool hash_enabled = false; /* Read DramOffset, check if base 1 is used. */ - if (hygon_f18h_m4h() && + if ((hygon_f18h_m4h() || hygon_f18h_m10h()) && amd_df_indirect_read(nid, 0, 0x214, umc, &tmp)) goto out_err; else if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp)) @@ -685,7 +685,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) } intlv_num_sockets = 0; - if (hygon_f18h_m4h()) + if (hygon_f18h_m4h() || hygon_f18h_m10h()) intlv_num_sockets = (tmp >> 2) & 0x3; lgcy_mmio_hole_en = tmp & BIT(1); intlv_num_chan = (tmp >> 4) & 0xF; @@ -703,14 +703,15 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (amd_df_indirect_read(nid, 0, 0x114 + (8 * base), umc, &tmp)) goto out_err; - if (!hygon_f18h_m4h()) + if (!hygon_f18h_m4h() && !hygon_f18h_m10h()) intlv_num_sockets = (tmp >> 8) & 0x1; intlv_num_dies = (tmp >> 10) & 0x3; dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0); intlv_addr_bit = intlv_addr_sel + 8; - if (hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) { + if ((hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) || + hygon_f18h_m10h()) { if (amd_df_indirect_read(nid, 0, 0x60, umc, &tmp)) goto out_err; intlv_num_dies = tmp & 0x3; @@ -775,7 +776,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (amd_df_indirect_read(nid, 0, 0x50, umc, &tmp)) goto out_err; - if (hygon_f18h_m4h()) + if (hygon_f18h_m4h() || hygon_f18h_m10h()) cs_fabric_id = (tmp >> 8) & 0x7FF; else cs_fabric_id = (tmp >> 8) & 0xFF; -- Gitee From 7d476f08476f5d9287dc21988801306fd3cbec8e Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 11:24:18 +0800 Subject: [PATCH 08/13] EDAC/amd64: Fix the calculation of instance id for Hygon family 18h model 6h hygon inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBN075 CVE: NA --------------------------- On Hygon family 18h model 6h platform, each DDR has two subchannels, and each subchannel has a mca bank with a cs corresponded. In the process of address translation, it needs to know the instance id of cs to access df register correctly. The instance id of cs can be calculated from IPID[23:20] and IPID[13]: IPID[23:20] represents which umc controller it belongs to, and IPID[13] represents which subchannel it is. Fixes: d0d1ed37697f ("EDAC/amd64: Adjust UMC channel for Hygon family 18h model 6h") Signed-off-by: Wenhui Fan --- drivers/edac/amd64_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 80090a7fc171..fbe0ad369ba9 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2801,7 +2801,7 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; if (hygon_f18h_m4h() && boot_cpu_data.x86_model == 0x6) - umc = err.channel << 1; + umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); else umc = err.channel; -- Gitee From f54a930cf07dd877f74c9c8518fe5113801bb2fd Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 14:42:20 +0800 Subject: [PATCH 09/13] EDAC/amd64: Calculate instance id for hygon family 18h model 7h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN1FG CVE: NA --------------------------- The instance id for Hygon family 18h model 7h and 10h is also get from IPID[23:20] and IPID[13]. Signed-off-by: Wenhui Fan --- drivers/edac/amd64_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index fbe0ad369ba9..9346ffdef169 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2800,7 +2800,7 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; - if (hygon_f18h_m4h() && boot_cpu_data.x86_model == 0x6) + if (hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); else umc = err.channel; -- Gitee From fc6026e6e236b552fe0fd26949525e86324a72ba Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 18 Feb 2025 16:26:44 +0800 Subject: [PATCH 10/13] EDAC/amd64: Get instance id for Hygon family 18h model 10h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBN2NP CVE: NA --------------------------- The instance id for Hygon family 18h model 10h is also get from IPID[23:20] and IPID[13]. Signed-off-by: Wenhui Fan --- drivers/edac/amd64_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9346ffdef169..e969a98f80b0 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2800,7 +2800,8 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; - if (hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) + if ((hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) || + hygon_f18h_m10h()) umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); else umc = err.channel; -- Gitee From f1184d87efe9e888e64b38841297c0bb6cd518a5 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Mon, 26 May 2025 16:26:56 +0800 Subject: [PATCH 11/13] EDAC/amd64: Rename the address translation function for hygon family 18h model 4h hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IDCQQ7 CVE: N/A Reference: https://gitee.com/anolis/cloud-kernel/commit/2fd0f2d3d438474350d001a8e5ef4304b0bd1bfa -------------------------------------------------------------------------------- ANBZ: #21447 Use the original function umc_normaddr_to_sysaddr() for AMD processors and use the function hygon_umc_normaddr_to_sysaddr() for Hygon processors. Hygon-SIG: commit 2fd0f2d3d438 anolis EDAC/amd64: Rename the address translation function for hygon family 18h model 4h Backport to fix EDAC address translation issue for Hygon processor. Signed-off-by: Wenhui Fan Reviewed-by: Ruidong Tian Reviewed-by: Guixin Liu Link: https://gitee.com/anolis/cloud-kernel/pulls/5346 [ Aichun Shi: amend commit log and resolve the conflict ] Signed-off-by: Aichun Shi --- arch/x86/kernel/cpu/mce/amd.c | 67 ++-------- drivers/edac/amd64_edac.c | 243 ++++++++++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 62 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index dbb3647cea24..e734ce856782 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -643,12 +643,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) u32 tmp; - u8 die_id_shift, socket_id_shift; -#ifdef CONFIG_CPU_SUP_HYGON - u16 die_id_mask, socket_id_mask; -#else - u8 die_id_mask, socket_id_mask; -#endif + u8 die_id_shift, die_id_mask, socket_id_shift, socket_id_mask; u8 intlv_num_dies, intlv_num_chan, intlv_num_sockets; u8 intlv_addr_sel, intlv_addr_bit; u8 num_intlv_bits, hashed_bit; @@ -656,11 +651,8 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) u8 cs_mask, cs_id = 0; bool hash_enabled = false; - /* Read DramOffset, check if base 1 is used. */ - if ((hygon_f18h_m4h() || hygon_f18h_m10h()) && - amd_df_indirect_read(nid, 0, 0x214, umc, &tmp)) - goto out_err; - else if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp)) + /* Read D18F0x1B4 (DramOffset), check if base 1 is used. */ + if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp)) goto out_err; /* Remove HiAddrOffset from normalized address, if enabled: */ @@ -684,9 +676,6 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) goto out_err; } - intlv_num_sockets = 0; - if (hygon_f18h_m4h() || hygon_f18h_m10h()) - intlv_num_sockets = (tmp >> 2) & 0x3; lgcy_mmio_hole_en = tmp & BIT(1); intlv_num_chan = (tmp >> 4) & 0xF; intlv_addr_sel = (tmp >> 8) & 0x7; @@ -703,20 +692,12 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (amd_df_indirect_read(nid, 0, 0x114 + (8 * base), umc, &tmp)) goto out_err; - if (!hygon_f18h_m4h() && !hygon_f18h_m10h()) - intlv_num_sockets = (tmp >> 8) & 0x1; + intlv_num_sockets = (tmp >> 8) & 0x1; intlv_num_dies = (tmp >> 10) & 0x3; dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0); intlv_addr_bit = intlv_addr_sel + 8; - if ((hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) || - hygon_f18h_m10h()) { - if (amd_df_indirect_read(nid, 0, 0x60, umc, &tmp)) - goto out_err; - intlv_num_dies = tmp & 0x3; - } - /* Re-use intlv_num_chan by setting it equal to log2(#channels) */ switch (intlv_num_chan) { case 0: intlv_num_chan = 0; break; @@ -729,9 +710,6 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) hash_enabled = true; break; default: - if (hygon_f18h_m4h() && boot_cpu_data.x86_model == 0x4 && - intlv_num_chan == 2) - break; pr_err("%s: Invalid number of interleaved channels %d.\n", __func__, intlv_num_chan); goto out_err; @@ -750,9 +728,8 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) /* Add a bit if sockets are interleaved. */ num_intlv_bits += intlv_num_sockets; - /* Assert num_intlv_bits in the correct range. */ - if ((hygon_f18h_m4h() && num_intlv_bits > 7) || - (!hygon_f18h_m4h() && num_intlv_bits > 4)) { + /* Assert num_intlv_bits <= 4 */ + if (num_intlv_bits > 4) { pr_err("%s: Invalid interleave bits %d.\n", __func__, num_intlv_bits); goto out_err; @@ -760,12 +737,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (num_intlv_bits > 0) { u64 temp_addr_x, temp_addr_i, temp_addr_y; - u8 die_id_bit, sock_id_bit; -#ifdef CONFIG_CPU_SUP_HYGON - u16 cs_fabric_id; -#else - u8 cs_fabric_id; -#endif + u8 die_id_bit, sock_id_bit, cs_fabric_id; /* * Read FabricBlockInstanceInformation3_CS[BlockFabricID]. @@ -776,10 +748,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) if (amd_df_indirect_read(nid, 0, 0x50, umc, &tmp)) goto out_err; - if (hygon_f18h_m4h() || hygon_f18h_m10h()) - cs_fabric_id = (tmp >> 8) & 0x7FF; - else - cs_fabric_id = (tmp >> 8) & 0xFF; + cs_fabric_id = (tmp >> 8) & 0xFF; die_id_bit = 0; /* If interleaved over more than 1 channel: */ @@ -799,26 +768,16 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) /* If interleaved over more than 1 die. */ if (intlv_num_dies) { sock_id_bit = die_id_bit + intlv_num_dies; - if (hygon_f18h_m4h()) { - die_id_shift = (tmp >> 12) & 0xF; - die_id_mask = tmp & 0x7FF; - cs_id |= (((cs_fabric_id & die_id_mask) >> die_id_shift) - 4) << - die_id_bit; - } else { - die_id_shift = (tmp >> 24) & 0xF; - die_id_mask = (tmp >> 8) & 0xFF; - cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << - die_id_bit; - } + die_id_shift = (tmp >> 24) & 0xF; + die_id_mask = (tmp >> 8) & 0xFF; + + cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit; } /* If interleaved over more than 1 socket. */ if (intlv_num_sockets) { socket_id_shift = (tmp >> 28) & 0xF; - if (hygon_f18h_m4h()) - socket_id_mask = (tmp >> 16) & 0x7FF; - else - socket_id_mask = (tmp >> 16) & 0xFF; + socket_id_mask = (tmp >> 16) & 0xFF; cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit; } diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e969a98f80b0..0a58dcf4209b 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -732,6 +732,227 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) return csrow; } +static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) +{ + u64 dram_base_addr, dram_limit_addr, dram_hole_base; + /* We start from the normalized address */ + u64 ret_addr = norm_addr; + + u32 tmp; + + u16 die_id_mask, socket_id_mask, cs_id = 0; + u8 die_id_shift, socket_id_shift; + u8 intlv_num_dies, intlv_num_chan, intlv_num_sockets; + u8 intlv_addr_sel, intlv_addr_bit; + u8 num_intlv_bits, hashed_bit; + u8 lgcy_mmio_hole_en, base = 0; + u8 cs_mask; + bool hash_enabled = false; + + /* Read DramOffset, check if base 1 is used. */ + if (amd_df_indirect_read(nid, 0, 0x214, umc, &tmp)) + goto out_err; + + /* Remove HiAddrOffset from normalized address, if enabled: */ + if (tmp & BIT(0)) { + u64 hi_addr_offset = (tmp & GENMASK_ULL(31, 20)) << 8; + + if (norm_addr >= hi_addr_offset) { + ret_addr -= hi_addr_offset; + base = 1; + } + } + + /* Read D18F0x110 (DramBaseAddress). */ + if (amd_df_indirect_read(nid, 0, 0x110 + (8 * base), umc, &tmp)) + goto out_err; + + /* Check if address range is valid. */ + if (!(tmp & BIT(0))) { + pr_err("%s: Invalid DramBaseAddress range: 0x%x.\n", + __func__, tmp); + goto out_err; + } + + intlv_num_sockets = (tmp >> 2) & 0x3; + lgcy_mmio_hole_en = tmp & BIT(1); + intlv_num_chan = (tmp >> 4) & 0xF; + intlv_addr_sel = (tmp >> 8) & 0x7; + dram_base_addr = (tmp & GENMASK_ULL(31, 12)) << 16; + + /* {0, 1, 2, 3} map to address bits {8, 9, 10, 11} respectively */ + if (intlv_addr_sel > 3) { + pr_err("%s: Invalid interleave address select %d.\n", + __func__, intlv_addr_sel); + goto out_err; + } + + /* Read D18F0x114 (DramLimitAddress). */ + if (amd_df_indirect_read(nid, 0, 0x114 + (8 * base), umc, &tmp)) + goto out_err; + + intlv_num_dies = (tmp >> 10) & 0x3; + dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0); + + intlv_addr_bit = intlv_addr_sel + 8; + + if (boot_cpu_data.x86_model >= 0x6) { + if (amd_df_indirect_read(nid, 0, 0x60, umc, &tmp)) + goto out_err; + intlv_num_dies = tmp & 0x3; + } + + /* Re-use intlv_num_chan by setting it equal to log2(#channels) */ + switch (intlv_num_chan) { + case 0: + intlv_num_chan = 0; + break; + case 1: + intlv_num_chan = 1; + break; + case 3: + intlv_num_chan = 2; + break; + case 5: + intlv_num_chan = 3; + break; + case 7: + intlv_num_chan = 4; + break; + case 8: + intlv_num_chan = 1; + hash_enabled = true; + break; + default: + if (boot_cpu_data.x86_model == 0x4 && + intlv_num_chan == 2) + break; + pr_err("%s: Invalid number of interleaved channels %d.\n", + __func__, intlv_num_chan); + goto out_err; + } + + num_intlv_bits = intlv_num_chan; + + if (intlv_num_dies > 2) { + pr_err("%s: Invalid number of interleaved nodes/dies %d.\n", + __func__, intlv_num_dies); + goto out_err; + } + + num_intlv_bits += intlv_num_dies; + + /* Add a bit if sockets are interleaved. */ + num_intlv_bits += intlv_num_sockets; + + /* Assert num_intlv_bits in the correct range. */ + if (num_intlv_bits > 7) { + pr_err("%s: Invalid interleave bits %d.\n", + __func__, num_intlv_bits); + goto out_err; + } + + if (num_intlv_bits > 0) { + u64 temp_addr_x, temp_addr_i, temp_addr_y; + u8 die_id_bit, sock_id_bit; + u16 cs_fabric_id; + + /* + * Read FabricBlockInstanceInformation3_CS[BlockFabricID]. + * This is the fabric id for this coherent slave. Use + * umc/channel# as instance id of the coherent slave + * for FICAA. + */ + if (amd_df_indirect_read(nid, 0, 0x50, umc, &tmp)) + goto out_err; + + cs_fabric_id = (tmp >> 8) & 0x7FF; + die_id_bit = 0; + + /* If interleaved over more than 1 channel: */ + if (intlv_num_chan) { + die_id_bit = intlv_num_chan; + cs_mask = (1 << die_id_bit) - 1; + cs_id = cs_fabric_id & cs_mask; + } + + sock_id_bit = die_id_bit; + + /* Read D18F1x208 (SystemFabricIdMask). */ + if (intlv_num_dies || intlv_num_sockets) + if (amd_df_indirect_read(nid, 1, 0x208, umc, &tmp)) + goto out_err; + + /* If interleaved over more than 1 die. */ + if (intlv_num_dies) { + sock_id_bit = die_id_bit + intlv_num_dies; + die_id_shift = (tmp >> 12) & 0xF; + die_id_mask = tmp & 0x7FF; + + cs_id |= (((cs_fabric_id & die_id_mask) >> die_id_shift) - 4) << + die_id_bit; + } + + /* If interleaved over more than 1 socket. */ + if (intlv_num_sockets) { + socket_id_shift = (tmp >> 28) & 0xF; + socket_id_mask = (tmp >> 16) & 0x7FF; + + cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit; + } + + /* + * The pre-interleaved address consists of XXXXXXIIIYYYYY + * where III is the ID for this CS, and XXXXXXYYYYY are the + * address bits from the post-interleaved address. + * "num_intlv_bits" has been calculated to tell us how many "I" + * bits there are. "intlv_addr_bit" tells us how many "Y" bits + * there are (where "I" starts). + */ + temp_addr_y = ret_addr & GENMASK_ULL(intlv_addr_bit-1, 0); + temp_addr_i = (cs_id << intlv_addr_bit); + temp_addr_x = (ret_addr & GENMASK_ULL(63, intlv_addr_bit)) << num_intlv_bits; + ret_addr = temp_addr_x | temp_addr_i | temp_addr_y; + } + + /* Add dram base address */ + ret_addr += dram_base_addr; + + /* If legacy MMIO hole enabled */ + if (lgcy_mmio_hole_en) { + if (amd_df_indirect_read(nid, 0, 0x104, umc, &tmp)) + goto out_err; + + dram_hole_base = tmp & GENMASK(31, 24); + if (ret_addr >= dram_hole_base) + ret_addr += (BIT_ULL(32) - dram_hole_base); + } + + if (hash_enabled) { + /* Save some parentheses and grab ls-bit at the end. */ + hashed_bit = (ret_addr >> 12) ^ + (ret_addr >> 18) ^ + (ret_addr >> 21) ^ + (ret_addr >> 30) ^ + cs_id; + + hashed_bit &= BIT(0); + + if (hashed_bit != ((ret_addr >> intlv_addr_bit) & BIT(0))) + ret_addr ^= BIT(intlv_addr_bit); + } + + /* Is calculated system address is above DRAM limit address? */ + if (ret_addr > dram_limit_addr) + goto out_err; + + *sys_addr = ret_addr; + return 0; + +out_err: + return -EINVAL; +} + static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16); /* @@ -2800,15 +3021,21 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; - if ((hygon_f18h_m4h() && boot_cpu_data.x86_model >= 0x6) || - hygon_f18h_m10h()) - umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); - else - umc = err.channel; + if (hygon_f18h_m4h() || hygon_f18h_m10h()) { + if (boot_cpu_data.x86_model >= 0x6) + umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); + else + umc = err.channel; - if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, umc, &sys_addr)) { - err.err_code = ERR_NORM_ADDR; - goto log_error; + if (hygon_umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, umc, &sys_addr)) { + err.err_code = ERR_NORM_ADDR; + goto log_error; + } + } else { + if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { + err.err_code = ERR_NORM_ADDR; + goto log_error; + } } error_address_to_page_and_offset(sys_addr, &err); -- Gitee From 317bbff0abe71e46162d37346b0e15027ca6f267 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Mon, 26 May 2025 16:52:21 +0800 Subject: [PATCH 12/13] EDAC/amd64: Correct the address translation for hygon family 18h model 4h hygon inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDCQQ7 CVE: N/A Reference: https://gitee.com/anolis/cloud-kernel/commit/d15e452ea7ce67772d078158c676ddd5b9cd903d -------------------------------------------------------------------------------- ANBZ: #21447 For Hygon family 18h model 4h processor, the normal address does not contain sub-channel bit, so it need to reserve the bit field for sub-channel and fill it in the address translating process. In the 3 channels interleaving scenario, the calculation of cs id is different from other scenarios. Hygon-SIG: commit d15e452ea7ce anolis EDAC/amd64: Correct the address translation for hygon family 18h model 4h Backport to fix EDAC address translation issue for Hygon processor. Fixes: 08fdc64fd095 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: Wenhui Fan Reviewed-by: Ruidong Tian Reviewed-by: Guixin Liu Link: https://gitee.com/anolis/cloud-kernel/pulls/5346 [ Aichun Shi: amend commit log and resolve the conflict ] Signed-off-by: Aichun Shi --- drivers/edac/amd64_edac.c | 98 ++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 0a58dcf4209b..4eae173f7ec3 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -732,7 +732,8 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) return csrow; } -static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) +static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, + u8 sub_channel, u64 *sys_addr) { u64 dram_base_addr, dram_limit_addr, dram_hole_base; /* We start from the normalized address */ @@ -740,10 +741,11 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy u32 tmp; - u16 die_id_mask, socket_id_mask, cs_id = 0; + u16 die_id_mask, socket_id_mask, dst_fabric_id, cs_id = 0; u8 die_id_shift, socket_id_shift; u8 intlv_num_dies, intlv_num_chan, intlv_num_sockets; u8 intlv_addr_sel, intlv_addr_bit; + u8 chan_addr_sel, chan_hash_enable, ddr5_enable, start_bit; u8 num_intlv_bits, hashed_bit; u8 lgcy_mmio_hole_en, base = 0; u8 cs_mask; @@ -793,6 +795,8 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy intlv_num_dies = (tmp >> 10) & 0x3; dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0); + if (boot_cpu_data.x86_model == 0x4) + dst_fabric_id = tmp & GENMASK_ULL(9, 0); intlv_addr_bit = intlv_addr_sel + 8; @@ -802,6 +806,31 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy intlv_num_dies = tmp & 0x3; } + if (boot_cpu_data.x86_model == 0x4) { + if (amd_df_indirect_read(nid, 2, 0x48, umc, &tmp)) + goto out_err; + chan_addr_sel = (tmp >> 24) & 0x1; + chan_hash_enable = (tmp >> 23) & 0x1; + ddr5_enable = (tmp >> 19) & 0x1; + if (ddr5_enable) { + u64 low_addr, high_addr; + + if (chan_addr_sel) + start_bit = 8; + else + start_bit = 7; + + low_addr = ret_addr & GENMASK_ULL(start_bit - 1, 0); + /* + * Reserve the sub-channel bit filed(ret_addr[start_bit]), + * and fill the sub-channel bit in the later channel hashing + * process. + */ + high_addr = (ret_addr & GENMASK_ULL(63, start_bit)) << 1; + ret_addr = high_addr | low_addr; + } + } + /* Re-use intlv_num_chan by setting it equal to log2(#channels) */ switch (intlv_num_chan) { case 0: @@ -853,7 +882,7 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy } if (num_intlv_bits > 0) { - u64 temp_addr_x, temp_addr_i, temp_addr_y; + u64 temp_addr_x, temp_addr_i, temp_addr_y, addr_mul3; u8 die_id_bit, sock_id_bit; u16 cs_fabric_id; @@ -872,8 +901,30 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy /* If interleaved over more than 1 channel: */ if (intlv_num_chan) { die_id_bit = intlv_num_chan; - cs_mask = (1 << die_id_bit) - 1; - cs_id = cs_fabric_id & cs_mask; + + /* + * In the 3 channels interleaving scenario, the calculation + * of cs id is different from other scenarios. + */ + if (boot_cpu_data.x86_model == 0x4 && intlv_num_chan == 2) { + u8 cs_offset; + + cs_offset = (cs_fabric_id & 0x3) - (dst_fabric_id & 0x3); + if (cs_offset > 3) { + pr_err("%s: Invalid cs offset: 0x%x cs_fabric_id: 0x%x dst_fabric_id: 0x%x.\n", + __func__, cs_offset, cs_fabric_id, dst_fabric_id); + goto out_err; + } + temp_addr_x = (ret_addr & GENMASK_ULL(63, intlv_addr_bit)) >> + intlv_addr_bit; + temp_addr_y = ret_addr & GENMASK_ULL(intlv_addr_bit - 1, 0); + + addr_mul3 = temp_addr_x * 3 + cs_offset; + cs_id = addr_mul3 & GENMASK_ULL(intlv_num_chan - 1, 0); + } else { + cs_mask = (1 << die_id_bit) - 1; + cs_id = cs_fabric_id & cs_mask; + } } sock_id_bit = die_id_bit; @@ -909,10 +960,16 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy * bits there are. "intlv_addr_bit" tells us how many "Y" bits * there are (where "I" starts). */ - temp_addr_y = ret_addr & GENMASK_ULL(intlv_addr_bit-1, 0); - temp_addr_i = (cs_id << intlv_addr_bit); - temp_addr_x = (ret_addr & GENMASK_ULL(63, intlv_addr_bit)) << num_intlv_bits; - ret_addr = temp_addr_x | temp_addr_i | temp_addr_y; + if (boot_cpu_data.x86_model == 0x4 && intlv_num_chan == 2) { + temp_addr_i = ((addr_mul3 >> intlv_num_chan) << intlv_num_chan) | cs_id; + ret_addr = temp_addr_y | (temp_addr_i << intlv_addr_bit); + } else { + temp_addr_y = ret_addr & GENMASK_ULL(intlv_addr_bit - 1, 0); + temp_addr_i = (cs_id << intlv_addr_bit); + temp_addr_x = (ret_addr & GENMASK_ULL(63, intlv_addr_bit)) << + num_intlv_bits; + ret_addr = temp_addr_x | temp_addr_i | temp_addr_y; + } } /* Add dram base address */ @@ -942,6 +999,21 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sy ret_addr ^= BIT(intlv_addr_bit); } + /* The channel hashing process. */ + if (boot_cpu_data.x86_model == 0x4 && ddr5_enable) { + if (chan_hash_enable) { + hashed_bit = (ret_addr >> 12) ^ + (ret_addr >> 21) ^ + (ret_addr >> 30) ^ + sub_channel; + hashed_bit &= BIT(0); + ret_addr |= hashed_bit << start_bit; + + } else { + ret_addr |= sub_channel << start_bit; + } + } + /* Is calculated system address is above DRAM limit address? */ if (ret_addr > dram_limit_addr) goto out_err; @@ -2990,7 +3062,7 @@ static void decode_umc_error(int node_id, struct mce *m) struct amd64_pvt *pvt; struct err_info err; u64 sys_addr; - u8 umc; + u8 umc, sub_channel = 0; mci = edac_mc_find(node_id); if (!mci) @@ -3022,12 +3094,14 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; if (hygon_f18h_m4h() || hygon_f18h_m10h()) { + sub_channel = (m->ipid & BIT(13)) >> 13; if (boot_cpu_data.x86_model >= 0x6) - umc = (err.channel << 1) + ((m->ipid & BIT(13)) >> 13); + umc = (err.channel << 1) + sub_channel; else umc = err.channel; - if (hygon_umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, umc, &sys_addr)) { + if (hygon_umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, umc, + sub_channel, &sys_addr)) { err.err_code = ERR_NORM_ADDR; goto log_error; } -- Gitee From 59a7a7271b7619213417f958a22fddb13b90ae38 Mon Sep 17 00:00:00 2001 From: Wenhui Fan Date: Tue, 28 Oct 2025 14:11:03 +0800 Subject: [PATCH 13/13] EDAC/amd64: The width of hash value is 2 bits for Hygon family 18h model 6h processors hygon inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IDCQR1 CVE: N/A Reference: https://gitee.com/anolis/cloud-kernel/commit/95e0df888d5d977c100b27b627b800a2a09baba8 -------------------------------------------------------------------------------- ANBZ: #26500 It has 2 bits hash value when hash enabled for hygon family 18h model 6h. Hygon-SIG: commit none hygon anolis: EDAC/amd64: The width of hash value is 2 bits for Hygon family 18h model 6h processors Hygon-SIG: commit 95e0df888d5d anolis EDAC/amd64: The width of hash value is 2 bits for Hygon family 18h model 6h processors Backport to add 2 bits of hash values EDAC support for Hygon Processors. Signed-off-by: Wenhui Fan Cc: hygon-arch@list.openanolis.cn Reviewed-by: Guixin Liu Link: https://gitee.com/anolis/cloud-kernel/pulls/5912 [ Aichun Shi: amend commit log and resolve the conflict ] Signed-off-by: Aichun Shi --- drivers/edac/amd64_edac.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 4eae173f7ec3..01332e52e036 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -849,7 +849,10 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, intlv_num_chan = 4; break; case 8: - intlv_num_chan = 1; + if (boot_cpu_data.x86_model >= 0x6) + intlv_num_chan = 2; + else + intlv_num_chan = 1; hash_enabled = true; break; default: @@ -993,10 +996,16 @@ static int hygon_umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, (ret_addr >> 30) ^ cs_id; - hashed_bit &= BIT(0); - - if (hashed_bit != ((ret_addr >> intlv_addr_bit) & BIT(0))) - ret_addr ^= BIT(intlv_addr_bit); + if (boot_cpu_data.x86_model >= 0x6) { + hashed_bit &= 0x3; + if (hashed_bit != ((ret_addr >> intlv_addr_bit) & 0x3)) + ret_addr = (ret_addr & ~((u64)3 << intlv_addr_bit)) | + (hashed_bit << intlv_addr_bit); + } else { + hashed_bit &= BIT(0); + if (hashed_bit != ((ret_addr >> intlv_addr_bit) & BIT(0))) + ret_addr ^= BIT(intlv_addr_bit); + } } /* The channel hashing process. */ -- Gitee