EDAC, amd64: Add Fam17h debug output
Read a few more UMC registers and provide debug output in order to be as similar as possible to older AMD systems. 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/1480344621-14966-1-git-send-email-Yazen.Ghannam@amd.com [ Remove unneeded K8 check and comments, fixup others. ] Signed-off-by: Borislav Petkov <bp@suse.de>
This commit is contained in:

committed by
Borislav Petkov

parent
8051c0af3c
commit
07ed82ef93
@@ -762,8 +762,75 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
|
|||||||
(dclr & BIT(15)) ? "yes" : "no");
|
(dclr & BIT(15)) ? "yes" : "no");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
|
||||||
|
{
|
||||||
|
u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
|
||||||
|
int dimm, size0, size1;
|
||||||
|
|
||||||
|
edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
|
||||||
|
|
||||||
|
for (dimm = 0; dimm < 4; dimm++) {
|
||||||
|
size0 = 0;
|
||||||
|
|
||||||
|
if (dcsb[dimm*2] & DCSB_CS_ENABLE)
|
||||||
|
size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
|
||||||
|
|
||||||
|
size1 = 0;
|
||||||
|
if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
|
||||||
|
size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, dimm);
|
||||||
|
|
||||||
|
amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
|
||||||
|
dimm * 2, size0,
|
||||||
|
dimm * 2 + 1, size1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __dump_misc_regs_df(struct amd64_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct amd64_umc *umc;
|
||||||
|
u32 i, tmp, umc_base;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_UMCS; i++) {
|
||||||
|
umc_base = get_umc_base(i);
|
||||||
|
umc = &pvt->umc[i];
|
||||||
|
|
||||||
|
edac_dbg(1, "UMC%d DIMM cfg: 0x%x\n", i, umc->dimm_cfg);
|
||||||
|
edac_dbg(1, "UMC%d UMC cfg: 0x%x\n", i, umc->umc_cfg);
|
||||||
|
edac_dbg(1, "UMC%d SDP ctrl: 0x%x\n", i, umc->sdp_ctrl);
|
||||||
|
edac_dbg(1, "UMC%d ECC ctrl: 0x%x\n", i, umc->ecc_ctrl);
|
||||||
|
|
||||||
|
amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ECC_BAD_SYMBOL, &tmp);
|
||||||
|
edac_dbg(1, "UMC%d ECC bad symbol: 0x%x\n", i, tmp);
|
||||||
|
|
||||||
|
amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_UMC_CAP, &tmp);
|
||||||
|
edac_dbg(1, "UMC%d UMC cap: 0x%x\n", i, tmp);
|
||||||
|
edac_dbg(1, "UMC%d UMC cap high: 0x%x\n", i, umc->umc_cap_hi);
|
||||||
|
|
||||||
|
edac_dbg(1, "UMC%d ECC capable: %s, ChipKill ECC capable: %s\n",
|
||||||
|
i, (umc->umc_cap_hi & BIT(30)) ? "yes" : "no",
|
||||||
|
(umc->umc_cap_hi & BIT(31)) ? "yes" : "no");
|
||||||
|
edac_dbg(1, "UMC%d All DIMMs support ECC: %s\n",
|
||||||
|
i, (umc->umc_cfg & BIT(12)) ? "yes" : "no");
|
||||||
|
edac_dbg(1, "UMC%d x4 DIMMs present: %s\n",
|
||||||
|
i, (umc->dimm_cfg & BIT(6)) ? "yes" : "no");
|
||||||
|
edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
|
||||||
|
i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");
|
||||||
|
|
||||||
|
if (pvt->dram_type == MEM_LRDDR4) {
|
||||||
|
amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
|
||||||
|
edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
|
||||||
|
i, 1 << ((tmp >> 4) & 0x3));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_display_dimm_sizes_df(pvt, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x\n",
|
||||||
|
pvt->dhar, dhar_base(pvt));
|
||||||
|
}
|
||||||
|
|
||||||
/* Display and decode various NB registers for debug purposes. */
|
/* Display and decode various NB registers for debug purposes. */
|
||||||
static void dump_misc_regs(struct amd64_pvt *pvt)
|
static void __dump_misc_regs(struct amd64_pvt *pvt)
|
||||||
{
|
{
|
||||||
edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
|
edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
|
||||||
|
|
||||||
@@ -783,8 +850,6 @@ static void dump_misc_regs(struct amd64_pvt *pvt)
|
|||||||
(pvt->fam == 0xf) ? k8_dhar_offset(pvt)
|
(pvt->fam == 0xf) ? k8_dhar_offset(pvt)
|
||||||
: f10_dhar_offset(pvt));
|
: f10_dhar_offset(pvt));
|
||||||
|
|
||||||
edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
|
|
||||||
|
|
||||||
debug_display_dimm_sizes(pvt, 0);
|
debug_display_dimm_sizes(pvt, 0);
|
||||||
|
|
||||||
/* everything below this point is Fam10h and above */
|
/* everything below this point is Fam10h and above */
|
||||||
@@ -793,13 +858,25 @@ static void dump_misc_regs(struct amd64_pvt *pvt)
|
|||||||
|
|
||||||
debug_display_dimm_sizes(pvt, 1);
|
debug_display_dimm_sizes(pvt, 1);
|
||||||
|
|
||||||
amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 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))
|
||||||
debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
|
debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Display and decode various NB registers for debug purposes. */
|
||||||
|
static void dump_misc_regs(struct amd64_pvt *pvt)
|
||||||
|
{
|
||||||
|
if (pvt->umc)
|
||||||
|
__dump_misc_regs_df(pvt);
|
||||||
|
else
|
||||||
|
__dump_misc_regs(pvt);
|
||||||
|
|
||||||
|
edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
|
||||||
|
|
||||||
|
amd64_info("using %s syndromes.\n",
|
||||||
|
((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
|
* See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
|
||||||
*/
|
*/
|
||||||
@@ -2001,8 +2078,9 @@ static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
|||||||
|
|
||||||
size0 = 0;
|
size0 = 0;
|
||||||
if (dcsb[dimm*2] & DCSB_CS_ENABLE)
|
if (dcsb[dimm*2] & DCSB_CS_ENABLE)
|
||||||
/* For f15m60h, need multiplier for LRDIMM cs_size
|
/*
|
||||||
* calculation. We pass 'dimm' value to the dbam_to_cs
|
* For F15m60h, we need multiplier for LRDIMM cs_size
|
||||||
|
* calculation. We pass dimm value to the dbam_to_cs
|
||||||
* mapper so we can find the multiplier from the
|
* mapper so we can find the multiplier from the
|
||||||
* corresponding DCSM.
|
* corresponding DCSM.
|
||||||
*/
|
*/
|
||||||
@@ -2463,9 +2541,11 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt)
|
|||||||
umc_base = get_umc_base(i);
|
umc_base = get_umc_base(i);
|
||||||
umc = &pvt->umc[i];
|
umc = &pvt->umc[i];
|
||||||
|
|
||||||
|
amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
|
||||||
|
amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg);
|
||||||
amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
|
amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl);
|
||||||
amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
|
amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl);
|
||||||
amd_smn_read(nid, umc_base + UMCCH_DIMM_CFG, &umc->dimm_cfg);
|
amd_smn_read(nid, umc_base + UMCCH_UMC_CAP_HI, &umc->umc_cap_hi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -260,9 +260,13 @@
|
|||||||
/* UMC CH register offsets */
|
/* UMC CH register offsets */
|
||||||
#define UMCCH_BASE_ADDR 0x0
|
#define UMCCH_BASE_ADDR 0x0
|
||||||
#define UMCCH_ADDR_MASK 0x20
|
#define UMCCH_ADDR_MASK 0x20
|
||||||
|
#define UMCCH_ADDR_CFG 0x30
|
||||||
#define UMCCH_DIMM_CFG 0x80
|
#define UMCCH_DIMM_CFG 0x80
|
||||||
|
#define UMCCH_UMC_CFG 0x100
|
||||||
#define UMCCH_SDP_CTRL 0x104
|
#define UMCCH_SDP_CTRL 0x104
|
||||||
#define UMCCH_ECC_CTRL 0x14C
|
#define UMCCH_ECC_CTRL 0x14C
|
||||||
|
#define UMCCH_ECC_BAD_SYMBOL 0xD90
|
||||||
|
#define UMCCH_UMC_CAP 0xDF0
|
||||||
#define UMCCH_UMC_CAP_HI 0xDF4
|
#define UMCCH_UMC_CAP_HI 0xDF4
|
||||||
|
|
||||||
/* UMC CH bitfields */
|
/* UMC CH bitfields */
|
||||||
@@ -316,8 +320,10 @@ struct chip_select {
|
|||||||
|
|
||||||
struct amd64_umc {
|
struct amd64_umc {
|
||||||
u32 dimm_cfg; /* DIMM Configuration reg */
|
u32 dimm_cfg; /* DIMM Configuration reg */
|
||||||
|
u32 umc_cfg; /* Configuration reg */
|
||||||
u32 sdp_ctrl; /* SDP Control reg */
|
u32 sdp_ctrl; /* SDP Control reg */
|
||||||
u32 ecc_ctrl; /* DRAM ECC Control reg */
|
u32 ecc_ctrl; /* DRAM ECC Control reg */
|
||||||
|
u32 umc_cap_hi; /* Capabilities High reg */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct amd64_pvt {
|
struct amd64_pvt {
|
||||||
|
Reference in New Issue
Block a user