Commit ad6a32e9 authored by Borislav Petkov's avatar Borislav Petkov

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
...@@ -796,6 +796,11 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) ...@@ -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 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) static void amd64_cpu_display_info(struct amd64_pvt *pvt)
{ {
if (boot_cpu_data.x86 == 0x11) if (boot_cpu_data.x86 == 0x11)
...@@ -888,6 +893,9 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt) ...@@ -888,6 +893,9 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
return; return;
} }
amd64_printk(KERN_INFO, "using %s syndromes.\n",
((pvt->syn_type == 8) ? "x8" : "x4"));
/* Only if NOT ganged does dclr1 have valid info */ /* Only if NOT ganged does dclr1 have valid info */
if (!dct_ganging_enabled(pvt)) if (!dct_ganging_enabled(pvt))
amd64_dump_dramcfg_low(pvt->dclr1, 1); amd64_dump_dramcfg_low(pvt->dclr1, 1);
...@@ -1101,20 +1109,17 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram) ...@@ -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, static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
struct err_regs *info, struct err_regs *err_info, u64 sys_addr)
u64 sys_addr)
{ {
struct mem_ctl_info *src_mci; struct mem_ctl_info *src_mci;
unsigned short syndrome;
int channel, csrow; int channel, csrow;
u32 page, offset; u32 page, offset;
u16 syndrome;
/* Extract the syndrome parts and form a 16-bit syndrome */ syndrome = extract_syndrome(err_info);
syndrome = HIGH_SYNDROME(info->nbsl) << 8;
syndrome |= LOW_SYNDROME(info->nbsh);
/* CHIPKILL enabled */ /* CHIPKILL enabled */
if (info->nbcfg & K8_NBCFG_CHIPKILL) { if (err_info->nbcfg & K8_NBCFG_CHIPKILL) {
channel = get_channel_from_ecc_syndrome(mci, syndrome); channel = get_channel_from_ecc_syndrome(mci, syndrome);
if (channel < 0) { if (channel < 0) {
/* /*
...@@ -1123,8 +1128,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, ...@@ -1123,8 +1128,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
* as suspect. * as suspect.
*/ */
amd64_mc_printk(mci, KERN_WARNING, amd64_mc_printk(mci, KERN_WARNING,
"unknown syndrome 0x%x - possible error " "unknown syndrome 0x%04x - possible "
"reporting race\n", syndrome); "error reporting race\n", syndrome);
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return; return;
} }
...@@ -1654,13 +1659,13 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, ...@@ -1654,13 +1659,13 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
* (MCX_ADDR). * (MCX_ADDR).
*/ */
static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci, static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
struct err_regs *info, struct err_regs *err_info,
u64 sys_addr) u64 sys_addr)
{ {
struct amd64_pvt *pvt = mci->pvt_info; struct amd64_pvt *pvt = mci->pvt_info;
u32 page, offset; u32 page, offset;
unsigned short syndrome;
int nid, csrow, chan = 0; int nid, csrow, chan = 0;
u16 syndrome;
csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan); 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, ...@@ -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); error_address_to_page_and_offset(sys_addr, &page, &offset);
syndrome = HIGH_SYNDROME(info->nbsl) << 8; syndrome = extract_syndrome(err_info);
syndrome |= LOW_SYNDROME(info->nbsh);
/* /*
* We need the syndromes for channel detection only when we're * We need the syndromes for channel detection only when we're
...@@ -1878,7 +1882,7 @@ static u16 x8_vectors[] = { ...@@ -1878,7 +1882,7 @@ static u16 x8_vectors[] = {
}; };
static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs, static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
int v_dim) int v_dim)
{ {
unsigned int i, err_sym; unsigned int i, err_sym;
...@@ -1955,23 +1959,23 @@ static int map_err_sym_to_channel(int err_sym, int sym_size) ...@@ -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) static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
{ {
struct amd64_pvt *pvt = mci->pvt_info; struct amd64_pvt *pvt = mci->pvt_info;
u32 value = 0; int err_sym = -1;
int err_sym = 0;
if (pvt->syn_type == 8)
if (boot_cpu_data.x86 == 0x10) { err_sym = decode_syndrome(syndrome, x8_vectors,
ARRAY_SIZE(x8_vectors),
amd64_read_pci_cfg(pvt->misc_f3_ctl, 0x180, &value); pvt->syn_type);
else if (pvt->syn_type == 4)
/* F3x180[EccSymbolSize]=1 => x8 symbols */ err_sym = decode_syndrome(syndrome, x4_vectors,
if (boot_cpu_data.x86_model > 7 && ARRAY_SIZE(x4_vectors),
value & BIT(25)) { pvt->syn_type);
err_sym = decode_syndrome(syndrome, x8_vectors, else {
ARRAY_SIZE(x8_vectors), 8); amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
return map_err_sym_to_channel(err_sym, 8); __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) ...@@ -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) static void amd64_read_mc_registers(struct amd64_pvt *pvt)
{ {
u64 msr_val; u64 msr_val;
u32 tmp;
int dram; int dram;
/* /*
...@@ -2349,10 +2354,22 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt) ...@@ -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_DCLR_0, &pvt->dclr0);
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0); 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) {
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1); if (!dct_ganging_enabled(pvt)) {
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1); 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); amd64_dump_misc_regs(pvt);
} }
......
...@@ -382,6 +382,8 @@ enum { ...@@ -382,6 +382,8 @@ enum {
#define K8_NBCAP_SECDED BIT(3) #define K8_NBCAP_SECDED BIT(3)
#define K8_NBCAP_DCT_DUAL BIT(0) #define K8_NBCAP_DCT_DUAL BIT(0)
#define EXT_NB_MCA_CFG 0x180
/* MSRs */ /* MSRs */
#define K8_MSR_MCGCTL_NBE BIT(4) #define K8_MSR_MCGCTL_NBE BIT(4)
...@@ -471,6 +473,9 @@ struct amd64_pvt { ...@@ -471,6 +473,9 @@ struct amd64_pvt {
u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */ u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */
u32 online_spare; /* On-Line spare 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 */ /* temp storage for when input is received from sysfs */
struct err_regs ctl_error_info; struct err_regs ctl_error_info;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment