]>
Commit | Line | Data |
---|---|---|
1fb9d6ad DZ |
1 | /* |
2 | * HW NMI watchdog support | |
3 | * | |
4 | * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. | |
5 | * | |
6 | * Arch specific calls to support NMI watchdog | |
7 | * | |
8 | * Bits copied from original nmi.c file | |
9 | * | |
10 | */ | |
5e85391b | 11 | #include <asm/apic.h> |
1fb9d6ad | 12 | |
1fb9d6ad | 13 | #include <linux/cpumask.h> |
7cbb7e7f DZ |
14 | #include <linux/kdebug.h> |
15 | #include <linux/notifier.h> | |
16 | #include <linux/kprobes.h> | |
1fb9d6ad DZ |
17 | #include <linux/nmi.h> |
18 | #include <linux/module.h> | |
19 | ||
20 | /* For reliability, we're prepared to waste bits here. */ | |
21 | static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; | |
22 | ||
504d7cf1 DZ |
23 | u64 hw_nmi_get_sample_period(void) |
24 | { | |
58687acb | 25 | return (u64)(cpu_khz) * 1000 * 60; |
504d7cf1 DZ |
26 | } |
27 | ||
2cc4452b | 28 | #ifdef ARCH_HAS_NMI_WATCHDOG |
1fb9d6ad DZ |
29 | void arch_trigger_all_cpu_backtrace(void) |
30 | { | |
31 | int i; | |
32 | ||
33 | cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); | |
34 | ||
35 | printk(KERN_INFO "sending NMI to all CPUs:\n"); | |
36 | apic->send_IPI_all(NMI_VECTOR); | |
37 | ||
38 | /* Wait for up to 10 seconds for all CPUs to do the backtrace */ | |
39 | for (i = 0; i < 10 * 1000; i++) { | |
40 | if (cpumask_empty(to_cpumask(backtrace_mask))) | |
41 | break; | |
42 | mdelay(1); | |
43 | } | |
44 | } | |
7cbb7e7f DZ |
45 | |
46 | static int __kprobes | |
47 | arch_trigger_all_cpu_backtrace_handler(struct notifier_block *self, | |
48 | unsigned long cmd, void *__args) | |
49 | { | |
50 | struct die_args *args = __args; | |
51 | struct pt_regs *regs; | |
52 | int cpu = smp_processor_id(); | |
53 | ||
54 | switch (cmd) { | |
55 | case DIE_NMI: | |
56 | case DIE_NMI_IPI: | |
57 | break; | |
58 | ||
59 | default: | |
60 | return NOTIFY_DONE; | |
61 | } | |
62 | ||
63 | regs = args->regs; | |
64 | ||
65 | if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { | |
66 | static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED; | |
67 | ||
68 | arch_spin_lock(&lock); | |
69 | printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); | |
70 | show_regs(regs); | |
71 | dump_stack(); | |
72 | arch_spin_unlock(&lock); | |
73 | cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); | |
74 | return NOTIFY_STOP; | |
75 | } | |
76 | ||
77 | return NOTIFY_DONE; | |
78 | } | |
79 | ||
80 | static __read_mostly struct notifier_block backtrace_notifier = { | |
81 | .notifier_call = arch_trigger_all_cpu_backtrace_handler, | |
82 | .next = NULL, | |
83 | .priority = 1 | |
84 | }; | |
85 | ||
86 | static int __init register_trigger_all_cpu_backtrace(void) | |
87 | { | |
88 | register_die_notifier(&backtrace_notifier); | |
89 | return 0; | |
90 | } | |
91 | early_initcall(register_trigger_all_cpu_backtrace); | |
2cc4452b | 92 | #endif |
1fb9d6ad DZ |
93 | |
94 | /* STUB calls to mimic old nmi_watchdog behaviour */ | |
504d7cf1 | 95 | #if defined(CONFIG_X86_LOCAL_APIC) |
1fb9d6ad DZ |
96 | unsigned int nmi_watchdog = NMI_NONE; |
97 | EXPORT_SYMBOL(nmi_watchdog); | |
504d7cf1 DZ |
98 | void acpi_nmi_enable(void) { return; } |
99 | void acpi_nmi_disable(void) { return; } | |
100 | #endif | |
1fb9d6ad DZ |
101 | atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ |
102 | EXPORT_SYMBOL(nmi_active); | |
1fb9d6ad DZ |
103 | int unknown_nmi_panic; |
104 | void cpu_nmi_set_wd_enabled(void) { return; } | |
1fb9d6ad DZ |
105 | void stop_apic_nmi_watchdog(void *unused) { return; } |
106 | void setup_apic_nmi_watchdog(void *unused) { return; } | |
107 | int __init check_nmi_watchdog(void) { return 0; } |