diff options
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r-- | arch/x86/kernel/traps.c | 102 |
1 files changed, 51 insertions, 51 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index c76aaca5694d..b9b67166f9de 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -84,6 +84,11 @@ EXPORT_SYMBOL_GPL(used_vectors); | |||
84 | static int ignore_nmis; | 84 | static int ignore_nmis; |
85 | 85 | ||
86 | int unknown_nmi_panic; | 86 | int unknown_nmi_panic; |
87 | /* | ||
88 | * Prevent NMI reason port (0x61) being accessed simultaneously, can | ||
89 | * only be used in NMI handler. | ||
90 | */ | ||
91 | static DEFINE_RAW_SPINLOCK(nmi_reason_lock); | ||
87 | 92 | ||
88 | static inline void conditional_sti(struct pt_regs *regs) | 93 | static inline void conditional_sti(struct pt_regs *regs) |
89 | { | 94 | { |
@@ -310,15 +315,15 @@ static int __init setup_unknown_nmi_panic(char *str) | |||
310 | __setup("unknown_nmi_panic", setup_unknown_nmi_panic); | 315 | __setup("unknown_nmi_panic", setup_unknown_nmi_panic); |
311 | 316 | ||
312 | static notrace __kprobes void | 317 | static notrace __kprobes void |
313 | mem_parity_error(unsigned char reason, struct pt_regs *regs) | 318 | pci_serr_error(unsigned char reason, struct pt_regs *regs) |
314 | { | 319 | { |
315 | printk(KERN_EMERG | 320 | pr_emerg("NMI: PCI system error (SERR) for reason %02x on CPU %d.\n", |
316 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", | 321 | reason, smp_processor_id()); |
317 | reason, smp_processor_id()); | ||
318 | |||
319 | printk(KERN_EMERG | ||
320 | "You have some hardware problem, likely on the PCI bus.\n"); | ||
321 | 322 | ||
323 | /* | ||
324 | * On some machines, PCI SERR line is used to report memory | ||
325 | * errors. EDAC makes use of it. | ||
326 | */ | ||
322 | #if defined(CONFIG_EDAC) | 327 | #if defined(CONFIG_EDAC) |
323 | if (edac_handler_set()) { | 328 | if (edac_handler_set()) { |
324 | edac_atomic_assert_error(); | 329 | edac_atomic_assert_error(); |
@@ -329,11 +334,11 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs) | |||
329 | if (panic_on_unrecovered_nmi) | 334 | if (panic_on_unrecovered_nmi) |
330 | panic("NMI: Not continuing"); | 335 | panic("NMI: Not continuing"); |
331 | 336 | ||
332 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 337 | pr_emerg("Dazed and confused, but trying to continue\n"); |
333 | 338 | ||
334 | /* Clear and disable the memory parity error line. */ | 339 | /* Clear and disable the PCI SERR error line. */ |
335 | reason = (reason & 0xf) | 4; | 340 | reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_SERR; |
336 | outb(reason, 0x61); | 341 | outb(reason, NMI_REASON_PORT); |
337 | } | 342 | } |
338 | 343 | ||
339 | static notrace __kprobes void | 344 | static notrace __kprobes void |
@@ -341,15 +346,17 @@ io_check_error(unsigned char reason, struct pt_regs *regs) | |||
341 | { | 346 | { |
342 | unsigned long i; | 347 | unsigned long i; |
343 | 348 | ||
344 | printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); | 349 | pr_emerg( |
350 | "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n", | ||
351 | reason, smp_processor_id()); | ||
345 | show_registers(regs); | 352 | show_registers(regs); |
346 | 353 | ||
347 | if (panic_on_io_nmi) | 354 | if (panic_on_io_nmi) |
348 | panic("NMI IOCK error: Not continuing"); | 355 | panic("NMI IOCK error: Not continuing"); |
349 | 356 | ||
350 | /* Re-enable the IOCK line, wait for a few seconds */ | 357 | /* Re-enable the IOCK line, wait for a few seconds */ |
351 | reason = (reason & 0xf) | 8; | 358 | reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK; |
352 | outb(reason, 0x61); | 359 | outb(reason, NMI_REASON_PORT); |
353 | 360 | ||
354 | i = 20000; | 361 | i = 20000; |
355 | while (--i) { | 362 | while (--i) { |
@@ -357,8 +364,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs) | |||
357 | udelay(100); | 364 | udelay(100); |
358 | } | 365 | } |
359 | 366 | ||
360 | reason &= ~8; | 367 | reason &= ~NMI_REASON_CLEAR_IOCHK; |
361 | outb(reason, 0x61); | 368 | outb(reason, NMI_REASON_PORT); |
362 | } | 369 | } |
363 | 370 | ||
364 | static notrace __kprobes void | 371 | static notrace __kprobes void |
@@ -377,57 +384,50 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
377 | return; | 384 | return; |
378 | } | 385 | } |
379 | #endif | 386 | #endif |
380 | printk(KERN_EMERG | 387 | pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
381 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", | 388 | reason, smp_processor_id()); |
382 | reason, smp_processor_id()); | ||
383 | 389 | ||
384 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | 390 | pr_emerg("Do you have a strange power saving mode enabled?\n"); |
385 | if (unknown_nmi_panic || panic_on_unrecovered_nmi) | 391 | if (unknown_nmi_panic || panic_on_unrecovered_nmi) |
386 | panic("NMI: Not continuing"); | 392 | panic("NMI: Not continuing"); |
387 | 393 | ||
388 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 394 | pr_emerg("Dazed and confused, but trying to continue\n"); |
389 | } | 395 | } |
390 | 396 | ||
391 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | 397 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
392 | { | 398 | { |
393 | unsigned char reason = 0; | 399 | unsigned char reason = 0; |
394 | int cpu; | ||
395 | 400 | ||
396 | cpu = smp_processor_id(); | 401 | /* |
397 | 402 | * CPU-specific NMI must be processed before non-CPU-specific | |
398 | /* Only the BSP gets external NMIs from the system. */ | 403 | * NMI, otherwise we may lose it, because the CPU-specific |
399 | if (!cpu) | 404 | * NMI can not be detected/processed on other CPUs. |
400 | reason = get_nmi_reason(); | 405 | */ |
406 | if (notify_die(DIE_NMI, "nmi", regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
407 | return; | ||
401 | 408 | ||
402 | if (!(reason & 0xc0)) { | 409 | /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */ |
403 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | 410 | raw_spin_lock(&nmi_reason_lock); |
404 | == NOTIFY_STOP) | 411 | reason = get_nmi_reason(); |
405 | return; | ||
406 | 412 | ||
407 | #ifdef CONFIG_X86_LOCAL_APIC | 413 | if (reason & NMI_REASON_MASK) { |
408 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) | 414 | if (reason & NMI_REASON_SERR) |
409 | == NOTIFY_STOP) | 415 | pci_serr_error(reason, regs); |
410 | return; | 416 | else if (reason & NMI_REASON_IOCHK) |
417 | io_check_error(reason, regs); | ||
418 | #ifdef CONFIG_X86_32 | ||
419 | /* | ||
420 | * Reassert NMI in case it became active | ||
421 | * meanwhile as it's edge-triggered: | ||
422 | */ | ||
423 | reassert_nmi(); | ||
411 | #endif | 424 | #endif |
412 | unknown_nmi_error(reason, regs); | 425 | raw_spin_unlock(&nmi_reason_lock); |
413 | |||
414 | return; | 426 | return; |
415 | } | 427 | } |
416 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 428 | raw_spin_unlock(&nmi_reason_lock); |
417 | return; | ||
418 | 429 | ||
419 | /* AK: following checks seem to be broken on modern chipsets. FIXME */ | 430 | unknown_nmi_error(reason, regs); |
420 | if (reason & 0x80) | ||
421 | mem_parity_error(reason, regs); | ||
422 | if (reason & 0x40) | ||
423 | io_check_error(reason, regs); | ||
424 | #ifdef CONFIG_X86_32 | ||
425 | /* | ||
426 | * Reassert NMI in case it became active meanwhile | ||
427 | * as it's edge-triggered: | ||
428 | */ | ||
429 | reassert_nmi(); | ||
430 | #endif | ||
431 | } | 431 | } |
432 | 432 | ||
433 | dotraplinkage notrace __kprobes void | 433 | dotraplinkage notrace __kprobes void |