diff options
-rw-r--r-- | drivers/edac/amd64_edac.c | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index fdd9637..9f9d2bc 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2698,20 +2698,22 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) static int init_csrows(struct mem_ctl_info *mci) { struct amd64_pvt *pvt = mci->pvt_info; + enum edac_type edac_mode = EDAC_NONE; struct csrow_info *csrow; struct dimm_info *dimm; - enum edac_type edac_mode; int i, j, empty = 1; int nr_pages = 0; u32 val; - amd64_read_pci_cfg(pvt->F3, NBCFG, &val); + if (!pvt->umc) { + amd64_read_pci_cfg(pvt->F3, NBCFG, &val); - pvt->nbcfg = val; + pvt->nbcfg = val; - edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", - pvt->mc_node_id, val, - !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); + edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", + pvt->mc_node_id, val, + !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); + } /* * We iterate over DCT0 here but we look at DCT1 in parallel, if needed. @@ -2747,14 +2749,18 @@ static int init_csrows(struct mem_ctl_info *mci) edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); - /* - * determine whether CHIPKILL or JUST ECC or NO ECC is operating - */ - if (pvt->nbcfg & NBCFG_ECC_ENABLE) - edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) ? - EDAC_S4ECD4ED : EDAC_SECDED; - else - edac_mode = EDAC_NONE; + /* Determine DIMM ECC mode: */ + if (pvt->umc) { + if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) + edac_mode = EDAC_S4ECD4ED; + else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) + edac_mode = EDAC_SECDED; + + } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) { + edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) + ? EDAC_S4ECD4ED + : EDAC_SECDED; + } for (j = 0; j < pvt->channel_count; j++) { dimm = csrow->channels[j]->dimm; @@ -2992,6 +2998,27 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) return true; } +static inline void +f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) +{ + u8 i, ecc_en = 1, cpk_en = 1; + + for (i = 0; i < NUM_UMCS; i++) { + if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { + ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED); + cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP); + } + } + + /* Set chipkill only if ECC is enabled: */ + if (ecc_en) { + mci->edac_ctl_cap |= EDAC_FLAG_SECDED; + + if (cpk_en) + mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; + } +} + static void setup_mci_misc_attrs(struct mem_ctl_info *mci, struct amd64_family_type *fam) { @@ -3000,11 +3027,15 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci, mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; mci->edac_ctl_cap = EDAC_FLAG_NONE; - if (pvt->nbcap & NBCAP_SECDED) - mci->edac_ctl_cap |= EDAC_FLAG_SECDED; + if (pvt->umc) { + f17h_determine_edac_ctl_cap(mci, pvt); + } else { + if (pvt->nbcap & NBCAP_SECDED) + mci->edac_ctl_cap |= EDAC_FLAG_SECDED; - if (pvt->nbcap & NBCAP_CHIPKILL) - mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; + if (pvt->nbcap & NBCAP_CHIPKILL) + mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; + } mci->edac_cap = determine_edac_cap(pvt); mci->mod_name = EDAC_MOD_STR; |