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:
parent
98cb40237c
commit
36d1aba7a1
|
@ -101,6 +101,17 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
|
|||
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
|
||||
*/
|
||||
|
@ -866,7 +877,10 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
|
|||
u32 i, tmp, umc_base;
|
||||
|
||||
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];
|
||||
|
||||
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 *base, *base_sec;
|
||||
u32 *mask, *mask_sec;
|
||||
u32 umc_base;
|
||||
int cs, umc;
|
||||
|
||||
for_each_umc(umc) {
|
||||
umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR;
|
||||
umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC;
|
||||
if (hygon_f18h_m4h())
|
||||
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) {
|
||||
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_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK;
|
||||
umc_mask_reg_sec = get_umc_base(umc) + get_umc_reg(UMCCH_ADDR_MASK_SEC);
|
||||
umc_mask_reg = umc_base + UMCCH_ADDR_MASK;
|
||||
umc_mask_reg_sec = umc_base + get_umc_reg(UMCCH_ADDR_MASK_SEC);
|
||||
|
||||
for_each_chip_select_mask(cs, umc, pvt) {
|
||||
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
|
||||
* 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))
|
||||
umc->dram_type = MEM_LRDDR5;
|
||||
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)
|
||||
{
|
||||
pvt->ecc_sym_sz = 4;
|
||||
|
@ -2843,6 +2872,14 @@ static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
|
|||
for_each_umc(i) {
|
||||
/* Check enabled channels only: */
|
||||
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)) {
|
||||
pvt->ecc_sym_sz = 16;
|
||||
return;
|
||||
|
@ -2877,8 +2914,11 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt)
|
|||
|
||||
/* Read registers from each UMC */
|
||||
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];
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 0x18:
|
||||
fam_type = &family_types[F17_CPUS];
|
||||
pvt->ops = &family_types[F17_CPUS].ops;
|
||||
break;
|
||||
|
||||
if (pvt->fam == 0x18)
|
||||
family_types[F17_CPUS].ctl_name = "F18h";
|
||||
case 0x18:
|
||||
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;
|
||||
|
||||
case 0x19:
|
||||
|
@ -3771,6 +3819,7 @@ static int __init amd64_edac_init(void)
|
|||
{
|
||||
const char *owner;
|
||||
int err = -ENODEV;
|
||||
u16 instance_num;
|
||||
int i;
|
||||
|
||||
owner = edac_get_owner();
|
||||
|
@ -3785,8 +3834,13 @@ static int __init amd64_edac_init(void)
|
|||
|
||||
opstate_init();
|
||||
|
||||
if (hygon_f18h_m4h())
|
||||
instance_num = hygon_nb_num();
|
||||
else
|
||||
instance_num = amd_nb_num();
|
||||
|
||||
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)
|
||||
goto err_free;
|
||||
|
||||
|
@ -3794,7 +3848,7 @@ static int __init amd64_edac_init(void)
|
|||
if (!msrs)
|
||||
goto err_free;
|
||||
|
||||
for (i = 0; i < amd_nb_num(); i++) {
|
||||
for (i = 0; i < instance_num; i++) {
|
||||
err = probe_one_instance(i);
|
||||
if (err) {
|
||||
/* unwind properly */
|
||||
|
@ -3844,6 +3898,7 @@ err_free:
|
|||
|
||||
static void __exit amd64_edac_exit(void)
|
||||
{
|
||||
u16 instance_num;
|
||||
int i;
|
||||
|
||||
if (pci_ctl)
|
||||
|
@ -3857,7 +3912,12 @@ static void __exit amd64_edac_exit(void)
|
|||
else
|
||||
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);
|
||||
|
||||
kfree(ecc_stngs);
|
||||
|
|
Loading…
Reference in New Issue