The branch main has been updated by mav:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3bdba24c74604b1bb27623cd8304476bbbed69d1

commit 3bdba24c74604b1bb27623cd8304476bbbed69d1
Author:     Alexander Motin <m...@freebsd.org>
AuthorDate: 2021-12-08 17:01:48 +0000
Commit:     Alexander Motin <m...@freebsd.org>
CommitDate: 2021-12-08 17:03:28 +0000

    mca: Decode new Intel status bits.
    
    MFC after:      1 week
---
 sys/x86/include/specialreg.h | 11 +++++
 sys/x86/x86/mca.c            | 96 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
index 22672d50efed..ddac2b9ea2b2 100644
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -608,6 +608,7 @@
 #define        MSR_MC4_STATUS          0x411
 #define        MSR_MC4_ADDR            0x412
 #define        MSR_MC4_MISC            0x413
+#define        MSR_MCG_EXT_CTL         0x4d0
 #define        MSR_RAPL_POWER_UNIT     0x606
 #define        MSR_PKG_ENERGY_STATUS   0x611
 #define        MSR_DRAM_ENERGY_STATUS  0x619
@@ -770,6 +771,7 @@
 #define        IA32_FEATURE_CONTROL_LOCK       0x01    /* lock bit */
 #define        IA32_FEATURE_CONTROL_SMX_EN     0x02    /* enable VMX inside 
SMX */
 #define        IA32_FEATURE_CONTROL_VMX_EN     0x04    /* enable VMX outside 
SMX */
+#define        IA32_FEATURE_CONTROL_LMCE_EN    0x100000 /* enable local MCE */
 
 /* MSR IA32_MISC_ENABLE */
 #define        IA32_MISC_EN_FASTSTR    0x0000000000000001ULL
@@ -948,9 +950,13 @@
 #define        MCG_CAP_TES_P           0x00000800
 #define        MCG_CAP_EXT_CNT         0x00ff0000
 #define        MCG_CAP_SER_P           0x01000000
+#define        MCG_CAP_EMC_P           0x02000000
+#define        MCG_CAP_ELOG_P          0x04000000
+#define        MCG_CAP_LMCE_P          0x08000000
 #define        MCG_STATUS_RIPV         0x00000001
 #define        MCG_STATUS_EIPV         0x00000002
 #define        MCG_STATUS_MCIP         0x00000004
+#define        MCG_STATUS_LMCS         0x00000008              /* if 
MCG_CAP_LMCE_P */
 #define        MCG_CTL_ENABLE          0xffffffffffffffff
 #define        MCG_CTL_DISABLE         0x0000000000000000
 #define        MSR_MC_CTL(x)           (MSR_MC0_CTL + (x) * 4)
@@ -974,6 +980,11 @@
 #define        MC_STATUS_VAL           0x8000000000000000
 #define        MC_MISC_RA_LSB          0x000000000000003f      /* If 
MCG_CAP_SER_P */
 #define        MC_MISC_ADDRESS_MODE    0x00000000000001c0      /* If 
MCG_CAP_SER_P */
+#define        MC_MISC_PCIE_RID        0x00000000ffff0000
+#define        MC_MISC_PCIE_FUNC       0x0000000000070000
+#define        MC_MISC_PCIE_SLOT       0x0000000000f80000
+#define        MC_MISC_PCIE_BUS        0x00000000ff000000
+#define        MC_MISC_PCIE_SEG        0x000000ff00000000
 #define        MC_CTL2_THRESHOLD       0x0000000000007fff
 #define        MC_CTL2_CMCI_EN         0x0000000040000000
 #define        MC_AMDNB_BANK           4
diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c
index 1b34fc398068..2f4fca0ca062 100644
--- a/sys/x86/x86/mca.c
+++ b/sys/x86/x86/mca.c
@@ -227,6 +227,26 @@ cmci_supported(uint64_t mcg_cap)
        return ((mcg_cap & MCG_CAP_CMCI_P) != 0);
 }
 
+static inline bool
+tes_supported(uint64_t mcg_cap)
+{
+
+       /*
+        * MCG_CAP_TES_P bit is reserved in AMD documentation.  Until
+        * it is defined, do not use it to check for TES support.
+        */
+       if (cpu_vendor_id != CPU_VENDOR_INTEL)
+               return (false);
+       return ((mcg_cap & MCG_CAP_TES_P) != 0);
+}
+
+static inline bool
+ser_supported(uint64_t mcg_cap)
+{
+
+       return (tes_supported(mcg_cap) && (mcg_cap & MCG_CAP_SER_P) != 0);
+}
+
 static int
 sysctl_positive_int(SYSCTL_HANDLER_ARGS)
 {
@@ -352,6 +372,25 @@ mca_error_mmtype(uint16_t mca_error)
        return ("???");
 }
 
