EDAC, amd64: Determine EDAC MC capabilities on Fam17h
The UMCs on Fam17h are independent memory controllers so we need to read the capabilities from all UMCs and make sure they agree. Once we determine what capabilities are available we should save them for convenience. Signed-off-by: Yazen Ghannam <Yazen.Ghannam@amd.com> Cc: Aravind Gopalakrishnan <aravindksg.lkml@gmail.com> Cc: linux-edac <linux-edac@vger.kernel.org> Cc: x86-ml <x86@kernel.org> Link: http://lkml.kernel.org/r/1480431116-94683-1-git-send-email-Yazen.Ghannam@amd.com [ Simplify f17h_determine_edac_ctl_cap(), preinit edac_mode in init_csrows(). ] Signed-off-by: Borislav Petkov <bp@suse.de>
This commit is contained in:
Родитель
07ed82ef93
Коммит
2d09d8f301
|
@ -2698,13 +2698,14 @@ 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;
|
||||
|
||||
if (!pvt->umc) {
|
||||
amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
|
||||
|
||||
pvt->nbcfg = val;
|
||||
|
@ -2712,6 +2713,7 @@ static int init_csrows(struct mem_ctl_info *mci)
|
|||
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->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;
|
||||
}
|
||||
|
||||
mci->edac_cap = determine_edac_cap(pvt);
|
||||
mci->mod_name = EDAC_MOD_STR;
|
||||
|
|
Загрузка…
Ссылка в новой задаче