Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
02e57d5
pinctrl: Add device HID for Hygon GPIO controller
liaoxuan123 Jan 10, 2025
8dc8801
Add set_guest_pat_wb parameter for non-passthrough application scenarios
liaoxuan123 Jan 14, 2025
42b9ec6
x86/amd_nb: Fix northbridge init warning in guest for Hygon family 18…
liaoxuan123 Jan 14, 2025
3e9c72d
EDAC/amd64: Fix the calculation of cs id for Hygon family 18h model 4h
liaoxuan123 Jan 14, 2025
054d5a3
EDAC/amd64: Use u16 for some umc variables for Hygon family 18h model 4h
liaoxuan123 Jan 14, 2025
e7aa049
EDAC/amd64: Fix the calculation of instance id for Hygon family 18h m…
liaoxuan123 Jan 14, 2025
3290b2d
EDAC/amd64: Get intlv_num_dies from F0x60 for Hygon family 18h model 6h
liaoxuan123 Jan 14, 2025
7ad8c82
EDAC/mce_amd: Add LS and IF mce types for Hygon family 18h model 7h
liaoxuan123 Jan 14, 2025
6195d54
x86/amd_nb: Get DF ID from F5 device for Hygon family 18h model 7h
liaoxuan123 Jan 14, 2025
ce14052
iommu/hygon: Add support for Hygon family 18h model 10h IOAPIC
liaoxuan123 Jan 14, 2025
a8f1ab7
x86/amd_nb: Add helper function to identify Hygon family 18h model 10h
liaoxuan123 Jan 14, 2025
94e8c1c
EDAC/amd64: Adjust address translation for Hygon family 18h model 10h
liaoxuan123 Jan 14, 2025
c376a43
EDAC/amd64: Check if umc channel is enabled for Hygon family 18h mode…
liaoxuan123 Jan 14, 2025
6a39d22
EDAC/amd64: Get correct memory type for Hygon family 18h model 10h
liaoxuan123 Jan 14, 2025
8804da9
EDAC/amd64: Get instance id for Hygon family 18h model 10h
liaoxuan123 Jan 14, 2025
defd20a
x86/amd_nb: Add support for Hygon family 18h model 8h
liaoxuan123 Jan 14, 2025
e06110e
EDAC/amd64: Add support for Hygon family 18h model 8h
liaoxuan123 Jan 14, 2025
fc26d71
perf/x86/amd/core: Fix performance monitor for Hygon family 18h proce…
liaoxuan123 Jan 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arch/x86/events/amd/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ static u64 amd_pmu_event_map(int hw_event)
if (cpu_feature_enabled(X86_FEATURE_ZEN1))
return amd_zen1_perfmon_event_map[hw_event];

if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
return amd_zen1_perfmon_event_map[hw_event];

return amd_perfmon_event_map[hw_event];
}

Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/amd_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,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);

Expand Down Expand Up @@ -127,6 +128,7 @@ static inline struct amd_northbridge *node_to_amd_nb(int node)
#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

Expand Down
28 changes: 21 additions & 7 deletions arch/x86/kernel/amd_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,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;
Expand All @@ -285,17 +299,15 @@ static int get_df_register(struct pci_dev *misc, u8 func, int offset, u32 *value
else
device = PCI_DEVICE_ID_HYGON_18H_M04H_DF_F1;
break;
case 0x6:
case 0x7:
case 0x6 ... 0x8:
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:
case 0x7:
case 0x6 ... 0x8:
device = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5;
break;
default:
Expand Down Expand Up @@ -328,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 <= 0xf) {
/* F5x180[19:16]: DF ID */
ret = get_df_register(misc, 5, 0x180, &value);
*id = (value >> 16) & 0xf;
Expand Down Expand Up @@ -466,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;
}

Expand Down
27 changes: 27 additions & 0 deletions arch/x86/kvm/svm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@ module_param(intercept_smi, bool, 0444);
bool vnmi = true;
module_param(vnmi, bool, 0444);

