aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2021-12-08 17:01:48 +0000
committerAlexander Motin <mav@FreeBSD.org>2021-12-08 17:03:28 +0000
commit3bdba24c74604b1bb27623cd8304476bbbed69d1 (patch)
treefda7f0d73d2726db812b2ead40124d392bc3c7a9
parent547fc67fecea51033a4b001d5b589f0e6cf8d820 (diff)
downloadsrc-3bdba24c74604b1bb27623cd8304476bbbed69d1.tar.gz
src-3bdba24c74604b1bb27623cd8304476bbbed69d1.zip
mca: Decode new Intel status bits.
MFC after: 1 week
-rw-r--r--sys/x86/include/specialreg.h11
-rw-r--r--sys/x86/x86/mca.c96
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);
}