From b0a648d982c994be51adcf755f59895cc8cd3fd8 Mon Sep 17 00:00:00 2001 From: fuhao Date: Thu, 1 Feb 2024 15:08:04 +0800 Subject: [PATCH 1/4] EDAC/amd64: Revert hi_addr_offset for Hygon family 18h model 4h The HiAddrOffset is always the top 4 bits of normalized address, so revert the modification in commit 0ac06d63 to the original implementation. Fixes: 0ac06d63 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: fuhao --- arch/x86/kernel/cpu/mce/amd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index a72b1a99683a..2e32d64f6e9f 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -686,12 +686,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) /* Remove HiAddrOffset from normalized address, if enabled: */ if (tmp & BIT(0)) { - u64 hi_addr_offset; - - if (hygon_f18h_m4h()) - hi_addr_offset = (tmp & GENMASK_ULL(31, 18)) << 8; - else - hi_addr_offset = (tmp & GENMASK_ULL(31, 20)) << 8; + u64 hi_addr_offset = (tmp & GENMASK_ULL(31, 20)) << 8; if (norm_addr >= hi_addr_offset) { ret_addr -= hi_addr_offset; -- Gitee From 448f6d075dc03040244837ef5bd779018a4f0760 Mon Sep 17 00:00:00 2001 From: fuhao Date: Thu, 1 Feb 2024 15:18:12 +0800 Subject: [PATCH 2/4] EDAC/amd64: Fix intlv_num_chan for Hygon family 18h model 4h Make the modification in commit 0ac06d63 to intlv_num_chan only for Hygon family 18h model 4h. Fixes: 0ac06d63 ("EDAC/amd64: Adjust address translation for Hygon family 18h model 4h") Signed-off-by: fuhao --- arch/x86/kernel/cpu/mce/amd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 2e32d64f6e9f..fc288a102ad3 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -735,10 +735,6 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) switch (intlv_num_chan) { case 0: intlv_num_chan = 0; break; case 1: intlv_num_chan = 1; break; - case 2: - if (hygon_f18h_m4h()) - intlv_num_chan = 2; - break; case 3: intlv_num_chan = 2; break; case 5: intlv_num_chan = 3; break; case 7: intlv_num_chan = 4; break; @@ -747,6 +743,10 @@ 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; -- Gitee From 1b48a446213b4173d9925c5fc75da58197a9ebd5 Mon Sep 17 00:00:00 2001 From: fuhao Date: Thu, 1 Feb 2024 17:23:37 +0800 Subject: [PATCH 3/4] x86/amd_nb: Get DF ID from F5 device for Hygon family 18h model 6h The DF ID should be get from DF F5 device for Hygon family 18h model 6h processor. Fixes: 3e980dd8 ("x86/amd_nb: Add support for Hygon family 18h model 6h") Signed-off-by: fuhao --- arch/x86/kernel/amd_nb.c | 74 +++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index f503af7765a8..bf9d227479f8 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -30,6 +30,7 @@ #define PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1 0x1491 #define PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1 0x14b1 #define PCI_DEVICE_ID_HYGON_18H_M05H_DF_F4 0x14b4 +#define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5 0x14b5 /* Protect the PCI config register pairs used for SMN and DF indirect access. */ static DEFINE_MUTEX(smn_mutex); @@ -45,7 +46,6 @@ static const struct pci_device_id amd_root_ids[] = { {} }; - #define PCI_DEVICE_ID_AMD_CNB17H_F4 0x1704 const struct pci_device_id amd_nb_misc_ids[] = { @@ -256,43 +256,55 @@ u16 hygon_nb_num(void) } EXPORT_SYMBOL_GPL(hygon_nb_num); -static int get_df1_register(struct pci_dev *misc, int offset, u32 *value) +static int get_df_register(struct pci_dev *misc, u8 func, int offset, u32 *value) { - struct pci_dev *df_f1 = NULL; + struct pci_dev *df_func = NULL; u32 device; int err; - switch (boot_cpu_data.x86_model) { - case 0x4: - device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1; - break; - case 0x5: - if (misc->device == PCI_DEVICE_ID_HYGON_18H_M05H_DF_F3) - device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1; - else + if (func == 1) { + switch (boot_cpu_data.x86_model) { + case 0x4: device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1; - break; - case 0x6: - device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1; - break; - default: + break; + case 0x5: + if (misc->device == PCI_DEVICE_ID_HYGON_18H_M05H_DF_F3) + device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1; + else + device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1; + break; + case 0x6: + device = PCI_DEVICE_ID_HYGON_18H_M05H_DF_F1; + break; + default: + return -ENODEV; + } + } else if (func == 5) { + switch (boot_cpu_data.x86_model) { + case 0x6: + device = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5; + break; + default: + return -ENODEV; + } + } else { return -ENODEV; } - while ((df_f1 = pci_get_device(misc->vendor, device, df_f1))) - if (pci_domain_nr(df_f1->bus) == pci_domain_nr(misc->bus) && - df_f1->bus->number == misc->bus->number && - PCI_SLOT(df_f1->devfn) == PCI_SLOT(misc->devfn)) + while ((df_func = pci_get_device(misc->vendor, device, df_func))) + if (pci_domain_nr(df_func->bus) == pci_domain_nr(misc->bus) && + df_func->bus->number == misc->bus->number && + PCI_SLOT(df_func->devfn) == PCI_SLOT(misc->devfn)) break; - if (!df_f1) { - pr_warn("Error getting DF F1 device.\n"); + if (!df_func) { + pr_warn("Error getting DF F%d device.\n", func); return -ENODEV; } - err = pci_read_config_dword(df_f1, offset, value); + err = pci_read_config_dword(df_func, offset, value); if (err) - pr_warn("Error reading DF F1 register.\n"); + pr_warn("Error reading DF F%d register.\n", func); return err; } @@ -302,9 +314,15 @@ int get_df_id(struct pci_dev *misc, u8 *id) u32 value; int ret; - /* F1x200[23:20]: DF ID */ - ret = get_df1_register(misc, 0x200, &value); - *id = (value >> 20) & 0xf; + if (boot_cpu_data.x86_model == 0x6) { + /* F5x180[19:16]: DF ID */ + ret = get_df_register(misc, 5, 0x180, &value); + *id = (value >> 16) & 0xf; + } else { + /* F1x200[23:20]: DF ID */ + ret = get_df_register(misc, 1, 0x200, &value); + *id = (value >> 20) & 0xf; + } return ret; } @@ -316,7 +334,7 @@ static u8 get_socket_num(struct pci_dev *misc) int ret; /* F1x200[7:0]: Which socket is present. */ - ret = get_df1_register(misc, 0x200, &value); + ret = get_df_register(misc, 1, 0x200, &value); return ret ? 0 : hweight8(value & 0xff); } -- Gitee From e58aee777e6ca49ec4ab7683de0ea7a3bbbd66db Mon Sep 17 00:00:00 2001 From: fuhao Date: Thu, 1 Feb 2024 17:34:35 +0800 Subject: [PATCH 4/4] EDAC/amd64: Adjust UMC channel for Hygon family 18h model 6h Hygon family 18h model 6h has 2 cs mapped to 1 umc, so adjust for it. Fixes: 6cf6141e ("EDAC/amd64: Add support for Hygon family 18h model 6h") Signed-off-by: fuhao --- drivers/edac/amd64_edac.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index f6026581f922..3b8c4b1e1961 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2733,6 +2733,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; mci = edac_mc_find(node_id); if (!mci) @@ -2763,7 +2764,12 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; - if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { + if (hygon_f18h_m4h() && boot_cpu_data.x86_model == 0x6) + umc = err.channel << 1; + 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; } -- Gitee