EDAC/amd64: Add support for Hygon family 18h model 4h

Hygon family 18h model 4h processor has the same F0/F6 device IDs
as F17h_M30h.

Add support to determine which DDR memory types it supports, but
determine syndrome sizes from different bits of the DRAM ECC control
reg.

Signed-off-by: Pu Wen <puwen@hygon.cn>
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: Bin Lai <robinlai@tencent.com>
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: caelli <caelli@tencent.com>
Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
Pu Wen 2023-06-08 12:38:28 +08:00 committed by Jianping Liu
parent 98cb40237c
commit 36d1aba7a1
1 changed files with 74 additions and 14 deletions

View File

@ -101,6 +101,17 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
return err; return err;
} }
static u32 get_umc_base_f18h_m4h(u16 node, u8 channel)
{
struct pci_dev *f3 = node_to_amd_nb(node)->misc;
u8 df_id;
get_df_id(f3, &df_id);
df_id -= 4;
return get_umc_base(channel) + (0x80000000 + (0x10000000 * df_id));
}
/* /*
* Select DCT to which PCI cfg accesses are routed * Select DCT to which PCI cfg accesses are routed
*/ */
@ -866,7 +877,10 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
u32 i, tmp, umc_base; u32 i, tmp, umc_base;
for_each_umc(i) { for_each_umc(i) {
umc_base = get_umc_base(i); if (hygon_f18h_m4h())
umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i);
else
umc_base = get_umc_base(i);
umc = &pvt->umc[i]; umc = &pvt->umc[i];
edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg); edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg);
@ -986,11 +1000,17 @@ static void read_umc_base_mask(struct amd64_pvt *pvt)
u32 mask_reg, mask_reg_sec; u32 mask_reg, mask_reg_sec;
u32 *base, *base_sec; u32 *base, *base_sec;
u32 *mask, *mask_sec; u32 *mask, *mask_sec;
u32 umc_base;
int cs, umc; int cs, umc;
for_each_umc(umc) { for_each_umc(umc) {
umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR; if (hygon_f18h_m4h())
umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC; umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, umc);
else
umc_base = get_umc_base(umc);
umc_base_reg = umc_base + UMCCH_BASE_ADDR;
umc_base_reg_sec = umc_base + UMCCH_BASE_ADDR_SEC;
for_each_chip_select(cs, umc, pvt) { for_each_chip_select(cs, umc, pvt) {
base = &pvt->csels[umc].csbases[cs]; base = &pvt->csels[umc].csbases[cs];
@ -1008,8 +1028,8 @@ static void read_umc_base_mask(struct amd64_pvt *pvt)
umc, cs, *base_sec, base_reg_sec); umc, cs, *base_sec, base_reg_sec);
} }
umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK; umc_mask_reg = umc_base + UMCCH_ADDR_MASK;
umc_mask_reg_sec = get_umc_base(umc) + get_umc_reg(UMCCH_ADDR_MASK_SEC); umc_mask_reg_sec = umc_base + get_umc_reg(UMCCH_ADDR_MASK_SEC);
for_each_chip_select_mask(cs, umc, pvt) { for_each_chip_select_mask(cs, umc, pvt) {
mask = &pvt->csels[umc].csmasks[cs]; mask = &pvt->csels[umc].csmasks[cs];
@ -1097,7 +1117,8 @@ static void determine_memory_type_df(struct amd64_pvt *pvt)
* Check if the system supports the "DDR Type" field in UMC Config * Check if the system supports the "DDR Type" field in UMC Config
* and has DDR5 DIMMs in use. * and has DDR5 DIMMs in use.
*/ */
if (fam_type->flags.zn_regs_v2 && ((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) { if ((fam_type->flags.zn_regs_v2 || hygon_f18h_m4h()) &&
((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) {
if (umc->dimm_cfg & BIT(5)) if (umc->dimm_cfg & BIT(5))
umc->dram_type = MEM_LRDDR5; umc->dram_type = MEM_LRDDR5;
else if (umc->dimm_cfg & BIT(4)) else if (umc->dimm_cfg & BIT(4))
@ -2833,6 +2854,14 @@ static void free_mc_sibling_devs(struct amd64_pvt *pvt)
} }
} }
static void determine_ecc_sym_sz_f18h_m4h(struct amd64_pvt *pvt, int channel)
{
if (pvt->umc[channel].ecc_ctrl & BIT(8))
pvt->ecc_sym_sz = 16;
else if (pvt->umc[channel].ecc_ctrl & BIT(7))
pvt->ecc_sym_sz = 8;
}
static void determine_ecc_sym_sz(struct amd64_pvt *pvt) static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
{ {
pvt->ecc_sym_sz = 4; pvt->ecc_sym_sz = 4;
@ -2843,6 +2872,14 @@ static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
for_each_umc(i) { for_each_umc(i) {
/* Check enabled channels only: */ /* Check enabled channels only: */
if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
boot_cpu_data.x86 == 0x18 &&
boot_cpu_data.x86_model == 0x4 &&
(pvt->umc[i].umc_cfg & GENMASK(2, 0)) == 0x1) {
determine_ecc_sym_sz_f18h_m4h(pvt, i);
return;
}
if (pvt->umc[i].ecc_ctrl & BIT(9)) { if (pvt->umc[i].ecc_ctrl & BIT(9)) {
pvt->ecc_sym_sz = 16; pvt->ecc_sym_sz = 16;
return; return;
@ -2877,8 +2914,11 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt)
/* Read registers from each UMC */ /* Read registers from each UMC */
for_each_umc(i) { for_each_umc(i) {
if (hygon_f18h_m4h())
umc_base = get_umc_base_f18h_m4h(pvt->mc_node_id, i);
else
umc_base = get_umc_base(i);
umc_base = get_umc_base(i);
umc = &pvt->umc[i]; umc = &pvt->umc[i];
amd_smn_read(nid, umc_base + get_umc_reg(UMCCH_DIMM_CFG), &umc->dimm_cfg); amd_smn_read(nid, umc_base + get_umc_reg(UMCCH_DIMM_CFG), &umc->dimm_cfg);
@ -3485,13 +3525,21 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
pvt->ops = &family_types[F17_M70H_CPUS].ops; pvt->ops = &family_types[F17_M70H_CPUS].ops;
break; break;
} }
/* fall through */
case 0x18:
fam_type = &family_types[F17_CPUS]; fam_type = &family_types[F17_CPUS];
pvt->ops = &family_types[F17_CPUS].ops; pvt->ops = &family_types[F17_CPUS].ops;
break;
if (pvt->fam == 0x18) case 0x18:
family_types[F17_CPUS].ctl_name = "F18h"; if (pvt->model == 0x4) {
fam_type = &family_types[F17_M30H_CPUS];
pvt->ops = &family_types[F17_M30H_CPUS].ops;
family_types[F17_M30H_CPUS].max_mcs = 3;
family_types[F17_M30H_CPUS].ctl_name = "F18h_M04h";
break;
}
fam_type = &family_types[F17_CPUS];
pvt->ops = &family_types[F17_CPUS].ops;
family_types[F17_CPUS].ctl_name = "F18h";
break; break;
case 0x19: case 0x19:
@ -3771,6 +3819,7 @@ static int __init amd64_edac_init(void)
{ {
const char *owner; const char *owner;
int err = -ENODEV; int err = -ENODEV;
u16 instance_num;
int i; int i;
owner = edac_get_owner(); owner = edac_get_owner();
@ -3785,8 +3834,13 @@ static int __init amd64_edac_init(void)
opstate_init(); opstate_init();
if (hygon_f18h_m4h())
instance_num = hygon_nb_num();
else
instance_num = amd_nb_num();
err = -ENOMEM; err = -ENOMEM;
ecc_stngs = kcalloc(amd_nb_num(), sizeof(ecc_stngs[0]), GFP_KERNEL); ecc_stngs = kcalloc(instance_num, sizeof(ecc_stngs[0]), GFP_KERNEL);
if (!ecc_stngs) if (!ecc_stngs)
goto err_free; goto err_free;
@ -3794,7 +3848,7 @@ static int __init amd64_edac_init(void)
if (!msrs) if (!msrs)
goto err_free; goto err_free;
for (i = 0; i < amd_nb_num(); i++) { for (i = 0; i < instance_num; i++) {
err = probe_one_instance(i); err = probe_one_instance(i);
if (err) { if (err) {
/* unwind properly */ /* unwind properly */
@ -3844,6 +3898,7 @@ err_free:
static void __exit amd64_edac_exit(void) static void __exit amd64_edac_exit(void)
{ {
u16 instance_num;
int i; int i;
if (pci_ctl) if (pci_ctl)
@ -3857,7 +3912,12 @@ static void __exit amd64_edac_exit(void)
else else
amd_unregister_ecc_decoder(decode_bus_error); amd_unregister_ecc_decoder(decode_bus_error);
for (i = 0; i < amd_nb_num(); i++) if (hygon_f18h_m4h())
instance_num = hygon_nb_num();
else
instance_num = amd_nb_num();
for (i = 0; i < instance_num; i++)
remove_one_instance(i); remove_one_instance(i);
kfree(ecc_stngs); kfree(ecc_stngs);