aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-09-09 02:16:06 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-09 02:16:06 -0400
commita8f22264550e64c0cd11fb6647284b0bd6407f9c (patch)
treee42ef7f04063bef6114c6488c70eff7089b5ea26 /arch/sparc
parent825c9fb47a0837db12fecf8d360e0e1d284ddb49 (diff)
sparc64: Manage NMI watchdog enabling like x86.
Use a per-cpu 'wd_enabled' boolean and a global atomic_t count of watchdog NMI enabled cpus which is set to '-1' if something is wrong with the watchdog and it can't be used. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/nmi.h2
-rw-r--r--arch/sparc/kernel/nmi.c60
-rw-r--r--arch/sparc/oprofile/init.c2
3 files changed, 45 insertions, 19 deletions
diff --git a/arch/sparc/include/asm/nmi.h b/arch/sparc/include/asm/nmi.h
index fbd546dd4feb..c7d11e435df9 100644
--- a/arch/sparc/include/asm/nmi.h
+++ b/arch/sparc/include/asm/nmi.h
@@ -5,6 +5,6 @@ extern int __init nmi_init(void);
5extern void perfctr_irq(int irq, struct pt_regs *regs); 5extern void perfctr_irq(int irq, struct pt_regs *regs);
6extern void nmi_adjust_hz(unsigned int new_hz); 6extern void nmi_adjust_hz(unsigned int new_hz);
7 7
8extern int nmi_usable; 8extern atomic_t nmi_active;
9 9
10#endif /* __NMI_H */ 10#endif /* __NMI_H */
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c
index 2c0cc72d295b..d1614e8384ae 100644
--- a/arch/sparc/kernel/nmi.c
+++ b/arch/sparc/kernel/nmi.c
@@ -34,10 +34,17 @@
34static int nmi_watchdog_active; 34static int nmi_watchdog_active;
35static int panic_on_timeout; 35static int panic_on_timeout;
36 36
37int nmi_usable; 37/* nmi_active:
38EXPORT_SYMBOL_GPL(nmi_usable); 38 * >0: the NMI watchdog is active, but can be disabled
39 * <0: the NMI watchdog has not been set up, and cannot be enabled
40 * 0: the NMI watchdog is disabled, but can be enabled
41 */
42atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
43EXPORT_SYMBOL(nmi_active);
39 44
40static unsigned int nmi_hz = HZ; 45static unsigned int nmi_hz = HZ;
46static DEFINE_PER_CPU(short, wd_enabled);
47static int endflag __initdata;
41 48
42static DEFINE_PER_CPU(unsigned int, last_irq_sum); 49static DEFINE_PER_CPU(unsigned int, last_irq_sum);
43static DEFINE_PER_CPU(local_t, alert_counter); 50static DEFINE_PER_CPU(local_t, alert_counter);
@@ -110,7 +117,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
110 __get_cpu_var(last_irq_sum) = sum; 117 __get_cpu_var(last_irq_sum) = sum;
111 local_set(&__get_cpu_var(alert_counter), 0); 118 local_set(&__get_cpu_var(alert_counter), 0);
112 } 119 }
113 if (nmi_usable) { 120 if (__get_cpu_var(wd_enabled)) {
114 write_pic(picl_value(nmi_hz)); 121 write_pic(picl_value(nmi_hz));
115 pcr_ops->write(pcr_enable); 122 pcr_ops->write(pcr_enable);
116 } 123 }
@@ -121,8 +128,6 @@ static inline unsigned int get_nmi_count(int cpu)
121 return cpu_data(cpu).__nmi_count; 128 return cpu_data(cpu).__nmi_count;
122} 129}
123 130
124static int endflag __initdata;
125
126static __init void nmi_cpu_busy(void *data) 131static __init void nmi_cpu_busy(void *data)
127{ 132{
128 local_irq_enable_in_hardirq(); 133 local_irq_enable_in_hardirq();
@@ -143,12 +148,15 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count)
143 printk(KERN_WARNING 148 printk(KERN_WARNING
144 "and attach the output of the 'dmesg' command.\n"); 149 "and attach the output of the 'dmesg' command.\n");
145 150
146 nmi_usable = 0; 151 per_cpu(wd_enabled, cpu) = 0;
152 atomic_dec(&nmi_active);
147} 153}
148 154
149static void stop_watchdog(void *unused) 155static void stop_nmi_watchdog(void *unused)
150{ 156{
151 pcr_ops->write(PCR_PIC_PRIV); 157 pcr_ops->write(PCR_PIC_PRIV);
158 __get_cpu_var(wd_enabled) = 0;
159 atomic_dec(&nmi_active);
152} 160}
153 161
154static int __init check_nmi_watchdog(void) 162static int __init check_nmi_watchdog(void)
@@ -156,6 +164,9 @@ static int __init check_nmi_watchdog(void)
156 unsigned int *prev_nmi_count; 164 unsigned int *prev_nmi_count;
157 int cpu, err; 165 int cpu, err;
158 166
167 if (!atomic_read(&nmi_active))
168 return 0;
169
159 prev_nmi_count = kmalloc(nr_cpu_ids * sizeof(unsigned int), GFP_KERNEL); 170 prev_nmi_count = kmalloc(nr_cpu_ids * sizeof(unsigned int), GFP_KERNEL);
160 if (!prev_nmi_count) { 171 if (!prev_nmi_count) {
161 err = -ENOMEM; 172 err = -ENOMEM;
@@ -172,12 +183,15 @@ static int __init check_nmi_watchdog(void)
172 mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */ 183 mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */
173 184
174 for_each_online_cpu(cpu) { 185 for_each_online_cpu(cpu) {
186 if (!per_cpu(wd_enabled, cpu))
187 continue;
175 if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) 188 if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5)
176 report_broken_nmi(cpu, prev_nmi_count); 189 report_broken_nmi(cpu, prev_nmi_count);
177 } 190 }
178 endflag = 1; 191 endflag = 1;
179 if (!nmi_usable) { 192 if (!atomic_read(&nmi_active)) {
180 kfree(prev_nmi_count); 193 kfree(prev_nmi_count);
194 atomic_set(&nmi_active, -1);
181 err = -ENODEV; 195 err = -ENODEV;
182 goto error; 196 goto error;
183 } 197 }
@@ -188,12 +202,26 @@ static int __init check_nmi_watchdog(void)
188 kfree(prev_nmi_count); 202 kfree(prev_nmi_count);
189 return 0; 203 return 0;
190error: 204error:
191 on_each_cpu(stop_watchdog, NULL, 1); 205 on_each_cpu(stop_nmi_watchdog, NULL, 1);
192 return err; 206 return err;
193} 207}
194 208
195static void start_watchdog(void *unused) 209static void start_nmi_watchdog(void *unused)
210{
211 __get_cpu_var(wd_enabled) = 1;
212 atomic_inc(&nmi_active);
213
214 pcr_ops->write(PCR_PIC_PRIV);
215 write_pic(picl_value(nmi_hz));
216
217 pcr_ops->write(pcr_enable);
218}
219
220static void nmi_adjust_hz_one(void *unused)
196{ 221{
222 if (!__get_cpu_var(wd_enabled))
223 return;
224
197 pcr_ops->write(PCR_PIC_PRIV); 225 pcr_ops->write(PCR_PIC_PRIV);
198 write_pic(picl_value(nmi_hz)); 226 write_pic(picl_value(nmi_hz));
199 227
@@ -203,13 +231,13 @@ static void start_watchdog(void *unused)
203void nmi_adjust_hz(unsigned int new_hz) 231void nmi_adjust_hz(unsigned int new_hz)
204{ 232{
205 nmi_hz = new_hz; 233 nmi_hz = new_hz;
206 on_each_cpu(start_watchdog, NULL, 1); 234 on_each_cpu(nmi_adjust_hz_one, NULL, 1);
207} 235}
208EXPORT_SYMBOL_GPL(nmi_adjust_hz); 236EXPORT_SYMBOL_GPL(nmi_adjust_hz);
209 237
210static int nmi_shutdown(struct notifier_block *nb, unsigned long cmd, void *p) 238static int nmi_shutdown(struct notifier_block *nb, unsigned long cmd, void *p)
211{ 239{
212 on_each_cpu(stop_watchdog, NULL, 1); 240 on_each_cpu(stop_nmi_watchdog, NULL, 1);
213 return 0; 241 return 0;
214} 242}
215 243
@@ -221,16 +249,14 @@ int __init nmi_init(void)
221{ 249{
222 int err; 250 int err;
223 251
224 nmi_usable = 1; 252 on_each_cpu(start_nmi_watchdog, NULL, 1);
225
226 on_each_cpu(start_watchdog, NULL, 1);
227 253
228 err = check_nmi_watchdog(); 254 err = check_nmi_watchdog();
229 if (!err) { 255 if (!err) {
230 err = register_reboot_notifier(&nmi_reboot_notifier); 256 err = register_reboot_notifier(&nmi_reboot_notifier);
231 if (err) { 257 if (err) {
232 nmi_usable = 0; 258 on_each_cpu(stop_nmi_watchdog, NULL, 1);
233 on_each_cpu(stop_watchdog, NULL, 1); 259 atomic_set(&nmi_active, -1);
234 } 260 }
235 } 261 }
236 return err; 262 return err;
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
index d172f86439b1..9ce34fd294c9 100644
--- a/arch/sparc/oprofile/init.c
+++ b/arch/sparc/oprofile/init.c
@@ -57,7 +57,7 @@ static void timer_stop(void)
57 57
58static int op_nmi_timer_init(struct oprofile_operations *ops) 58static int op_nmi_timer_init(struct oprofile_operations *ops)
59{ 59{
60 if (!nmi_usable) 60 if (atomic_read(&nmi_active) <= 0)
61 return -ENODEV; 61 return -ENODEV;
62 62
63 ops->start = timer_start; 63 ops->start = timer_start;