diff options
| -rw-r--r-- | arch/x86/include/asm/mce.h | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce-inject.c | 34 |
2 files changed, 35 insertions, 8 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index b7c47a468fde..6add827381c9 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
| @@ -50,10 +50,11 @@ | |||
| 50 | #define MCJ_CTX_MASK 3 | 50 | #define MCJ_CTX_MASK 3 |
| 51 | #define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK) | 51 | #define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK) |
| 52 | #define MCJ_CTX_RANDOM 0 /* inject context: random */ | 52 | #define MCJ_CTX_RANDOM 0 /* inject context: random */ |
| 53 | #define MCJ_CTX_PROCESS 1 /* inject context: process */ | 53 | #define MCJ_CTX_PROCESS 0x1 /* inject context: process */ |
| 54 | #define MCJ_CTX_IRQ 2 /* inject context: IRQ */ | 54 | #define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */ |
| 55 | #define MCJ_NMI_BROADCAST 4 /* do NMI broadcasting */ | 55 | #define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */ |
| 56 | #define MCJ_EXCEPTION 8 /* raise as exception */ | 56 | #define MCJ_EXCEPTION 0x8 /* raise as exception */ |
| 57 | #define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */ | ||
| 57 | 58 | ||
| 58 | /* Fields are zero when not available */ | 59 | /* Fields are zero when not available */ |
| 59 | struct mce { | 60 | struct mce { |
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c index 319882ef848d..fc4beb393577 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 20 | #include <linux/preempt.h> | ||
| 20 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
| 21 | #include <linux/notifier.h> | 22 | #include <linux/notifier.h> |
| 22 | #include <linux/kdebug.h> | 23 | #include <linux/kdebug.h> |
| @@ -92,6 +93,18 @@ static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs) | |||
| 92 | return NMI_HANDLED; | 93 | return NMI_HANDLED; |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 96 | static void mce_irq_ipi(void *info) | ||
| 97 | { | ||
| 98 | int cpu = smp_processor_id(); | ||
| 99 | struct mce *m = &__get_cpu_var(injectm); | ||
| 100 | |||
| 101 | if (cpumask_test_cpu(cpu, mce_inject_cpumask) && | ||
| 102 | m->inject_flags & MCJ_EXCEPTION) { | ||
| 103 | cpumask_clear_cpu(cpu, mce_inject_cpumask); | ||
| 104 | raise_exception(m, NULL); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 95 | /* Inject mce on current CPU */ | 108 | /* Inject mce on current CPU */ |
| 96 | static int raise_local(void) | 109 | static int raise_local(void) |
| 97 | { | 110 | { |
| @@ -139,9 +152,10 @@ static void raise_mce(struct mce *m) | |||
| 139 | return; | 152 | return; |
| 140 | 153 | ||
| 141 | #ifdef CONFIG_X86_LOCAL_APIC | 154 | #ifdef CONFIG_X86_LOCAL_APIC |
| 142 | if (m->inject_flags & MCJ_NMI_BROADCAST) { | 155 | if (m->inject_flags & (MCJ_IRQ_BRAODCAST | MCJ_NMI_BROADCAST)) { |
| 143 | unsigned long start; | 156 | unsigned long start; |
| 144 | int cpu; | 157 | int cpu; |
| 158 | |||
| 145 | get_online_cpus(); | 159 | get_online_cpus(); |
| 146 | cpumask_copy(mce_inject_cpumask, cpu_online_mask); | 160 | cpumask_copy(mce_inject_cpumask, cpu_online_mask); |
| 147 | cpumask_clear_cpu(get_cpu(), mce_inject_cpumask); | 161 | cpumask_clear_cpu(get_cpu(), mce_inject_cpumask); |
| @@ -151,13 +165,25 @@ static void raise_mce(struct mce *m) | |||
| 151 | MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM) | 165 | MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM) |
| 152 | cpumask_clear_cpu(cpu, mce_inject_cpumask); | 166 | cpumask_clear_cpu(cpu, mce_inject_cpumask); |
| 153 | } | 167 | } |
| 154 | if (!cpumask_empty(mce_inject_cpumask)) | 168 | if (!cpumask_empty(mce_inject_cpumask)) { |
| 155 | apic->send_IPI_mask(mce_inject_cpumask, NMI_VECTOR); | 169 | if (m->inject_flags & MCJ_IRQ_BRAODCAST) { |
| 170 | /* | ||
| 171 | * don't wait because mce_irq_ipi is necessary | ||
| 172 | * to be sync with following raise_local | ||
| 173 | */ | ||
| 174 | preempt_disable(); | ||
| 175 | smp_call_function_many(mce_inject_cpumask, | ||
| 176 | mce_irq_ipi, NULL, 0); | ||
| 177 | preempt_enable(); | ||
| 178 | } else if (m->inject_flags & MCJ_NMI_BROADCAST) | ||
| 179 | apic->send_IPI_mask(mce_inject_cpumask, | ||
| 180 | NMI_VECTOR); | ||
| 181 | } | ||
| 156 | start = jiffies; | 182 | start = jiffies; |
| 157 | while (!cpumask_empty(mce_inject_cpumask)) { | 183 | while (!cpumask_empty(mce_inject_cpumask)) { |
| 158 | if (!time_before(jiffies, start + 2*HZ)) { | 184 | if (!time_before(jiffies, start + 2*HZ)) { |
| 159 | printk(KERN_ERR | 185 | printk(KERN_ERR |
| 160 | "Timeout waiting for mce inject NMI %lx\n", | 186 | "Timeout waiting for mce inject %lx\n", |
| 161 | *cpumask_bits(mce_inject_cpumask)); | 187 | *cpumask_bits(mce_inject_cpumask)); |
| 162 | break; | 188 | break; |
| 163 | } | 189 | } |
