diff options
author | Don Zickus <dzickus@redhat.com> | 2010-02-12 17:19:19 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-14 03:19:43 -0500 |
commit | 504d7cf10ee42bb76b9556859f23d4121dee0a77 (patch) | |
tree | edaa43a7c221f0926d150dbbeb38abc5fe0f1cc6 | |
parent | c3128fb6ad39b0edda6675d20585a64846cf89ea (diff) |
nmi_watchdog: Compile and portability fixes
The original patch was x86_64 centric. Changed the code to make
it less so.
ested by building and running on a powerpc.
Signed-off-by: Don Zickus <dzickus@redhat.com>
Cc: peterz@infradead.org
Cc: gorcunov@gmail.com
Cc: aris@redhat.com
LKML-Reference: <1266013161-31197-2-git-send-email-dzickus@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/include/asm/nmi.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/hw_nmi.c | 21 | ||||
-rw-r--r-- | include/linux/nmi.h | 9 | ||||
-rw-r--r-- | kernel/nmi_watchdog.c | 52 | ||||
-rw-r--r-- | kernel/sysctl.c | 15 |
5 files changed, 82 insertions, 17 deletions
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index 93da9c3f3341..5b41b0feb6db 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h | |||
@@ -17,7 +17,9 @@ int do_nmi_callback(struct pt_regs *regs, int cpu); | |||
17 | 17 | ||
18 | extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); | 18 | extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); |
19 | extern int check_nmi_watchdog(void); | 19 | extern int check_nmi_watchdog(void); |
20 | #if !defined(CONFIG_NMI_WATCHDOG) | ||
20 | extern int nmi_watchdog_enabled; | 21 | extern int nmi_watchdog_enabled; |
22 | #endif | ||
21 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); | 23 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); |
22 | extern int reserve_perfctr_nmi(unsigned int); | 24 | extern int reserve_perfctr_nmi(unsigned int); |
23 | extern void release_perfctr_nmi(unsigned int); | 25 | extern void release_perfctr_nmi(unsigned int); |
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 8c0e6a410d05..312d772c5c35 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c | |||
@@ -32,8 +32,13 @@ static DEFINE_PER_CPU(unsigned, last_irq_sum); | |||
32 | */ | 32 | */ |
33 | static inline unsigned int get_timer_irqs(int cpu) | 33 | static inline unsigned int get_timer_irqs(int cpu) |
34 | { | 34 | { |
35 | return per_cpu(irq_stat, cpu).apic_timer_irqs + | 35 | unsigned int irqs = per_cpu(irq_stat, cpu).irq0_irqs; |
36 | per_cpu(irq_stat, cpu).irq0_irqs; | 36 | |
37 | #if defined(CONFIG_X86_LOCAL_APIC) | ||
38 | irqs += per_cpu(irq_stat, cpu).apic_timer_irqs; | ||
39 | #endif | ||
40 | |||
41 | return irqs; | ||
37 | } | 42 | } |
38 | 43 | ||
39 | static inline int mce_in_progress(void) | 44 | static inline int mce_in_progress(void) |
@@ -82,6 +87,11 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) | |||
82 | } | 87 | } |
83 | } | 88 | } |
84 | 89 | ||
90 | u64 hw_nmi_get_sample_period(void) | ||
91 | { | ||
92 | return cpu_khz * 1000; | ||
93 | } | ||
94 | |||
85 | void arch_trigger_all_cpu_backtrace(void) | 95 | void arch_trigger_all_cpu_backtrace(void) |
86 | { | 96 | { |
87 | int i; | 97 | int i; |
@@ -100,15 +110,16 @@ void arch_trigger_all_cpu_backtrace(void) | |||
100 | } | 110 | } |
101 | 111 | ||
102 | /* STUB calls to mimic old nmi_watchdog behaviour */ | 112 | /* STUB calls to mimic old nmi_watchdog behaviour */ |
113 | #if defined(CONFIG_X86_LOCAL_APIC) | ||
103 | unsigned int nmi_watchdog = NMI_NONE; | 114 | unsigned int nmi_watchdog = NMI_NONE; |
104 | EXPORT_SYMBOL(nmi_watchdog); | 115 | EXPORT_SYMBOL(nmi_watchdog); |
116 | void acpi_nmi_enable(void) { return; } | ||
117 | void acpi_nmi_disable(void) { return; } | ||
118 | #endif | ||
105 | atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ | 119 | atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ |
106 | EXPORT_SYMBOL(nmi_active); | 120 | EXPORT_SYMBOL(nmi_active); |
107 | int nmi_watchdog_enabled; | ||
108 | int unknown_nmi_panic; | 121 | int unknown_nmi_panic; |
109 | void cpu_nmi_set_wd_enabled(void) { return; } | 122 | void cpu_nmi_set_wd_enabled(void) { return; } |
110 | void acpi_nmi_enable(void) { return; } | ||
111 | void acpi_nmi_disable(void) { return; } | ||
112 | void stop_apic_nmi_watchdog(void *unused) { return; } | 123 | void stop_apic_nmi_watchdog(void *unused) { return; } |
113 | void setup_apic_nmi_watchdog(void *unused) { return; } | 124 | void setup_apic_nmi_watchdog(void *unused) { return; } |
114 | int __init check_nmi_watchdog(void) { return 0; } | 125 | int __init check_nmi_watchdog(void) { return 0; } |
diff --git a/include/linux/nmi.h b/include/linux/nmi.h index a42ff0bef708..794e7354c5bf 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h | |||
@@ -20,10 +20,14 @@ extern void touch_nmi_watchdog(void); | |||
20 | extern void acpi_nmi_disable(void); | 20 | extern void acpi_nmi_disable(void); |
21 | extern void acpi_nmi_enable(void); | 21 | extern void acpi_nmi_enable(void); |
22 | #else | 22 | #else |
23 | #ifndef CONFIG_NMI_WATCHDOG | ||
23 | static inline void touch_nmi_watchdog(void) | 24 | static inline void touch_nmi_watchdog(void) |
24 | { | 25 | { |
25 | touch_softlockup_watchdog(); | 26 | touch_softlockup_watchdog(); |
26 | } | 27 | } |
28 | #else | ||
29 | extern void touch_nmi_watchdog(void); | ||
30 | #endif | ||
27 | static inline void acpi_nmi_disable(void) { } | 31 | static inline void acpi_nmi_disable(void) { } |
28 | static inline void acpi_nmi_enable(void) { } | 32 | static inline void acpi_nmi_enable(void) { } |
29 | #endif | 33 | #endif |
@@ -49,6 +53,11 @@ static inline bool trigger_all_cpu_backtrace(void) | |||
49 | 53 | ||
50 | #ifdef CONFIG_NMI_WATCHDOG | 54 | #ifdef CONFIG_NMI_WATCHDOG |
51 | int hw_nmi_is_cpu_stuck(struct pt_regs *); | 55 | int hw_nmi_is_cpu_stuck(struct pt_regs *); |
56 | u64 hw_nmi_get_sample_period(void); | ||
57 | extern int nmi_watchdog_enabled; | ||
58 | struct ctl_table; | ||
59 | extern int proc_nmi_enabled(struct ctl_table *, int , | ||
60 | void __user *, size_t *, loff_t *); | ||
52 | #endif | 61 | #endif |
53 | 62 | ||
54 | #endif | 63 | #endif |
diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 36817b214d69..73c1954a97bb 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c | |||
@@ -30,6 +30,8 @@ static DEFINE_PER_CPU(struct perf_event *, nmi_watchdog_ev); | |||
30 | static DEFINE_PER_CPU(int, nmi_watchdog_touch); | 30 | static DEFINE_PER_CPU(int, nmi_watchdog_touch); |
31 | static DEFINE_PER_CPU(long, alert_counter); | 31 | static DEFINE_PER_CPU(long, alert_counter); |
32 | 32 | ||
33 | static int panic_on_timeout; | ||
34 | |||
33 | void touch_nmi_watchdog(void) | 35 | void touch_nmi_watchdog(void) |
34 | { | 36 | { |
35 | __raw_get_cpu_var(nmi_watchdog_touch) = 1; | 37 | __raw_get_cpu_var(nmi_watchdog_touch) = 1; |
@@ -46,19 +48,49 @@ void touch_all_nmi_watchdog(void) | |||
46 | touch_softlockup_watchdog(); | 48 | touch_softlockup_watchdog(); |
47 | } | 49 | } |
48 | 50 | ||
51 | static int __init setup_nmi_watchdog(char *str) | ||
52 | { | ||
53 | if (!strncmp(str, "panic", 5)) { | ||
54 | panic_on_timeout = 1; | ||
55 | str = strchr(str, ','); | ||
56 | if (!str) | ||
57 | return 1; | ||
58 | ++str; | ||
59 | } | ||
60 | return 1; | ||
61 | } | ||
62 | __setup("nmi_watchdog=", setup_nmi_watchdog); | ||
63 | |||
49 | #ifdef CONFIG_SYSCTL | 64 | #ifdef CONFIG_SYSCTL |
50 | /* | 65 | /* |
51 | * proc handler for /proc/sys/kernel/nmi_watchdog | 66 | * proc handler for /proc/sys/kernel/nmi_watchdog |
52 | */ | 67 | */ |
68 | int nmi_watchdog_enabled; | ||
69 | |||
53 | int proc_nmi_enabled(struct ctl_table *table, int write, | 70 | int proc_nmi_enabled(struct ctl_table *table, int write, |
54 | void __user *buffer, size_t *length, loff_t *ppos) | 71 | void __user *buffer, size_t *length, loff_t *ppos) |
55 | { | 72 | { |
56 | int cpu; | 73 | int cpu; |
57 | 74 | ||
58 | if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) | 75 | if (!write) { |
76 | struct perf_event *event; | ||
77 | for_each_online_cpu(cpu) { | ||
78 | event = per_cpu(nmi_watchdog_ev, cpu); | ||
79 | if (event->state > PERF_EVENT_STATE_OFF) { | ||
80 | nmi_watchdog_enabled = 1; | ||
81 | break; | ||
82 | } | ||
83 | } | ||
84 | proc_dointvec(table, write, buffer, length, ppos); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) { | ||
59 | nmi_watchdog_enabled = 0; | 89 | nmi_watchdog_enabled = 0; |
60 | else | 90 | proc_dointvec(table, write, buffer, length, ppos); |
61 | nmi_watchdog_enabled = 1; | 91 | printk("NMI watchdog failed configuration, can not be enabled\n"); |
92 | return 0; | ||
93 | } | ||
62 | 94 | ||
63 | touch_all_nmi_watchdog(); | 95 | touch_all_nmi_watchdog(); |
64 | proc_dointvec(table, write, buffer, length, ppos); | 96 | proc_dointvec(table, write, buffer, length, ppos); |
@@ -81,8 +113,6 @@ struct perf_event_attr wd_attr = { | |||
81 | .disabled = 1, | 113 | .disabled = 1, |
82 | }; | 114 | }; |
83 | 115 | ||
84 | static int panic_on_timeout; | ||
85 | |||
86 | void wd_overflow(struct perf_event *event, int nmi, | 116 | void wd_overflow(struct perf_event *event, int nmi, |
87 | struct perf_sample_data *data, | 117 | struct perf_sample_data *data, |
88 | struct pt_regs *regs) | 118 | struct pt_regs *regs) |
@@ -103,11 +133,11 @@ void wd_overflow(struct perf_event *event, int nmi, | |||
103 | */ | 133 | */ |
104 | per_cpu(alert_counter,cpu) += 1; | 134 | per_cpu(alert_counter,cpu) += 1; |
105 | if (per_cpu(alert_counter,cpu) == 5) { | 135 | if (per_cpu(alert_counter,cpu) == 5) { |
106 | /* | 136 | if (panic_on_timeout) { |
107 | * die_nmi will return ONLY if NOTIFY_STOP happens.. | 137 | panic("NMI Watchdog detected LOCKUP on cpu %d", cpu); |
108 | */ | 138 | } else { |
109 | die_nmi("BUG: NMI Watchdog detected LOCKUP", | 139 | WARN(1, "NMI Watchdog detected LOCKUP on cpu %d", cpu); |
110 | regs, panic_on_timeout); | 140 | } |
111 | } | 141 | } |
112 | } else { | 142 | } else { |
113 | per_cpu(alert_counter,cpu) = 0; | 143 | per_cpu(alert_counter,cpu) = 0; |
@@ -133,7 +163,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | |||
133 | case CPU_ONLINE: | 163 | case CPU_ONLINE: |
134 | case CPU_ONLINE_FROZEN: | 164 | case CPU_ONLINE_FROZEN: |
135 | /* originally wanted the below chunk to be in CPU_UP_PREPARE, but caps is unpriv for non-CPU0 */ | 165 | /* originally wanted the below chunk to be in CPU_UP_PREPARE, but caps is unpriv for non-CPU0 */ |
136 | wd_attr.sample_period = cpu_khz * 1000; | 166 | wd_attr.sample_period = hw_nmi_get_sample_period(); |
137 | event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); | 167 | event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); |
138 | if (IS_ERR(event)) { | 168 | if (IS_ERR(event)) { |
139 | printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); | 169 | printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8a68b2448468..ac72c9e6bd9b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -60,6 +60,10 @@ | |||
60 | #include <asm/io.h> | 60 | #include <asm/io.h> |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | #ifdef CONFIG_NMI_WATCHDOG | ||
64 | #include <linux/nmi.h> | ||
65 | #endif | ||
66 | |||
63 | 67 | ||
64 | #if defined(CONFIG_SYSCTL) | 68 | #if defined(CONFIG_SYSCTL) |
65 | 69 | ||
@@ -692,7 +696,16 @@ static struct ctl_table kern_table[] = { | |||
692 | .mode = 0444, | 696 | .mode = 0444, |
693 | .proc_handler = proc_dointvec, | 697 | .proc_handler = proc_dointvec, |
694 | }, | 698 | }, |
695 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | 699 | #if defined(CONFIG_NMI_WATCHDOG) |
700 | { | ||
701 | .procname = "nmi_watchdog", | ||
702 | .data = &nmi_watchdog_enabled, | ||
703 | .maxlen = sizeof (int), | ||
704 | .mode = 0644, | ||
705 | .proc_handler = proc_nmi_enabled, | ||
706 | }, | ||
707 | #endif | ||
708 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_NMI_WATCHDOG) | ||
696 | { | 709 | { |
697 | .procname = "unknown_nmi_panic", | 710 | .procname = "unknown_nmi_panic", |
698 | .data = &unknown_nmi_panic, | 711 | .data = &unknown_nmi_panic, |