Commit 55b01665 authored by Pu Wen's avatar Pu Wen
Browse files

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

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7DX6V


CVE: NA

---------------------------

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: default avatarPu Wen <puwen@hygon.cn>
parent ce8672f5
Loading
Loading
Loading
Loading
+74 −14
Original line number Diff line number Diff line
@@ -98,6 +98,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
 */
@@ -1064,6 +1075,9 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
	u32 i, tmp, umc_base;

	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 = &pvt->umc[i];

@@ -1184,11 +1198,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];
@@ -1206,8 +1226,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];
@@ -1295,7 +1315,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))
@@ -3031,6 +3052,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;
@@ -3041,6 +3070,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;
@@ -3075,8 +3112,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 = &pvt->umc[i];

		amd_smn_read(nid, umc_base + get_umc_reg(UMCCH_DIMM_CFG), &umc->dimm_cfg);
@@ -3686,12 +3726,20 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
			pvt->ops = &family_types[F17_M70H_CPUS].ops;
			break;
		}
		fallthrough;
	case 0x18:
		fam_type	= &family_types[F17_CPUS];
		pvt->ops	= &family_types[F17_CPUS].ops;
		break;

		if (pvt->fam == 0x18)
	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;

@@ -3970,6 +4018,7 @@ static int __init amd64_edac_init(void)
{
	const char *owner;
	int err = -ENODEV;
	u16 instance_num;
	int i;

	owner = edac_get_owner();
@@ -3984,8 +4033,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;

@@ -3993,7 +4047,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 */
@@ -4040,6 +4094,7 @@ static int __init amd64_edac_init(void)

static void __exit amd64_edac_exit(void)
{
	u16 instance_num;
	int i;

	if (pci_ctl)
@@ -4051,7 +4106,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);