]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/x86/kernel/cpu/mcheck/mce-inject.c
x86: add IRQ context simulation in module mce-inject
[karo-tx-linux.git] / arch / x86 / kernel / cpu / mcheck / mce-inject.c
index 319882ef848d3cd43c0a4dcfa41ea14cd09502ab..fc4beb3935771eab1b404b3333cdb7842dac7c5c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/fs.h>
+#include <linux/preempt.h>
 #include <linux/smp.h>
 #include <linux/notifier.h>
 #include <linux/kdebug.h>
@@ -92,6 +93,18 @@ static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs)
        return NMI_HANDLED;
 }
 
+static void mce_irq_ipi(void *info)
+{
+       int cpu = smp_processor_id();
+       struct mce *m = &__get_cpu_var(injectm);
+
+       if (cpumask_test_cpu(cpu, mce_inject_cpumask) &&
+                       m->inject_flags & MCJ_EXCEPTION) {
+               cpumask_clear_cpu(cpu, mce_inject_cpumask);
+               raise_exception(m, NULL);
+       }
+}
+
 /* Inject mce on current CPU */
 static int raise_local(void)
 {
@@ -139,9 +152,10 @@ static void raise_mce(struct mce *m)
                return;
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       if (m->inject_flags & MCJ_NMI_BROADCAST) {
+       if (m->inject_flags & (MCJ_IRQ_BRAODCAST | MCJ_NMI_BROADCAST)) {
                unsigned long start;
                int cpu;
+
                get_online_cpus();
                cpumask_copy(mce_inject_cpumask, cpu_online_mask);
                cpumask_clear_cpu(get_cpu(), mce_inject_cpumask);
@@ -151,13 +165,25 @@ static void raise_mce(struct mce *m)
                            MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM)
                                cpumask_clear_cpu(cpu, mce_inject_cpumask);
                }
-               if (!cpumask_empty(mce_inject_cpumask))
-                       apic->send_IPI_mask(mce_inject_cpumask, NMI_VECTOR);
+               if (!cpumask_empty(mce_inject_cpumask)) {
+                       if (m->inject_flags & MCJ_IRQ_BRAODCAST) {
+                               /*
+                                * don't wait because mce_irq_ipi is necessary
+                                * to be sync with following raise_local
+                                */
+                               preempt_disable();
+                               smp_call_function_many(mce_inject_cpumask,
+                                       mce_irq_ipi, NULL, 0);
+                               preempt_enable();
+                       } else if (m->inject_flags & MCJ_NMI_BROADCAST)
+                               apic->send_IPI_mask(mce_inject_cpumask,
+                                               NMI_VECTOR);
+               }
                start = jiffies;
                while (!cpumask_empty(mce_inject_cpumask)) {
                        if (!time_before(jiffies, start + 2*HZ)) {
                                printk(KERN_ERR
-                               "Timeout waiting for mce inject NMI %lx\n",
+                               "Timeout waiting for mce inject %lx\n",
                                        *cpumask_bits(mce_inject_cpumask));
                                break;
                        }