Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad6a32e9 authored by Borislav Petkov's avatar Borislav Petkov
Browse files

amd64_edac: Sanitize syndrome extraction



Remove the two syndrome extraction macros and add a single function
which does the same thing but with proper typechecking. While at it,
make sure to cache ECC syndrome size and dump it in debug output.

Signed-off-by: default avatarBorislav Petkov <borislav.petkov@amd.com>
parent 9fe6206f
Loading
Loading
Loading
Loading
+50 −33
Original line number Diff line number Diff line
@@ -796,6 +796,11 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)

static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);

static u16 extract_syndrome(struct err_regs *err)
{
	return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
}

static void amd64_cpu_display_info(struct amd64_pvt *pvt)
{
	if (boot_cpu_data.x86 == 0x11)
@@ -888,6 +893,9 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
		return;
	}

	amd64_printk(KERN_INFO, "using %s syndromes.\n",
		     ((pvt->syn_type == 8) ? "x8" : "x4"));

	/* Only if NOT ganged does dclr1 have valid info */
	if (!dct_ganging_enabled(pvt))
		amd64_dump_dramcfg_low(pvt->dclr1, 1);
@@ -1101,20 +1109,17 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
}

static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
					struct err_regs *info,
					u64 sys_addr)
				    struct err_regs *err_info, u64 sys_addr)
{
	struct mem_ctl_info *src_mci;
	unsigned short syndrome;
	int channel, csrow;
	u32 page, offset;
	u16 syndrome;

	/* Extract the syndrome parts and form a 16-bit syndrome */
	syndrome  = HIGH_SYNDROME(info->nbsl) << 8;
	syndrome |= LOW_SYNDROME(info->nbsh);
	syndrome = extract_syndrome(err_info);

	/* CHIPKILL enabled */
	if (info->nbcfg & K8_NBCFG_CHIPKILL) {
	if (err_info->nbcfg & K8_NBCFG_CHIPKILL) {
		channel = get_channel_from_ecc_syndrome(mci, syndrome);
		if (channel < 0) {
			/*
@@ -1123,8 +1128,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
			 * as suspect.
			 */
			amd64_mc_printk(mci, KERN_WARNING,
				       "unknown syndrome 0x%x - possible error "
				       "reporting race\n", syndrome);
					"unknown syndrome 0x%04x - possible "
					"error reporting race\n", syndrome);
			edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
			return;
		}
@@ -1654,13 +1659,13 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
 * (MCX_ADDR).
 */
static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
				     struct err_regs *info,
				     struct err_regs *err_info,
				     u64 sys_addr)
{
	struct amd64_pvt *pvt = mci->pvt_info;
	u32 page, offset;
	unsigned short syndrome;
	int nid, csrow, chan = 0;
	u16 syndrome;

	csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);

@@ -1671,8 +1676,7 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,

	error_address_to_page_and_offset(sys_addr, &page, &offset);

	syndrome  = HIGH_SYNDROME(info->nbsl) << 8;
	syndrome |= LOW_SYNDROME(info->nbsh);
	syndrome = extract_syndrome(err_info);

	/*
	 * We need the syndromes for channel detection only when we're
@@ -1955,23 +1959,23 @@ static int map_err_sym_to_channel(int err_sym, int sym_size)
static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
{
	struct amd64_pvt *pvt = mci->pvt_info;
	u32 value = 0;
	int err_sym = 0;
	int err_sym = -1;

	if (boot_cpu_data.x86 == 0x10) {

		amd64_read_pci_cfg(pvt->misc_f3_ctl, 0x180, &value);

		/* F3x180[EccSymbolSize]=1 => x8 symbols */
		if (boot_cpu_data.x86_model > 7 &&
		    value & BIT(25)) {
	if (pvt->syn_type == 8)
		err_sym = decode_syndrome(syndrome, x8_vectors,
						  ARRAY_SIZE(x8_vectors), 8);
			return map_err_sym_to_channel(err_sym, 8);
		}
					  ARRAY_SIZE(x8_vectors),
					  pvt->syn_type);
	else if (pvt->syn_type == 4)
		err_sym = decode_syndrome(syndrome, x4_vectors,
					  ARRAY_SIZE(x4_vectors),
					  pvt->syn_type);
	else {
		amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
					   __func__, pvt->syn_type);
		return err_sym;
	}
	err_sym = decode_syndrome(syndrome, x4_vectors, ARRAY_SIZE(x4_vectors), 4);
	return map_err_sym_to_channel(err_sym, 4);

	return map_err_sym_to_channel(err_sym, pvt->syn_type);
}

/*
@@ -2284,6 +2288,7 @@ static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
static void amd64_read_mc_registers(struct amd64_pvt *pvt)
{
	u64 msr_val;
	u32 tmp;
	int dram;

	/*
@@ -2349,10 +2354,22 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
	amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
	amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);

	if (!dct_ganging_enabled(pvt) && boot_cpu_data.x86 >= 0x10) {
	if (boot_cpu_data.x86 >= 0x10) {
		if (!dct_ganging_enabled(pvt)) {
			amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
			amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
		}
		amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
	}

	if (boot_cpu_data.x86 == 0x10 &&
	    boot_cpu_data.x86_model > 7 &&
	    /* F3x180[EccSymbolSize]=1 => x8 symbols */
	    tmp & BIT(25))
		pvt->syn_type = 8;
	else
		pvt->syn_type = 4;

	amd64_dump_misc_regs(pvt);
}

+5 −0
Original line number Diff line number Diff line
@@ -382,6 +382,8 @@ enum {
#define K8_NBCAP_SECDED			BIT(3)
#define K8_NBCAP_DCT_DUAL		BIT(0)

#define EXT_NB_MCA_CFG			0x180

/* MSRs */
#define K8_MSR_MCGCTL_NBE		BIT(4)

@@ -471,6 +473,9 @@ struct amd64_pvt {
	u32 dram_ctl_select_high;	/* DRAM Controller Select High Reg */
	u32 online_spare;               /* On-Line spare Reg */

	/* x4 or x8 syndromes in use */
	u8 syn_type;

	/* temp storage for when input is received from sysfs */
	struct err_regs ctl_error_info;