mca: Decode new Intel status bits.

MFC after:	1 week
This commit is contained in:
Alexander Motin 2021-12-08 12:01:48 -05:00
parent 547fc67fec
commit 3bdba24c74
2 changed files with 103 additions and 4 deletions

View File

@ -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

View File

@ -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);
}