diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index b6e5db1069e9bb3954ef03d47d8a7e2756b999ba..e48a7e2ba40ca5620bef62263a75775e9f86393f 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 a459ae8b9f7c1d63affad5906e66ed0102fc194e..93864362937fa62b3fa51a21eae3ea64fe48423e 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -260,6 +260,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; @@ -326,7 +340,8 @@ int get_df_id(struct pci_dev *misc, u8 *id) u32 value; int ret; - if (boot_cpu_data.x86_model == 0x6) { + if (boot_cpu_data.x86_model >= 0x6 && + boot_cpu_data.x86_model <= 0x7) { /* F5x180[19:16]: DF ID */ ret = get_df_register(misc, 5, 0x180, &value); *id = (value >> 16) & 0xf; @@ -464,8 +479,9 @@ static int northbridge_init_f18h_m4h(const struct pci_device_id *root_ids, amd_northbridges.nb = NULL; ret: - pr_err("Hygon Fam%xh Model%xh northbridge init failed(%d)!\n", - boot_cpu_data.x86, boot_cpu_data.x86_model, err); + if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) + pr_err("Hygon Fam%xh Model%xh northbridge init failed(%d)!\n", + boot_cpu_data.x86, boot_cpu_data.x86_model, err); return err; } diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 9f914bf80180bfd69cf9dfc1b0cac97541c86834..3da9c951ac31badfe0375091e8cc3193e890e218 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -84,16 +84,11 @@ static void hygon_get_topology(struct cpuinfo_x86 *c) if (smp_num_siblings > 1) c->x86_max_cores /= smp_num_siblings; - switch (c->x86_model) { - case 0x0 ... 0x3: - if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) - break; + if (c->x86 == 0x18 && c->x86_model < 0x4 && + !boot_cpu_has(X86_FEATURE_HYPERVISOR)) { /* Socket ID is ApicId[6] for these processors. */ c->phys_proc_id = c->apicid >> APICID_SOCKET_ID_BIT; - break; - case 0x4: - case 0x5: - case 0x6: + } else { /* * In case leaf 0xB is available, use it to derive * topology information. @@ -103,9 +98,6 @@ static void hygon_get_topology(struct cpuinfo_x86 *c) c->x86_coreid_bits = get_count_order(c->x86_max_cores); __max_die_per_package = nodes_per_socket; - break; - default: - break; } cacheinfo_hygon_init_llc_id(c, cpu); diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 63cc38577508aadb7d856cb1d6b5a4ff6c0aa535..c681f9266777ae64e481da4e3f6cb260de950c22 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -705,7 +705,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; @@ -714,7 +719,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)) @@ -742,7 +747,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; @@ -760,13 +765,20 @@ 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) || + 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; @@ -811,7 +823,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]. @@ -822,7 +839,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; @@ -848,12 +865,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. */ diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c479ea21a5b432e30cb6bcc9b1536f0b6e56d12b..4e2502855b26863642fd70bd871fcb25751b0dd8 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -89,6 +89,8 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); #define TSC_RATIO_MIN 0x0000000000000001ULL #define TSC_RATIO_MAX 0x000000ffffffffffULL +#define GUEST_PAT_WB_ATTR 0x0606060606060606 + #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF) /* @@ -382,6 +384,17 @@ module_param(sev, int, 0444); static bool __read_mostly dump_invalid_vmcb = 0; module_param(dump_invalid_vmcb, bool, 0644); +/* + * Allow set guest PAT to WB in some non-passthrough + * application scenarios to enhance performance. + * + * Add kernel parameter set_guest_pat_wb(default 0): + * 1 - set guest PAT to WB + * 0 - keep guest PAT to the kernel default value + */ +static int set_guest_pat_wb; +module_param(set_guest_pat_wb, int, 0444); + static u8 rsm_ins_bytes[] = "\x0f\xaa"; static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); @@ -1536,6 +1549,16 @@ static void avic_init_vmcb(struct vcpu_svm *svm) vmcb->control.int_ctl |= AVIC_ENABLE_MASK; } +static void svm_set_guest_pat(struct vcpu_svm *svm, u64 *g_pat) +{ + struct kvm_vcpu *vcpu = &svm->vcpu; + + if (!kvm_arch_has_assigned_device(vcpu->kvm)) + *g_pat = GUEST_PAT_WB_ATTR; + else + *g_pat = vcpu->arch.pat; +} + static void init_vmcb(struct vcpu_svm *svm) { struct vmcb_control_area *control = &svm->vmcb->control; @@ -1648,6 +1671,8 @@ static void init_vmcb(struct vcpu_svm *svm) clr_cr_intercept(svm, INTERCEPT_CR3_READ); clr_cr_intercept(svm, INTERCEPT_CR3_WRITE); save->g_pat = svm->vcpu.arch.pat; + if (set_guest_pat_wb) + svm_set_guest_pat(svm, &save->g_pat); save->cr3 = 0; save->cr4 = 0; } @@ -4335,6 +4360,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) return 1; vcpu->arch.pat = data; svm->vmcb->save.g_pat = data; + if (npt_enabled && set_guest_pat_wb) { + svm_set_guest_pat(svm, &svm->vmcb->save.g_pat); + vcpu->arch.pat = svm->vmcb->save.g_pat; + } mark_dirty(svm->vmcb, VMCB_NPT); break; case MSR_IA32_SPEC_CTRL: diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 55296297171231547c2516d70048b8638609347b..94e5e5384a04de6f132538039eb3c3488ef5c477 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -871,12 +871,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 @@ -1004,6 +1021,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 @@ -1117,7 +1137,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; @@ -2792,8 +2814,9 @@ 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; + 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; @@ -2941,6 +2964,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 @@ -3391,6 +3417,9 @@ static bool ecc_enabled(struct amd64_pvt *pvt) for_each_umc(i) { umc = &pvt->umc[i]; + if (!hygon_umc_channel_enabled(nid, i)) + continue; + /* Only check enabled UMCs. */ if (!(umc->sdp_ctrl & UMC_SDP_INIT)) continue; diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 298e2a7dd3d1ee6ada4afbb43b6b0c461a41e108..ac401b1dfacd1c4f23a004b6722b084287dad1e0 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -202,6 +202,33 @@ static const char * const smca_ls2_mce_desc[] = { "A parity error was detected in an STLF, SCB EMEM entry or SRB store data by any access", }; +/* Hygon Model7h Scalable MCA LS error strings */ +static const char * const smca_ls_mce_hygon_desc[] = { + "Load queue parity error", + "Store queue parity error", + "Miss address buffer payload parity error", + "Level 1 TLB parity error", + "DC Tag error type 5", + "DC Tag error type 6", + "DC Tag error type 1", + "Internal error type 1", + "Internal error type 2", + "System Read Data Error 0", + "System Read Data Error 1", + "System Read Data Error 2", + "System Read Data Error 3", + "DC Tag error type 2", + "DC Data error type 1 and poison consumption", + "DC Data error type 2", + "DC Data error type 3", + "DC Tag error type 4", + "Level 2 TLB parity error", + "PDC parity error", + "DC Tag error type 3", + "DC Tag error type 5", + "L2 Fill Data error", +}; + static const char * const smca_if_mce_desc[] = { "Op Cache Microtag Probe Port Parity Error", "IC Microtag or Full Tag Multi-hit Error", @@ -219,6 +246,26 @@ static const char * const smca_if_mce_desc[] = { "System Read Data Error", }; +/* Hygon Model7h Scalable MCA IF error strings */ +static const char * const smca_if_mce_hygon_desc[] = { + "Op Cache Microtag Probe Port Parity Error", + "IC Microtag or Full Tag Multi-hit Error", + "IC Full Tag Parity Error", + "IC Data Array Parity Error", + "Decoupling Queue PhysAddr Parity Error", + "L0 ITLB Parity Error", + "L1 ITLB Parity Error", + "L2 ITLB Parity Error", + "BPQ 0 Snoop Parity Error", + "BPQ 1 Snoop Parity Error", + "BPQ 2 Snoop Parity Error", + "BPQ 3 Snoop Parity Error", + "L1 BTB Multi-Match Error", + "L2 BTB Multi-Match Error", + "L2 Cache Response Poison Error", + "System Read Data Error", +}; + static const char * const smca_l2_mce_desc[] = { "L2M Tag Multiple-Way-Hit error", "L2M Tag or State Array ECC Error", @@ -1445,6 +1492,16 @@ static int __init mce_amd_init(void) out: pr_info("MCE: In-kernel MCE decoding enabled.\n"); + if (c->x86_vendor == X86_VENDOR_HYGON && + c->x86_model >= 0x7 && c->x86_model <= 0xf) { + smca_mce_descs[SMCA_LS].descs = smca_ls_mce_hygon_desc; + smca_mce_descs[SMCA_LS].num_descs = ARRAY_SIZE(smca_ls_mce_hygon_desc); + smca_mce_descs[SMCA_IF].descs = smca_if_mce_hygon_desc; + smca_mce_descs[SMCA_IF].num_descs = ARRAY_SIZE(smca_if_mce_hygon_desc); + pr_info("MCE: Hygon Fam%xh Model%xh smca mce descs setup.\n", + c->x86, c->x86_model); + } + mce_register_decode_chain(&amd_mce_dec_nb); return 0; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 77835053015b76e494ad68a689f65b92095df22b..7092df1002d856c3d0df900e0acb10757ee95017 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2477,7 +2477,7 @@ static bool __init check_ioapic_information(void) (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON && boot_cpu_data.x86 == 0x18 && boot_cpu_data.x86_model >= 0x4 && - boot_cpu_data.x86_model <= 0xf && + boot_cpu_data.x86_model <= 0x10 && devid == IOAPIC_SB_DEVID_FAM18H_M4H)) { has_sb_ioapic = true; ret = true; diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 887dc57704402376cfad3040432700d27d006771..3e1bfe460ea11ebe9926007056791d61f84069bd 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -996,6 +996,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { { "AMD0030", 0 }, { "AMDI0030", 0}, { "AMDI0031", 0}, + { "HYGO0030", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match);