blob: 9608c6c3c8c8190572b2c9b49fbfdad62ecda305 [file]
/* Copyright (C) 2025 Intel Corporation
Decode Intel Diamond Rapids specific machine check errors.
mcelog is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
mcelog is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should find a copy of v2 of the GNU General Public License somewhere
on your Linux system; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Author: Qiuxu Zhuo
*/
#include "mcelog.h"
#include "bitfield.h"
#include "diamond.h"
#include "memdb.h"
static char *cbb_punit_0[] = {
[0x01] = "CR4_MCE_CLEAR: MCE when CR4.MCE is clear",
[0x02] = "MCE_MCIP_SET: MCE when MCIP bit is set",
[0x03] = "MCE_UNDER_WFS: MCE under WPS",
[0x04] = "MCE_LT_HANDSHAKE: Unrecoverable error during security flow execution",
[0x05] = "TRIPLE_FAULT: SW triple fault shutdown",
[0x06] = "VMX_ABORT: VMX exit consistency check failures",
[0x07] = "RSM_CONSISTENCY_FAIL: RSM consistency check failures",
[0x08] = "SMM_PROTECTED_ENTRY_FAIL: Invalid conditions on protected mode SMM entry",
[0x09] = "UCODE_PATCH_LOAD_FAIL: Unrecoverable error during security flow execution",
};
static char *cbb_punit_8[] = {
[0x16] = "MCA_DVFS_COUNTER_EXPIRED",
[0x23] = "MCA_UNSUPP_RESP",
[0x25] = "MCA_FUSA_MBIST",
[0x26] = "MCA_SA_PLL_LOCKED",
[0x27] = "MCA_XTAL_FREQ_MON_ERROR",
[0x28] = "MCA_PMSB_FUSE_PULLER_ERROR",
[0x29] = "MCA_GPSB_FUSE_PULLER_ERROR",
[0x30] = "MCA_PCODE_WATCHDOG",
[0x31] = "MCA_BGR_FUSA_ERR",
[0x32] = "MCA_CORE_FIVR_ERR",
[0x33] = "MCA_D2D_FIVR_ERR",
[0x34] = "MCA_MLC_FIVR_ERR",
[0x35] = "MCA_RING_FIVR_ERR",
[0x36] = "MCA_D2D_MONF_PLL_FUSA_0",
[0x37] = "MCA_D2D_MONF_PLL_FUSA_1",
[0x38] = "MCA_TOP0_FUSA_PLL_ERR",
[0x39] = "MCA_BASE_FUSA_PLL_ERR",
[0x40] = "MCA_UCIE_RESET_BUS_STOP_ON_ERROR",
[0x41] = "MCA_RSRC_ADAPT_0_ERR",
[0x42] = "MCA_RSC_ADAPT_1_ERR",
[0x45] = "MCA_TOP1_FUSA_PLL_ERR",
[0x46] = "MCA_TOP2_FUSA_PLL_ERR",
[0x47] = "MCA_TOP3_FUSA_PLL_ERR",
[0x48] = "UC_PATCH_LOAD_ACK_ERROR",
};
static char *cbb_punit_12[] = {
[0x01] = "MCA_UC_IRAM_DOUBLE_ERROR",
[0x02] = "MCA_UC_DOUBLE_EXCEPTION_ERROR",
[0x03] = "MCA_UC_TELEM_SRAM_ERROR",
[0x04] = "MCA_UC_DRAM_DOUBLE_ERROR",
[0x05] = "MCA_UC_TPMI_SRAM_ERROR",
};
static char *cbb_punit_20[] = {
[0x01] = "MCA_FIVR_HI_YELLOW",
[0x02] = "MCA_FIVR_HI_RED",
};
static struct field cbb_punit0[] = {
FIELD(0, cbb_punit_0),
{}
};
static struct field cbb_punit8[] = {
FIELD(0, cbb_punit_8),
{}
};
static struct field cbb_punit12[] = {
FIELD(0, cbb_punit_12),
{}
};
static struct field cbb_punit20[] = {
FIELD(0, cbb_punit_20),
{}
};
static char *imh_punit_0[] = {
[0x02 ... 0x03] = "Power Management Unit microcontroller double-bit ECC error",
[0x08 ... 0x09] = "Power Management Unit microcontroller error",
[0x0a] = "Power Management Unit microcontroller Patch Load error",
[0x0b] = "Power Management Unit microcontroller POReqValid error",
[0x0c] = "Power Management Unit microcontroller RAM address error",
[0x0d] = "Power Management Unit microcontroller RAM access error",
[0x10] = "If MCI_MISC.MODEL_SPECIFIC_INFORMATION is set to 1, "
"indicates Pcode Watchdog Timer expired. "
"If MCI_MISC.MODEL_SPECIFIC_INFORMATION is set to 3, "
"indicates Power Management Unit TeleSRAM double-bit ECC error detected.",
[0x20] = "Power Management Agent signaled Error",
[0x30] = "Power Management Unit Microcontroller Error",
[0xa0] = "Power Management Unit HPMSRAM double-bit ECC error detected",
[0xb0] = "Power Management Unit TPMISRAM double-bit ECC error detected",
};
static char *imh_punit_1[] = {
[0x09] = "MCA_TSC_DOWNLOAD_TIMEOUT",
[0x0a] = "MCA_INVALID_XTALFREQ_RANGE",
[0x0b] = "MCA_GPSB_TIMEOUT",
[0x0c] = "MCA_PMSB_TIMEOUT",
[0x0d] = "MCA_CFG_ACK_TIMEOUT",
[0x23] = "MCA_PCU_SVID_ERROR",
[0x35] = "MCA_SVID_LOADLINE_INVALID",
[0x36] = "MCA_SVID_ICCMAX_INVALID",
[0x4a] = "MCA_FIVR_PD_HARDERR",
[0x4c] = "MCA_HPM_DOUBLE_BIT_ERROR_DETECTED",
[0x58] = "MCA_INVALID_MEMORY_FREQUENCY",
[0x63] = "MCA_SVID_VCCIN_PROTOCOL_ERROR",
[0x6a] = "MCA_SPPR_TIMEOUT",
[0x6f] = "MCA_INVALID_SID_ERROR",
[0x70] = "MCA_INVALID_REMOTE_LEGACY_AGENT_ERROR",
[0x71] = "MCA_INVALID_REMOTE_LT_AGENT_ERROR",
[0x7b] = "MCA_THERMAL_SENSOR_INVALID",
[0x7c] = "MCA_CXL_DEVICE_NO_CREDIT",
[0x7e] = "MCA_RECOVERABLE_DIE_THERMAL_TOO_HOT",
[0x83] = "MCA_PKGS_RECOVERABLE_RESET_PREP_ACK_TIMEOUT",
};
static struct field imh_punit0[] = {
FIELD(0, imh_punit_0),
{}
};
static struct field imh_punit1[] = {
FIELD(0, imh_punit_1),
{}
};
static char *upi_0[] = {
[0x00 ... 0x02] = "Internal Parity Error",
[0x05] = "Internal Parity Error",
[0x08] = "Internal Queue Overflow Error",
[0x09] = "UPI link layer buffer overflow",
[0x0a] = "Internal Queue Underflow Error",
[0x0b] = "UPI link layer buffer underflow",
[0x0c] = "Link layer or internal credit overflow",
[0x11 ... 0x12] = "Internal Queue Overflow Error",
[0x13 ... 0x14] = "Internal Queue Underflow Error",
[0x21] = "Internal Interface Error",
[0x23] = "Invalid Message",
[0x24] = "UPI Protocol Error",
[0x25] = "UPI Interleave Error",
[0x28] = "Internal Interface Error",
[0x29] = "Link integrity or initialization error",
[0x2a ... 0x2d] = "Power Management Transition Error - Timeout",
[0x30] = "Received poison when poison is disabled",
[0x31] = "Internal Interface Error",
};
static char *upi_2[] = {
[0x00] = "Link integrity or initialization error",
[0x03] = "Link degraded",
[0x04 ... 0x07] = "Power Management Transition Error - Timeout",
};
static struct field upi0[] = {
FIELD(0, upi_0),
{}
};
static struct field upi2[] = {
FIELD(0, upi_2),
{}
};
static char *mcchan_0[] = {
[0x01] = "CMI Request Address Parity Error (APPP)",
[0x02] = "CMI Wr data parity error",
[0x04] = "CMI Wr BE parity error",
[0x08] = "Transient or Correctable Error for Patrol Reads",
[0x10] = "UnCorr Patrol Scrub Error",
[0x20] = "Nontransient or Transient ectable Error for Spare Reads",
[0x40] = "UnCorr Spare Error",
[0x80] = "Transient or Correctable Error for Demand or Underfill Reads",
[0xa0] = "Uncorrectable Error for Demand or Underfill Reads",
[0xb0] = "Poisoned Read Data when Poison Disabled",
[0xc0] = "Read 2LM MetaData Error for Demand, Underfill, or Patrol/Spare",
};
static char *mcchan_1[] = {
[0x02] = "WDB Read ECC Error",
[0x04] = "WDB BE Read Parity Error",
[0x06] = "WDB Read Persistent ECC Error",
[0x08] = "DDR Link Fail",
[0x09] = "Illegal incoming opcode",
};
static char *mcchan_2[] = {
[0x00] = "DDR CAParity or WrCRC Error",
[0x40] = "Decoder structure error",
};
static char *mcchan_4[] = {
[0x00] = "MC internal address parity error",
};
static char *mcchan_8[] = {
[0x13] = "CMI Credit Oversubscription Error",
[0x14] = "CMI Total Credit Count Error",
[0x15] = "CMI Reserved Credit Pool Error",
[0x32] = "MC Internal Errors",
[0x34] = "MC Tracker RDCMP RF parity error",
[0x36] = "MC Tracker WRCMP RF parity error",
};
static struct field mcchan0[] = {
FIELD(0, mcchan_0),
{}
};
static struct field mcchan1[] = {
FIELD(0, mcchan_1),
{}
};
static struct field mcchan2[] = {
FIELD(0, mcchan_2),
{}
};
static struct field mcchan4[] = {
FIELD(0, mcchan_4),
{}
};
static struct field mcchan8[] = {
FIELD(0, mcchan_8),
{}
};
static int diamond_imh(struct mce *m)
{
return (m->apicid >> 2) & 1;
}
static void diamond_imc_misc(u64 status, u64 misc)
{
u64 mscod = EXTRACT(status, 16, 31);
u32 column = EXTRACT(misc, 9, 18) << 2;
u32 row = EXTRACT(misc, 19, 36);
u32 bank = EXTRACT(misc, 37, 38);
u32 bankgroup = EXTRACT(misc, 39, 41);
u32 fdevice_v = EXTRACT(misc, 42, 42);
u32 fdevice = EXTRACT(misc, 44, 48);
u32 subchan = EXTRACT(misc, 49, 49);
u32 subrank = EXTRACT(misc, 51, 54);
u32 chipselect = EXTRACT(misc, 55, 56);
u32 eccmode = EXTRACT(misc, 58, 61);
u32 transient = EXTRACT(misc, 63, 63);
/* For MSCOD 0800h or above, MCi_MISC[31:9] holds proprietary error information. */
if (mscod >= 0x800)
return;
Wprintf("bank: 0x%x bankgroup: 0x%x row: 0x%x column: 0x%x\n", bank, bankgroup, row, column);
Wprintf("chipselect: 0x%x subrank: 0x%x subchan: 0x%x\n", chipselect, subrank, subchan);
if (transient) {
Wprintf("transient\n");
return;
}
if (fdevice_v)
Wprintf("failed device: 0x%x\n", fdevice);
Wprintf("ecc mode: ");
switch (eccmode) {
case 1: Wprintf("SDDC 128b 1LM\n"); break;
case 2: Wprintf("SDDC 125b 1LM\n"); break;
case 3: Wprintf("SDDC 125b 2LM\n"); break;
case 4: Wprintf("ADDDC 80b 1LM\n"); break;
case 5: Wprintf("ADDDC 80b 2LM\n"); break;
case 9: Wprintf("5x8 128b 1LM\n"); break;
case 10: Wprintf("5x8 125b 1LM\n"); break;
case 11: Wprintf("5x8 125b 2LM\n"); break;
default: Wprintf("Invalid/unknown ECC mode\n"); break;
}
}
void diamond_decode_model(int cputype, struct mce *m)
{
u64 f, status = m->status;
int imh = diamond_imh(m);
switch (m->bank) {
case 4:
Wprintf("CBB Punit: ");
if (EXTRACT(status, 0, 15) == 0x040b) {
Wprintf("Scan-at-Field Error\n");
break;
}
f = EXTRACT(status, 16, 23);
switch (EXTRACT(status, 24, 31)) {
case 0x00: decode_bitfield(f, cbb_punit0); break;
case 0x08: decode_bitfield(f, cbb_punit8); break;
case 0x0c: decode_bitfield(f, cbb_punit12); break;
case 0x14: decode_bitfield(f, cbb_punit20); break;
}
break;
case 11:
Wprintf("IMH%d Punit: ", imh);
f = EXTRACT(status, 24, 31);
if (f)
decode_bitfield(f, imh_punit1);
else
decode_bitfield(EXTRACT(status, 16, 23), imh_punit0);
break;
case 18:
Wprintf("UPI: ");
f = EXTRACT(status, 16, 23);
switch (EXTRACT(status, 24, 31)) {
case 0x00: decode_bitfield(f, upi0); break;
case 0x02: decode_bitfield(f, upi2); break;
}
break;
case 19 ... 26:
Wprintf("IMH%d MCCHAN: ", imh);
f = EXTRACT(status, 16, 23);
switch (EXTRACT(status, 24, 31)) {
case 0x00: decode_bitfield(f, mcchan0); break;
case 0x01: decode_bitfield(f, mcchan1); break;
case 0x02: decode_bitfield(f, mcchan2); break;
case 0x04: decode_bitfield(f, mcchan4); break;
case 0x08: decode_bitfield(f, mcchan8); break;
}
/* Decode MISC register if MISCV and OTHER_INFO[1] are both set. */
if (EXTRACT(status, 59, 59) && EXTRACT(status, 33, 33))
diamond_imc_misc(status, m->misc);
break;
}
}
void diamond_memerr_misc(struct mce *m, int *channel, int *dimm)
{
/* Check this is a memory error */
if (!test_prefix(7, m->status & 0xefff))
return;
if (m->bank < 19 || m->bank > 26)
return;
channel[0] = m->bank - 19 + 8 * diamond_imh(m);
}