diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck/mce_amd_64.c')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_amd_64.c | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c index 9817506dd469..7d01be868870 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c | |||
@@ -79,6 +79,8 @@ static unsigned char shared_bank[NR_BANKS] = { | |||
79 | 79 | ||
80 | static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */ | 80 | static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */ |
81 | 81 | ||
82 | static void amd_threshold_interrupt(void); | ||
83 | |||
82 | /* | 84 | /* |
83 | * CPU Initialization | 85 | * CPU Initialization |
84 | */ | 86 | */ |
@@ -90,7 +92,8 @@ struct thresh_restart { | |||
90 | }; | 92 | }; |
91 | 93 | ||
92 | /* must be called with correct cpu affinity */ | 94 | /* must be called with correct cpu affinity */ |
93 | static long threshold_restart_bank(void *_tr) | 95 | /* Called via smp_call_function_single() */ |
96 | static void threshold_restart_bank(void *_tr) | ||
94 | { | 97 | { |
95 | struct thresh_restart *tr = _tr; | 98 | struct thresh_restart *tr = _tr; |
96 | u32 mci_misc_hi, mci_misc_lo; | 99 | u32 mci_misc_hi, mci_misc_lo; |
@@ -117,7 +120,6 @@ static long threshold_restart_bank(void *_tr) | |||
117 | 120 | ||
118 | mci_misc_hi |= MASK_COUNT_EN_HI; | 121 | mci_misc_hi |= MASK_COUNT_EN_HI; |
119 | wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi); | 122 | wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi); |
120 | return 0; | ||
121 | } | 123 | } |
122 | 124 | ||
123 | /* cpu init entry point, called from mce.c with preempt off */ | 125 | /* cpu init entry point, called from mce.c with preempt off */ |
@@ -174,6 +176,8 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) | |||
174 | tr.reset = 0; | 176 | tr.reset = 0; |
175 | tr.old_limit = 0; | 177 | tr.old_limit = 0; |
176 | threshold_restart_bank(&tr); | 178 | threshold_restart_bank(&tr); |
179 | |||
180 | mce_threshold_vector = amd_threshold_interrupt; | ||
177 | } | 181 | } |
178 | } | 182 | } |
179 | } | 183 | } |
@@ -187,19 +191,13 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) | |||
187 | * the interrupt goes off when error_count reaches threshold_limit. | 191 | * the interrupt goes off when error_count reaches threshold_limit. |
188 | * the handler will simply log mcelog w/ software defined bank number. | 192 | * the handler will simply log mcelog w/ software defined bank number. |
189 | */ | 193 | */ |
190 | asmlinkage void mce_threshold_interrupt(void) | 194 | static void amd_threshold_interrupt(void) |
191 | { | 195 | { |
192 | unsigned int bank, block; | 196 | unsigned int bank, block; |
193 | struct mce m; | 197 | struct mce m; |
194 | u32 low = 0, high = 0, address = 0; | 198 | u32 low = 0, high = 0, address = 0; |
195 | 199 | ||
196 | ack_APIC_irq(); | 200 | mce_setup(&m); |
197 | exit_idle(); | ||
198 | irq_enter(); | ||
199 | |||
200 | memset(&m, 0, sizeof(m)); | ||
201 | rdtscll(m.tsc); | ||
202 | m.cpu = smp_processor_id(); | ||
203 | 201 | ||
204 | /* assume first bank caused it */ | 202 | /* assume first bank caused it */ |
205 | for (bank = 0; bank < NR_BANKS; ++bank) { | 203 | for (bank = 0; bank < NR_BANKS; ++bank) { |
@@ -233,7 +231,8 @@ asmlinkage void mce_threshold_interrupt(void) | |||
233 | 231 | ||
234 | /* Log the machine check that caused the threshold | 232 | /* Log the machine check that caused the threshold |
235 | event. */ | 233 | event. */ |
236 | do_machine_check(NULL, 0); | 234 | machine_check_poll(MCP_TIMESTAMP, |
235 | &__get_cpu_var(mce_poll_banks)); | ||
237 | 236 | ||
238 | if (high & MASK_OVERFLOW_HI) { | 237 | if (high & MASK_OVERFLOW_HI) { |
239 | rdmsrl(address, m.misc); | 238 | rdmsrl(address, m.misc); |
@@ -243,13 +242,10 @@ asmlinkage void mce_threshold_interrupt(void) | |||
243 | + bank * NR_BLOCKS | 242 | + bank * NR_BLOCKS |
244 | + block; | 243 | + block; |
245 | mce_log(&m); | 244 | mce_log(&m); |
246 | goto out; | 245 | return; |
247 | } | 246 | } |
248 | } | 247 | } |
249 | } | 248 | } |
250 | out: | ||
251 | inc_irq_stat(irq_threshold_count); | ||
252 | irq_exit(); | ||
253 | } | 249 | } |
254 | 250 | ||
255 | /* | 251 | /* |
@@ -283,7 +279,7 @@ static ssize_t store_interrupt_enable(struct threshold_block *b, | |||
283 | tr.b = b; | 279 | tr.b = b; |
284 | tr.reset = 0; | 280 | tr.reset = 0; |
285 | tr.old_limit = 0; | 281 | tr.old_limit = 0; |
286 | work_on_cpu(b->cpu, threshold_restart_bank, &tr); | 282 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); |
287 | 283 | ||
288 | return end - buf; | 284 | return end - buf; |
289 | } | 285 | } |
@@ -305,23 +301,32 @@ static ssize_t store_threshold_limit(struct threshold_block *b, | |||
305 | tr.b = b; | 301 | tr.b = b; |
306 | tr.reset = 0; | 302 | tr.reset = 0; |
307 | 303 | ||
308 | work_on_cpu(b->cpu, threshold_restart_bank, &tr); | 304 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); |
309 | 305 | ||
310 | return end - buf; | 306 | return end - buf; |
311 | } | 307 | } |
312 | 308 | ||
313 | static long local_error_count(void *_b) | 309 | struct threshold_block_cross_cpu { |
310 | struct threshold_block *tb; | ||
311 | long retval; | ||
312 | }; | ||
313 | |||
314 | static void local_error_count_handler(void *_tbcc) | ||
314 | { | 315 | { |
315 | struct threshold_block *b = _b; | 316 | struct threshold_block_cross_cpu *tbcc = _tbcc; |
317 | struct threshold_block *b = tbcc->tb; | ||
316 | u32 low, high; | 318 | u32 low, high; |
317 | 319 | ||
318 | rdmsr(b->address, low, high); | 320 | rdmsr(b->address, low, high); |
319 | return (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit); | 321 | tbcc->retval = (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit); |
320 | } | 322 | } |
321 | 323 | ||
322 | static ssize_t show_error_count(struct threshold_block *b, char *buf) | 324 | static ssize_t show_error_count(struct threshold_block *b, char *buf) |
323 | { | 325 | { |
324 | return sprintf(buf, "%lx\n", work_on_cpu(b->cpu, local_error_count, b)); | 326 | struct threshold_block_cross_cpu tbcc = { .tb = b, }; |
327 | |||
328 | smp_call_function_single(b->cpu, local_error_count_handler, &tbcc, 1); | ||
329 | return sprintf(buf, "%lx\n", tbcc.retval); | ||
325 | } | 330 | } |
326 | 331 | ||
327 | static ssize_t store_error_count(struct threshold_block *b, | 332 | static ssize_t store_error_count(struct threshold_block *b, |
@@ -329,7 +334,7 @@ static ssize_t store_error_count(struct threshold_block *b, | |||
329 | { | 334 | { |
330 | struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 }; | 335 | struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 }; |
331 | 336 | ||
332 | work_on_cpu(b->cpu, threshold_restart_bank, &tr); | 337 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); |
333 | return 1; | 338 | return 1; |
334 | } | 339 | } |
335 | 340 | ||
@@ -398,7 +403,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, | |||
398 | if ((bank >= NR_BANKS) || (block >= NR_BLOCKS)) | 403 | if ((bank >= NR_BANKS) || (block >= NR_BLOCKS)) |
399 | return 0; | 404 | return 0; |
400 | 405 | ||
401 | if (rdmsr_safe(address, &low, &high)) | 406 | if (rdmsr_safe_on_cpu(cpu, address, &low, &high)) |
402 | return 0; | 407 | return 0; |
403 | 408 | ||
404 | if (!(high & MASK_VALID_HI)) { | 409 | if (!(high & MASK_VALID_HI)) { |
@@ -462,12 +467,11 @@ out_free: | |||
462 | return err; | 467 | return err; |
463 | } | 468 | } |
464 | 469 | ||
465 | static __cpuinit long local_allocate_threshold_blocks(void *_bank) | 470 | static __cpuinit long |
471 | local_allocate_threshold_blocks(int cpu, unsigned int bank) | ||
466 | { | 472 | { |
467 | unsigned int *bank = _bank; | 473 | return allocate_threshold_blocks(cpu, bank, 0, |
468 | 474 | MSR_IA32_MC0_MISC + bank * 4); | |
469 | return allocate_threshold_blocks(smp_processor_id(), *bank, 0, | ||
470 | MSR_IA32_MC0_MISC + *bank * 4); | ||
471 | } | 475 | } |
472 | 476 | ||
473 | /* symlinks sibling shared banks to first core. first core owns dir/files. */ | 477 | /* symlinks sibling shared banks to first core. first core owns dir/files. */ |
@@ -530,7 +534,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) | |||
530 | 534 | ||
531 | per_cpu(threshold_banks, cpu)[bank] = b; | 535 | per_cpu(threshold_banks, cpu)[bank] = b; |
532 | 536 | ||
533 | err = work_on_cpu(cpu, local_allocate_threshold_blocks, &bank); | 537 | err = local_allocate_threshold_blocks(cpu, bank); |
534 | if (err) | 538 | if (err) |
535 | goto out_free; | 539 | goto out_free; |
536 | 540 | ||