diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c --- a/sys/x86/x86/mca.c +++ b/sys/x86/x86/mca.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +144,11 @@ "Bank to use for artificial MCAs (testing purpose only)"); #endif +static bool mca_uselog = false; +SYSCTL_BOOL(_hw_mca, OID_AUTO, uselog, CTLFLAG_RWTUN, &mca_uselog, 0, + "Should the system send non-fatal machine check errors to the log " + "(instead of the console)?"); + static STAILQ_HEAD(, mca_internal) mca_freelist; static int mca_freecount; static STAILQ_HEAD(, mca_internal) mca_records; @@ -472,17 +478,20 @@ /* Dump details about a single machine check. */ static void -mca_log(enum scan_mode mode, const struct mca_record *rec) +mca_log(enum scan_mode mode, const struct mca_record *rec, bool fatal) { int numskipped; uint16_t mca_error; enum mca_stat_types event_type; struct sbuf sb; char buf[128]; + bool uncor; if (mca_mute(rec)) return; + uncor = false; + if (mode == POLLED) { if (sbuf_new(&sb, NULL, 512, SBUF_AUTOEXTEND) == NULL) { printf("MCA: error logging message (sbuf alloc)\n"); @@ -505,9 +514,10 @@ sbuf_printf(&sb, "MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); sbuf_printf(&sb, "MCA: CPU %d ", rec->mr_cpu); - if (rec->mr_status & MC_STATUS_UC) + if (rec->mr_status & MC_STATUS_UC) { + uncor = true; sbuf_printf(&sb, "UNCOR "); - else { + } else { sbuf_printf(&sb, "COR "); if (cmci_supported(rec->mr_mcg_cap)) sbuf_printf(&sb, "(%lld) ", ((long long)rec->mr_status & @@ -708,7 +718,8 @@ event_type)); event_type = MCA_T_UNKNOWN; } - if (!(rec->mr_status & MC_STATUS_UC)) { + numskipped = 0; + if (!fatal) { mtx_lock_spin(&mca_lock); mca_stats[event_type]++; if (mode != POLLED) { @@ -724,16 +735,27 @@ numskipped = mca_log_skipped; mca_log_skipped = 0; mtx_unlock_spin(&mca_lock); - if (numskipped > 0) - printf("MCA: %d events skipped due to rate limit\n", - numskipped); } else if (mode != POLLED) goto done; - if (sbuf_error(&sb)) - printf("MCA: error logging message (sbuf error)\n"); - else - sbuf_putbuf(&sb); + if (fatal || !mca_uselog) { + if (numskipped > 0 && !fatal) + printf("MCA: %d events skipped due to rate limit\n", + numskipped); + if (sbuf_error(&sb)) + printf("MCA: error logging message (sbuf error)\n"); + else + sbuf_putbuf(&sb); + } else { + if (numskipped > 0) + log(LOG_ERR, "MCA: %d events skipped due to rate" + " limit\n", numskipped); + if (sbuf_error(&sb)) + log(LOG_ERR, + "MCA: error logging message (sbuf error)\n"); + else + log(uncor ? LOG_CRIT : LOG_ERR, "%s", sbuf_data(&sb)); + } done: sbuf_delete(&sb); @@ -897,7 +919,7 @@ if (rec == NULL) { mtx_unlock_spin(&mca_lock); printf("MCA: Unable to allocate space for an event.\n"); - mca_log(mode, record); + mca_log(mode, record, false); return; } STAILQ_REMOVE_HEAD(&mca_freelist, link); @@ -1054,7 +1076,7 @@ if (*recoverablep) mca_record_entry(mode, &rec); else - mca_log(mode, &rec); + mca_log(mode, &rec, true); } #ifdef DEV_APIC @@ -1138,7 +1160,7 @@ mtx_unlock_spin(&mca_lock); STAILQ_FOREACH(mca, &tmplist, link) - mca_log(mode, &mca->rec); + mca_log(mode, &mca->rec, false); mtx_lock_spin(&mca_lock); while ((mca = STAILQ_FIRST(&tmplist)) != NULL) {