|
@@ -207,8 +207,12 @@ EXPORT_SYMBOL_GPL(mce_inject_log);
|
|
|
|
|
|
static struct notifier_block mce_srao_nb;
|
|
|
|
|
|
+static atomic_t num_notifiers;
|
|
|
+
|
|
|
void mce_register_decode_chain(struct notifier_block *nb)
|
|
|
{
|
|
|
+ atomic_inc(&num_notifiers);
|
|
|
+
|
|
|
/* Ensure SRAO notifier has the highest priority in the decode chain. */
|
|
|
if (nb != &mce_srao_nb && nb->priority == INT_MAX)
|
|
|
nb->priority -= 1;
|
|
@@ -219,6 +223,8 @@ EXPORT_SYMBOL_GPL(mce_register_decode_chain);
|
|
|
|
|
|
void mce_unregister_decode_chain(struct notifier_block *nb)
|
|
|
{
|
|
|
+ atomic_dec(&num_notifiers);
|
|
|
+
|
|
|
atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
|
|
@@ -270,17 +276,17 @@ struct mca_msr_regs msr_ops = {
|
|
|
.misc = misc_reg
|
|
|
};
|
|
|
|
|
|
-static void print_mce(struct mce *m)
|
|
|
+static void __print_mce(struct mce *m)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
|
|
|
- m->extcpu, m->mcgstatus, m->bank, m->status);
|
|
|
+ pr_emerg(HW_ERR "CPU %d: Machine Check%s: %Lx Bank %d: %016Lx\n",
|
|
|
+ m->extcpu,
|
|
|
+ (m->mcgstatus & MCG_STATUS_MCIP ? " Exception" : ""),
|
|
|
+ m->mcgstatus, m->bank, m->status);
|
|
|
|
|
|
if (m->ip) {
|
|
|
pr_emerg(HW_ERR "RIP%s %02x:<%016Lx> ",
|
|
|
!(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
|
|
|
- m->cs, m->ip);
|
|
|
+ m->cs, m->ip);
|
|
|
|
|
|
if (m->cs == __KERNEL_CS)
|
|
|
print_symbol("{%s}", m->ip);
|
|
@@ -308,6 +314,13 @@ static void print_mce(struct mce *m)
|
|
|
pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
|
|
|
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
|
|
|
cpu_data(m->extcpu).microcode);
|
|
|
+}
|
|
|
+
|
|
|
+static void print_mce(struct mce *m)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ __print_mce(m);
|
|
|
|
|
|
/*
|
|
|
* Print out human-readable details about the MCE error,
|
|
@@ -569,6 +582,32 @@ static struct notifier_block mce_srao_nb = {
|
|
|
.priority = INT_MAX,
|
|
|
};
|
|
|
|
|
|
+static int mce_default_notifier(struct notifier_block *nb, unsigned long val,
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct mce *m = (struct mce *)data;
|
|
|
+
|
|
|
+ if (!m)
|
|
|
+ return NOTIFY_DONE;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Run the default notifier if we have only the SRAO
|
|
|
+ * notifier and us registered.
|
|
|
+ */
|
|
|
+ if (atomic_read(&num_notifiers) > 2)
|
|
|
+ return NOTIFY_DONE;
|
|
|
+
|
|
|
+ __print_mce(m);
|
|
|
+
|
|
|
+ return NOTIFY_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+static struct notifier_block mce_default_nb = {
|
|
|
+ .notifier_call = mce_default_notifier,
|
|
|
+ /* lowest prio, we want it to run last. */
|
|
|
+ .priority = 0,
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Read ADDR and MISC registers.
|
|
|
*/
|
|
@@ -2138,6 +2177,7 @@ int __init mcheck_init(void)
|
|
|
{
|
|
|
mcheck_intel_therm_init();
|
|
|
mce_register_decode_chain(&mce_srao_nb);
|
|
|
+ mce_register_decode_chain(&mce_default_nb);
|
|
|
mcheck_vendor_init_severity();
|
|
|
|
|
|
INIT_WORK(&mce_work, mce_process_work);
|