+static const char *
+mca_addres_mode(uint64_t mca_misc)
+{
+
+       switch ((mca_misc & MC_MISC_ADDRESS_MODE) >> 6) {
+       case 0x0:
+               return ("Segment Offset");
+       case 0x1:
+               return ("Linear Address");
+       case 0x2:
+               return ("Physical Address");
+       case 0x3:
+               return ("Memory Address");
+       case 0x7:
+               return ("Generic");
+       }
+       return ("???");
+}
+
 static int
 mca_mute(const struct mca_record *rec)
 {
@@ -403,9 +442,25 @@ mca_log(const struct mca_record *rec)
                if (cmci_supported(rec->mr_mcg_cap))
                        printf("(%lld) ", ((long long)rec->mr_status &
                            MC_STATUS_COR_COUNT) >> 38);
+               if (tes_supported(rec->mr_mcg_cap)) {
+                       switch ((rec->mr_status & MC_STATUS_TES_STATUS) >> 53) {
+                       case 0x1:
+                               printf("(Green) ");
+                       case 0x2:
+                               printf("(Yellow) ");
+                       }
+               }
        }
+       if (rec->mr_status & MC_STATUS_EN)
+               printf("EN ");
        if (rec->mr_status & MC_STATUS_PCC)
                printf("PCC ");
+       if (ser_supported(rec->mr_mcg_cap)) {
+               if (rec->mr_status & MC_STATUS_S)
+                       printf("S ");
+               if (rec->mr_status & MC_STATUS_AR)
+                       printf("AR ");
+       }
        if (rec->mr_status & MC_STATUS_OVER)
                printf("OVER ");
        mca_error = rec->mr_status & MC_STATUS_MCA_ERROR;
@@ -429,9 +484,23 @@ mca_log(const struct mca_record *rec)
        case 0x0005:
                printf("internal parity error");
                break;
+       case 0x0006:
+               printf("SMM handler code access violation");
+               break;
        case 0x0400:
                printf("internal timer error");
                break;
+       case 0x0e0b:
+               printf("generic I/O error");
+               if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL &&
+                   (rec->mr_status & MC_STATUS_MISCV)) {
+                       printf(" (pci%d:%d:%d:%d)",
+                           (int)((rec->mr_misc & MC_MISC_PCIE_SEG) >> 32),
+                           (int)((rec->mr_misc & MC_MISC_PCIE_BUS) >> 24),
+                           (int)((rec->mr_misc & MC_MISC_PCIE_SLOT) >> 19),
+                           (int)((rec->mr_misc & MC_MISC_PCIE_FUNC) >> 16));
+               }
+               break;
        default:
                if ((mca_error & 0xfc00) == 0x0400) {
                        printf("internal error %x", mca_error & 0x03ff);
@@ -463,7 +532,7 @@ mca_log(const struct mca_record *rec)
                        printf(" memory error");
                        break;
                }
-               
+
                /* Cache error. */
                if ((mca_error & 0xef00) == 0x0100) {
                        printf("%sCACHE %s %s error",
@@ -473,8 +542,19 @@ mca_log(const struct mca_record *rec)
                        break;
                }
 
+               /* Extended memory error. */
+               if ((mca_error & 0xef80) == 0x0280) {
+                       printf("%s channel ", mca_error_mmtype(mca_error));
+                       if ((mca_error & 0x000f) != 0x000f)
+                               printf("%d", mca_error & 0x000f);
+                       else
+                               printf("??");
+                       printf(" extended memory error");
+                       break;
+               }
+
                /* Bus and/or Interconnect error. */
-               if ((mca_error & 0xe800) == 0x0800) {                   
+               if ((mca_error & 0xe800) == 0x0800) {
                        printf("BUS%s ", mca_error_level(mca_error));
                        switch ((mca_error & 0x0600) >> 9) {
                        case 0:
@@ -514,8 +594,16 @@ mca_log(const struct mca_record *rec)
                break;
        }
        printf("\n");
-       if (rec->mr_status & MC_STATUS_ADDRV)
-               printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr);
+       if (rec->mr_status & MC_STATUS_ADDRV) {
+               printf("MCA: Address 0x%llx", (long long)rec->mr_addr);
+               if (ser_supported(rec->mr_mcg_cap) &&
+                   (rec->mr_status & MC_STATUS_MISCV)) {
+                       printf(" (Mode: %s, LSB: %d)",
+                           mca_addres_mode(rec->mr_misc),
+                           (int)(rec->mr_misc & MC_MISC_RA_LSB));
+               }
+               printf("\n");
+       }
        if (rec->mr_status & MC_STATUS_MISCV)
                printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc);
 }

Reply via email to