diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-17 07:24:52 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-17 07:24:52 -0500 |
commit | 855caa37b9b61c1ccfeb91a2bc04d90bfc5e4525 (patch) | |
tree | f95e80165c293f43321b17c4280acfca478d9ba8 /arch/x86/kernel/reboot.c | |
parent | 948a7b2b5e2bf126fb697aeb11ff379b2c85dd2e (diff) | |
parent | c415b3dce30dfb41234e118662e8720f47343a4f (diff) |
Merge branch 'x86/crashdump' into cpus4096
Conflicts:
arch/x86/kernel/crash.c
Merged for semantic conflict:
arch/x86/kernel/reboot.c
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r-- | arch/x86/kernel/reboot.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 0e3dbc7b2bdb..ba7b9a0e6063 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -21,6 +21,9 @@ | |||
21 | # include <asm/iommu.h> | 21 | # include <asm/iommu.h> |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #include <mach_ipi.h> | ||
25 | |||
26 | |||
24 | /* | 27 | /* |
25 | * Power off function, if any | 28 | * Power off function, if any |
26 | */ | 29 | */ |
@@ -548,3 +551,92 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
548 | machine_ops.crash_shutdown(regs); | 551 | machine_ops.crash_shutdown(regs); |
549 | } | 552 | } |
550 | #endif | 553 | #endif |
554 | |||
555 | |||
556 | #if defined(CONFIG_SMP) | ||
557 | |||
558 | /* This keeps a track of which one is crashing cpu. */ | ||
559 | static int crashing_cpu; | ||
560 | static nmi_shootdown_cb shootdown_callback; | ||
561 | |||
562 | static atomic_t waiting_for_crash_ipi; | ||
563 | |||
564 | static int crash_nmi_callback(struct notifier_block *self, | ||
565 | unsigned long val, void *data) | ||
566 | { | ||
567 | int cpu; | ||
568 | |||
569 | if (val != DIE_NMI_IPI) | ||
570 | return NOTIFY_OK; | ||
571 | |||
572 | cpu = raw_smp_processor_id(); | ||
573 | |||
574 | /* Don't do anything if this handler is invoked on crashing cpu. | ||
575 | * Otherwise, system will completely hang. Crashing cpu can get | ||
576 | * an NMI if system was initially booted with nmi_watchdog parameter. | ||
577 | */ | ||
578 | if (cpu == crashing_cpu) | ||
579 | return NOTIFY_STOP; | ||
580 | local_irq_disable(); | ||
581 | |||
582 | shootdown_callback(cpu, (struct die_args *)data); | ||
583 | |||
584 | atomic_dec(&waiting_for_crash_ipi); | ||
585 | /* Assume hlt works */ | ||
586 | halt(); | ||
587 | for (;;) | ||
588 | cpu_relax(); | ||
589 | |||
590 | return 1; | ||
591 | } | ||
592 | |||
593 | static void smp_send_nmi_allbutself(void) | ||
594 | { | ||
595 | send_IPI_allbutself(NMI_VECTOR); | ||
596 | } | ||
597 | |||
598 | static struct notifier_block crash_nmi_nb = { | ||
599 | .notifier_call = crash_nmi_callback, | ||
600 | }; | ||
601 | |||
602 | /* Halt all other CPUs, calling the specified function on each of them | ||
603 | * | ||
604 | * This function can be used to halt all other CPUs on crash | ||
605 | * or emergency reboot time. The function passed as parameter | ||
606 | * will be called inside a NMI handler on all CPUs. | ||
607 | */ | ||
608 | void nmi_shootdown_cpus(nmi_shootdown_cb callback) | ||
609 | { | ||
610 | unsigned long msecs; | ||
611 | local_irq_disable(); | ||
612 | |||
613 | /* Make a note of crashing cpu. Will be used in NMI callback.*/ | ||
614 | crashing_cpu = safe_smp_processor_id(); | ||
615 | |||
616 | shootdown_callback = callback; | ||
617 | |||
618 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | ||
619 | /* Would it be better to replace the trap vector here? */ | ||
620 | if (register_die_notifier(&crash_nmi_nb)) | ||
621 | return; /* return what? */ | ||
622 | /* Ensure the new callback function is set before sending | ||
623 | * out the NMI | ||
624 | */ | ||
625 | wmb(); | ||
626 | |||
627 | smp_send_nmi_allbutself(); | ||
628 | |||
629 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ | ||
630 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { | ||
631 | mdelay(1); | ||
632 | msecs--; | ||
633 | } | ||
634 | |||
635 | /* Leave the nmi callback set */ | ||
636 | } | ||
637 | #else /* !CONFIG_SMP */ | ||
638 | void nmi_shootdown_cpus(nmi_shootdown_cb callback) | ||
639 | { | ||
640 | /* No other CPUs to shoot down */ | ||
641 | } | ||
642 | #endif | ||