@@ -180,6 +180,23 @@ static struct smca_hwid smca_hwid_mcatypes[] = {
struct smca_bank smca_banks[MAX_NR_BANKS];
EXPORT_SYMBOL_GPL(smca_banks);
+/*
+ * Zen-based Instruction Fetch Units set EIPV=RIPV=0 on poison consumption
+ * errors (XEC = 12). However, the context is still valid, so save the CS
+ * register for later use.
+ */
+void quirk_zen_ifu(int bank, struct mce *m, struct pt_regs *regs)
+{
+ if (smca_get_bank_type(bank) != SMCA_IF)
+ return;
+ if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0)
+ return;
+ if (((m->status >> 16) & 0x1F) != 12)
+ return;
+
+ m->cs = regs->cs;
+}
+
/*
* In SMCA enabled processors, we can have multiple banks for a given IP type.
* So to define a unique name for each bank, we use a temp c-string to append
@@ -1754,6 +1754,13 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
if (c->x86 == 0x15 && c->x86_model <= 0xf)
mce_flags.overflow_recov = 1;
+ if (c->x86 == 0x17 || c->x86 == 0x19)
+ quirk_no_way_out = quirk_zen_ifu;
+ }
+
+ if (c->x86_vendor == X86_VENDOR_HYGON) {
+ if (c->x86 == 0x18)
+ quirk_no_way_out = quirk_zen_ifu;
}
if (c->x86_vendor == X86_VENDOR_INTEL) {
@@ -181,8 +181,10 @@ extern struct mca_msr_regs msr_ops;
extern bool filter_mce(struct mce *m);
#ifdef CONFIG_X86_MCE_AMD
+extern void quirk_zen_ifu(int bank, struct mce *m, struct pt_regs *regs);
extern bool amd_filter_mce(struct mce *m);
#else
+#define quirk_zen_ifu NULL
static inline bool amd_filter_mce(struct mce *m) { return false; };
#endif