/*
* 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 = false;
module_param(set_guest_pat_wb, int, 0444);

static bool svm_gp_erratum_intercept = true;

static u8 rsm_ins_bytes[] = "\x0f\xaa";
Expand Down Expand Up @@ -1256,6 +1267,16 @@ static inline void init_vmcb_after_set_cpuid(struct kvm_vcpu *vcpu)
}
}

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 kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
Expand Down Expand Up @@ -1357,6 +1378,8 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
svm_clr_intercept(svm, INTERCEPT_CR3_READ);
svm_clr_intercept(svm, INTERCEPT_CR3_WRITE);
save->g_pat = vcpu->arch.pat;
if (set_guest_pat_wb)
svm_set_guest_pat(svm, &save->g_pat);
save->cr3 = 0;
}
svm->current_vmcb->asid_generation = 0;
Expand Down Expand Up @@ -3068,6 +3091,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
svm->vmcb01.ptr->save.g_pat = data;
if (is_guest_mode(vcpu))
nested_vmcb02_compute_g_pat(svm);
if (npt_enabled && set_guest_pat_wb) {
svm_set_guest_pat(svm, &svm->vmcb01.ptr->save.g_pat);
vcpu->arch.pat = svm->vmcb01.ptr->save.g_pat;
}
vmcb_mark_dirty(svm->vmcb, VMCB_NPT);
break;
case MSR_IA32_SPEC_CTRL:
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kvm/svm/svm.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#define IOPM_SIZE PAGE_SIZE * 3
#define MSRPM_SIZE PAGE_SIZE * 2

#define GUEST_PAT_WB_ATTR 0x0606060606060606

#define MAX_DIRECT_ACCESS_MSRS 48
#define MSRPM_OFFSETS 32
extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
Expand Down
70 changes: 59 additions & 11 deletions drivers/edac/amd64_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,12 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
{
u64 dram_base_addr, dram_limit_addr, dram_hole_base;

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;
Expand All @@ -1149,7 +1154,7 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
ctx.inst_id = umc;

/* Read DramOffset, check if base 1 is used. */
if (hygon_f18h_m4h() &&
if ((hygon_f18h_m4h() || hygon_f18h_m10h()) &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider creating a helper function to abstract repeated Hygon variant checks.

Consider abstracting the repeated Hygon variant checks into helper functions to simplify the control flow. For example, you can create an inline helper to cover both conditions:

static inline bool is_hygon_variant(void) {
    return hygon_f18h_m4h() || hygon_f18h_m10h();
}

Then replace:

if ((hygon_f18h_m4h() || hygon_f18h_m10h()) && 
    df_indirect_read_instance(nid, 0, 0x214, umc, &ctx.tmp))
    goto out_err;

with:

if (is_hygon_variant() && 
    df_indirect_read_instance(nid, 0, 0x214, umc, &ctx.tmp))
    goto out_err;

Similarly, where you check both positive and negative conditions related to Hygon functions, reuse the helper:

if (!is_hygon_variant())
    intlv_num_sockets = (ctx.tmp >> 8) & 0x1;

This isolates the configuration‐specific logic from the main flow and minimizes duplicated branches while preserving functionality.

df_indirect_read_instance(nid, 0, 0x214, umc, &ctx.tmp))
goto out_err;
else if (df_indirect_read_instance(nid, 0, 0x1B4, umc, &ctx.tmp))
Expand Down Expand Up @@ -1177,7 +1182,7 @@ static 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 = (ctx.tmp >> 2) & 0x3;
lgcy_mmio_hole_en = ctx.tmp & BIT(1);
intlv_num_chan = (ctx.tmp >> 4) & 0xF;
Expand All @@ -1195,13 +1200,20 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
if (df_indirect_read_instance(nid, 0, 0x114 + (8 * base), umc, &ctx.tmp))
goto out_err;

if (!hygon_f18h_m4h())
if (!hygon_f18h_m4h() && !hygon_f18h_m10h())
intlv_num_sockets = (ctx.tmp >> 8) & 0x1;
intlv_num_dies = (ctx.tmp >> 10) & 0x3;
dram_limit_addr = ((ctx.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 (df_indirect_read_instance(nid, 0, 0x60, umc, &ctx.tmp))
goto out_err;
intlv_num_dies = ctx.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;
Expand Down Expand Up @@ -1245,7 +1257,12 @@ static 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].
Expand All @@ -1256,7 +1273,7 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
if (df_indirect_read_instance(nid, 0, 0x50, umc, &ctx.tmp))
goto out_err;

if (hygon_f18h_m4h())
if (hygon_f18h_m4h() || hygon_f18h_m10h())
cs_fabric_id = (ctx.tmp >> 8) & 0x7FF;
else
cs_fabric_id = (ctx.tmp >> 8) & 0xFF;
Expand All @@ -1282,12 +1299,14 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
if (hygon_f18h_m4h()) {
die_id_shift = (ctx.tmp >> 12) & 0xF;
die_id_mask = ctx.tmp & 0x7FF;
cs_id |= (((cs_fabric_id & die_id_mask) >> die_id_shift) - 4) <<
die_id_bit;
} else {
die_id_shift = (ctx.tmp >> 24) & 0xF;
die_id_mask = (ctx.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. */
Expand Down Expand Up @@ -1637,12 +1656,29 @@ static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
}
}

static bool hygon_umc_channel_enabled(struct amd64_pvt *pvt, int channel)
{
u32 enable;

if (hygon_f18h_m10h()) {
__df_indirect_read(pvt->mc_node_id, 1, 0x32c, 0xc, &enable);
if ((enable & BIT(channel)))
return true;
return false;
}

return true;
}

static void umc_dump_misc_regs(struct amd64_pvt *pvt)
{
struct amd64_umc *umc;
u32 i, tmp, umc_base;

for_each_umc(i) {
if (!hygon_umc_channel_enabled(pvt, i))
continue;

if (hygon_f18h_m4h())
umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i);
else
Expand Down Expand Up @@ -1759,6 +1795,9 @@ static void umc_read_base_mask(struct amd64_pvt *pvt)
int cs, umc;

for_each_umc(umc) {
if (!hygon_umc_channel_enabled(pvt, umc))
continue;

if (hygon_f18h_m4h())
umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, umc);
else
Expand Down Expand Up @@ -1867,7 +1906,9 @@ static void umc_determine_memory_type(struct amd64_pvt *pvt)
* Check if the system supports the "DDR Type" field in UMC Config
* and has DDR5 DIMMs in use.
*/
if ((pvt->flags.zn_regs_v2 || hygon_f18h_m4h()) &&
if ((pvt->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;
Expand Down Expand Up @@ -3148,8 +3189,9 @@ static void decode_umc_error(int node_id, struct mce *m)

pvt->ops->get_err_info(m, &err);

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;

Expand Down Expand Up @@ -3227,6 +3269,9 @@ static void umc_read_mc_regs(struct amd64_pvt *pvt)

/* Read registers from each UMC */
for_each_umc(i) {
if (!hygon_umc_channel_enabled(pvt, i))
continue;

if (hygon_f18h_m4h())
umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i);
else
Expand Down Expand Up @@ -4164,6 +4209,9 @@ static int per_family_init(struct amd64_pvt *pvt)
} else if (pvt->model == 0x7) {
pvt->ctl_name = "F18h_M07h";
break;
} else if (pvt->model == 0x8) {
pvt->ctl_name = "F18h_M08h";
break;
} else if (pvt->model == 0x10) {
pvt->ctl_name = "F18h_M10h";
break;
Expand Down
Loading
Loading