EDAC, amd64: Extend ecc_enabled() to Fam17h
authorYazen Ghannam <Yazen.Ghannam@amd.com>
Thu, 17 Nov 2016 22:57:34 +0000 (17:57 -0500)
committerBorislav Petkov <bp@suse.de>
Thu, 24 Nov 2016 20:07:03 +0000 (21:07 +0100)
Update the ecc_enabled() function to work on Fam17h. This entails
reading a different set of registers and using the SMN (System
Management Network) rather than PCI devices.

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/1479423463-8536-9-git-send-email-Yazen.Ghannam@amd.com
[ Fixup ecc_en assignment and get_umc_base(). ]
Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h

index ca1d63a..870f567 100644 (file)
@@ -2664,20 +2664,50 @@ static const char *ecc_msg =
 
 static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 {
-       u32 value;
-       u8 ecc_en = 0;
        bool nb_mce_en = false;
+       u8 ecc_en = 0, i;
+       u32 value;
 
-       amd64_read_pci_cfg(F3, NBCFG, &value);
+       if (boot_cpu_data.x86 >= 0x17) {
+               u8 umc_en_mask = 0, ecc_en_mask = 0;
 
-       ecc_en = !!(value & NBCFG_ECC_ENABLE);
-       amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
+               for (i = 0; i < NUM_UMCS; i++) {
+                       u32 base = get_umc_base(i);
+
+                       /* Only check enabled UMCs. */
+                       if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value))
+                               continue;
+
+                       if (!(value & UMC_SDP_INIT))
+                               continue;
+
+                       umc_en_mask |= BIT(i);
+
+                       if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value))
+                               continue;
+
+                       if (value & UMC_ECC_ENABLED)
+                               ecc_en_mask |= BIT(i);
+               }
+
+               /* Check whether at least one UMC is enabled: */
+               if (umc_en_mask)
+                       ecc_en = umc_en_mask == ecc_en_mask;
+
+               /* Assume UMC MCA banks are enabled. */
+               nb_mce_en = true;
+       } else {
+               amd64_read_pci_cfg(F3, NBCFG, &value);
 
-       nb_mce_en = nb_mce_bank_enabled_on_node(nid);
-       if (!nb_mce_en)
-               amd64_notice("NB MCE bank disabled, set MSR "
-                            "0x%08x[4] on node %d to enable.\n",
-                            MSR_IA32_MCG_CTL, nid);
+               ecc_en = !!(value & NBCFG_ECC_ENABLE);
+
+               nb_mce_en = nb_mce_bank_enabled_on_node(nid);
+               if (!nb_mce_en)
+                       amd64_notice("NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n",
+                                    MSR_IA32_MCG_CTL, nid);
+       }
+
+       amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
 
        if (!ecc_en || !nb_mce_en) {
                amd64_notice("%s", ecc_msg);
index c088704..96c1f5d 100644 (file)
 /* MSRs */
 #define MSR_MCGCTL_NBE                 BIT(4)
 
+/* UMC CH register offsets */
+#define UMCCH_SDP_CTRL                 0x104
+#define UMCCH_UMC_CAP_HI               0xDF4
+
+/* UMC CH bitfields */
+#define UMC_ECC_ENABLED                        BIT(30)
+#define UMC_SDP_INIT                   BIT(31)
+
+#define NUM_UMCS                       2
+
 enum amd_families {
        K8_CPUS = 0,
        F10_CPUS,
@@ -354,6 +364,12 @@ struct err_info {
        u32 offset;
 };
 
+static inline u32 get_umc_base(u8 channel)
+{
+       /* ch0: 0x50000, ch1: 0x150000 */
+       return 0x50000 + (!!channel << 20);
+}
+
 static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
 {
        u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;