aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/watchdog.c4
-rw-r--r--kernel/watchdog_hld.c88
2 files changed, 8 insertions, 84 deletions
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index fd8a998eb197..5eb11960e4a2 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -107,6 +107,7 @@ __setup("hardlockup_all_cpu_backtrace=", hardlockup_all_cpu_backtrace_setup);
107 */ 107 */
108int __weak watchdog_nmi_enable(unsigned int cpu) 108int __weak watchdog_nmi_enable(unsigned int cpu)
109{ 109{
110 hardlockup_detector_perf_enable();
110 return 0; 111 return 0;
111} 112}
112 113
@@ -465,7 +466,8 @@ static void watchdog_enable(unsigned int cpu)
465 /* Initialize timestamp */ 466 /* Initialize timestamp */
466 __touch_watchdog(); 467 __touch_watchdog();
467 /* Enable the perf event */ 468 /* Enable the perf event */
468 watchdog_nmi_enable(cpu); 469 if (watchdog_enabled & NMI_WATCHDOG_ENABLED)
470 watchdog_nmi_enable(cpu);
469 471
470 watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1); 472 watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);
471} 473}
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index 99a3f22e48cc..509bb6b59c41 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -25,7 +25,7 @@ static DEFINE_PER_CPU(struct perf_event *, dead_event);
25static struct cpumask dead_events_mask; 25static struct cpumask dead_events_mask;
26 26
27static unsigned long hardlockup_allcpu_dumped; 27static unsigned long hardlockup_allcpu_dumped;
28static bool hardlockup_detector_disabled; 28static unsigned int watchdog_cpus;
29 29
30void arch_touch_nmi_watchdog(void) 30void arch_touch_nmi_watchdog(void)
31{ 31{
@@ -160,84 +160,6 @@ static void watchdog_overflow_callback(struct perf_event *event,
160 return; 160 return;
161} 161}
162 162
163/*
164 * People like the simple clean cpu node info on boot.
165 * Reduce the watchdog noise by only printing messages
166 * that are different from what cpu0 displayed.
167 */
168static unsigned long firstcpu_err;
169static atomic_t watchdog_cpus;
170
171int watchdog_nmi_enable(unsigned int cpu)
172{
173 struct perf_event_attr *wd_attr;
174 struct perf_event *event = per_cpu(watchdog_ev, cpu);
175 int firstcpu = 0;
176
177 /* nothing to do if the hard lockup detector is disabled */
178 if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
179 goto out;
180
181 /* A failure disabled the hardlockup detector permanently */
182 if (hardlockup_detector_disabled)
183 return -ENODEV;
184
185 /* is it already setup and enabled? */
186 if (event && event->state > PERF_EVENT_STATE_OFF)
187 goto out;
188
189 /* it is setup but not enabled */
190 if (event != NULL)
191 goto out_enable;
192
193 if (atomic_inc_return(&watchdog_cpus) == 1)
194 firstcpu = 1;
195
196 wd_attr = &wd_hw_attr;
197 wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
198
199 /* Try to register using hardware perf events */
200 event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
201
202 /* save the first cpu's error for future comparision */
203 if (firstcpu && IS_ERR(event))
204 firstcpu_err = PTR_ERR(event);
205
206 if (!IS_ERR(event)) {
207 /* only print for the first cpu initialized */
208 if (firstcpu || firstcpu_err)
209 pr_info("enabled on all CPUs, permanently consumes one hw-PMU counter.\n");
210 goto out_save;
211 }
212
213 /* skip displaying the same error again */
214 if (!firstcpu && (PTR_ERR(event) == firstcpu_err))
215 return PTR_ERR(event);
216
217 /* vary the KERN level based on the returned errno */
218 if (PTR_ERR(event) == -EOPNOTSUPP)
219 pr_info("disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
220 else if (PTR_ERR(event) == -ENOENT)
221 pr_warn("disabled (cpu%i): hardware events not enabled\n",
222 cpu);
223 else
224 pr_err("disabled (cpu%i): unable to create perf event: %ld\n",
225 cpu, PTR_ERR(event));
226
227 pr_info("Disabling hard lockup detector permanently\n");
228 hardlockup_detector_disabled = true;
229
230 return PTR_ERR(event);
231
232 /* success path */
233out_save:
234 per_cpu(watchdog_ev, cpu) = event;
235out_enable:
236 perf_event_enable(per_cpu(watchdog_ev, cpu));
237out:
238 return 0;
239}
240
241static int hardlockup_detector_event_create(void) 163static int hardlockup_detector_event_create(void)
242{ 164{
243 unsigned int cpu = smp_processor_id(); 165 unsigned int cpu = smp_processor_id();
@@ -267,6 +189,9 @@ void hardlockup_detector_perf_enable(void)
267 if (hardlockup_detector_event_create()) 189 if (hardlockup_detector_event_create())
268 return; 190 return;
269 191
192 if (!watchdog_cpus++)
193 pr_info("Enabled. Permanently consumes one hw-PMU counter.\n");
194
270 perf_event_enable(this_cpu_read(watchdog_ev)); 195 perf_event_enable(this_cpu_read(watchdog_ev));
271} 196}
272 197
@@ -282,10 +207,7 @@ void hardlockup_detector_perf_disable(void)
282 this_cpu_write(watchdog_ev, NULL); 207 this_cpu_write(watchdog_ev, NULL);
283 this_cpu_write(dead_event, event); 208 this_cpu_write(dead_event, event);
284 cpumask_set_cpu(smp_processor_id(), &dead_events_mask); 209 cpumask_set_cpu(smp_processor_id(), &dead_events_mask);
285 210 watchdog_cpus--;
286 /* watchdog_nmi_enable() expects this to be zero initially. */
287 if (atomic_dec_and_test(&watchdog_cpus))
288 firstcpu_err = 0;
289 } 211 }
290} 212}
291 213