diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-12-18 03:18:45 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-12-18 03:18:45 -0500 |
commit | a228b5892b0527b8574c06edc72cacaf8c25418d (patch) | |
tree | 0b70c47c07fad1a18301e63be52e8252d16c0af5 | |
parent | 715a43182a20a9e2bae59b4e0826a91ee30f355c (diff) | |
parent | 2c29d9dd577b74b44e580f957ea44d1df73af23a (diff) |
Merge branch 'mce-inject' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras into x86/mce
-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 | } |