|
@@ -729,3 +729,145 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
|
|
|
return csrow;
|
|
|
}
|
|
|
|
|
|
+static int get_channel_from_ecc_syndrome(unsigned short syndrome);
|
|
|
+
|
|
|
+static void amd64_cpu_display_info(struct amd64_pvt *pvt)
|
|
|
+{
|
|
|
+ if (boot_cpu_data.x86 == 0x11)
|
|
|
+ edac_printk(KERN_DEBUG, EDAC_MC, "F11h CPU detected\n");
|
|
|
+ else if (boot_cpu_data.x86 == 0x10)
|
|
|
+ edac_printk(KERN_DEBUG, EDAC_MC, "F10h CPU detected\n");
|
|
|
+ else if (boot_cpu_data.x86 == 0xf)
|
|
|
+ edac_printk(KERN_DEBUG, EDAC_MC, "%s detected\n",
|
|
|
+ (pvt->ext_model >= OPTERON_CPU_REV_F) ?
|
|
|
+ "Rev F or later" : "Rev E or earlier");
|
|
|
+ else
|
|
|
+ /* we'll hardly ever ever get here */
|
|
|
+ edac_printk(KERN_ERR, EDAC_MC, "Unknown cpu!\n");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
|
|
|
+ * are ECC capable.
|
|
|
+ */
|
|
|
+static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
|
|
|
+{
|
|
|
+ int bit;
|
|
|
+ enum dev_type edac_cap = EDAC_NONE;
|
|
|
+
|
|
|
+ bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
|
|
|
+ ? 19
|
|
|
+ : 17;
|
|
|
+
|
|
|
+ if (pvt->dclr0 >> BIT(bit))
|
|
|
+ edac_cap = EDAC_FLAG_SECDED;
|
|
|
+
|
|
|
+ return edac_cap;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void f10_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt,
|
|
|
+ int ganged);
|
|
|
+
|
|
|
+/* Display and decode various NB registers for debug purposes. */
|
|
|
+static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
|
|
|
+{
|
|
|
+ int ganged;
|
|
|
+
|
|
|
+ debugf1(" nbcap:0x%8.08x DctDualCap=%s DualNode=%s 8-Node=%s\n",
|
|
|
+ pvt->nbcap,
|
|
|
+ (pvt->nbcap & K8_NBCAP_DCT_DUAL) ? "True" : "False",
|
|
|
+ (pvt->nbcap & K8_NBCAP_DUAL_NODE) ? "True" : "False",
|
|
|
+ (pvt->nbcap & K8_NBCAP_8_NODE) ? "True" : "False");
|
|
|
+ debugf1(" ECC Capable=%s ChipKill Capable=%s\n",
|
|
|
+ (pvt->nbcap & K8_NBCAP_SECDED) ? "True" : "False",
|
|
|
+ (pvt->nbcap & K8_NBCAP_CHIPKILL) ? "True" : "False");
|
|
|
+ debugf1(" DramCfg0-low=0x%08x DIMM-ECC=%s Parity=%s Width=%s\n",
|
|
|
+ pvt->dclr0,
|
|
|
+ (pvt->dclr0 & BIT(19)) ? "Enabled" : "Disabled",
|
|
|
+ (pvt->dclr0 & BIT(8)) ? "Enabled" : "Disabled",
|
|
|
+ (pvt->dclr0 & BIT(11)) ? "128b" : "64b");
|
|
|
+ debugf1(" DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s DIMM Type=%s\n",
|
|
|
+ (pvt->dclr0 & BIT(12)) ? "Y" : "N",
|
|
|
+ (pvt->dclr0 & BIT(13)) ? "Y" : "N",
|
|
|
+ (pvt->dclr0 & BIT(14)) ? "Y" : "N",
|
|
|
+ (pvt->dclr0 & BIT(15)) ? "Y" : "N",
|
|
|
+ (pvt->dclr0 & BIT(16)) ? "UN-Buffered" : "Buffered");
|
|
|
+
|
|
|
+
|
|
|
+ debugf1(" online-spare: 0x%8.08x\n", pvt->online_spare);
|
|
|
+
|
|
|
+ if (boot_cpu_data.x86 == 0xf) {
|
|
|
+ debugf1(" dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n",
|
|
|
+ pvt->dhar, dhar_base(pvt->dhar),
|
|
|
+ k8_dhar_offset(pvt->dhar));
|
|
|
+ debugf1(" DramHoleValid=%s\n",
|
|
|
+ (pvt->dhar & DHAR_VALID) ? "True" : "False");
|
|
|
+
|
|
|
+ debugf1(" dbam-dkt: 0x%8.08x\n", pvt->dbam0);
|
|
|
+
|
|
|
+ /* everything below this point is Fam10h and above */
|
|
|
+ return;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ debugf1(" dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n",
|
|
|
+ pvt->dhar, dhar_base(pvt->dhar),
|
|
|
+ f10_dhar_offset(pvt->dhar));
|
|
|
+ debugf1(" DramMemHoistValid=%s DramHoleValid=%s\n",
|
|
|
+ (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) ?
|
|
|
+ "True" : "False",
|
|
|
+ (pvt->dhar & DHAR_VALID) ?
|
|
|
+ "True" : "False");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Only if NOT ganged does dcl1 have valid info */
|
|
|
+ if (!dct_ganging_enabled(pvt)) {
|
|
|
+ debugf1(" DramCfg1-low=0x%08x DIMM-ECC=%s Parity=%s "
|
|
|
+ "Width=%s\n", pvt->dclr1,
|
|
|
+ (pvt->dclr1 & BIT(19)) ? "Enabled" : "Disabled",
|
|
|
+ (pvt->dclr1 & BIT(8)) ? "Enabled" : "Disabled",
|
|
|
+ (pvt->dclr1 & BIT(11)) ? "128b" : "64b");
|
|
|
+ debugf1(" DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s "
|
|
|
+ "DIMM Type=%s\n",
|
|
|
+ (pvt->dclr1 & BIT(12)) ? "Y" : "N",
|
|
|
+ (pvt->dclr1 & BIT(13)) ? "Y" : "N",
|
|
|
+ (pvt->dclr1 & BIT(14)) ? "Y" : "N",
|
|
|
+ (pvt->dclr1 & BIT(15)) ? "Y" : "N",
|
|
|
+ (pvt->dclr1 & BIT(16)) ? "UN-Buffered" : "Buffered");
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Determine if ganged and then dump memory sizes for first controller,
|
|
|
+ * and if NOT ganged dump info for 2nd controller.
|
|
|
+ */
|
|
|
+ ganged = dct_ganging_enabled(pvt);
|
|
|
+
|
|
|
+ f10_debug_display_dimm_sizes(0, pvt, ganged);
|
|
|
+
|
|
|
+ if (!ganged)
|
|
|
+ f10_debug_display_dimm_sizes(1, pvt, ganged);
|
|
|
+}
|
|
|
+
|
|
|
+/* Read in both of DBAM registers */
|
|
|
+static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ unsigned int reg;
|
|
|
+
|
|
|
+ reg = DBAM0;
|
|
|
+ err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam0);
|
|
|
+ if (err)
|
|
|
+ goto err_reg;
|
|
|
+
|
|
|
+ if (boot_cpu_data.x86 >= 0x10) {
|
|
|
+ reg = DBAM1;
|
|
|
+ err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam1);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ goto err_reg;
|
|
|
+ }
|
|
|
+
|
|
|
+err_reg:
|
|
|
+ debugf0("Error reading F2x%03x.\n", reg);
|
|
|
+}
|
|
|
+
|