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;
|
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);
|
||||||
|
|
Loading…
Reference in New Issue