|
@@ -238,6 +238,27 @@ out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int hardlockup_detector_event_create(void)
|
|
|
+{
|
|
|
+ unsigned int cpu = smp_processor_id();
|
|
|
+ struct perf_event_attr *wd_attr;
|
|
|
+ struct perf_event *evt;
|
|
|
+
|
|
|
+ wd_attr = &wd_hw_attr;
|
|
|
+ wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
|
|
|
+
|
|
|
+ /* Try to register using hardware perf events */
|
|
|
+ evt = perf_event_create_kernel_counter(wd_attr, cpu, NULL,
|
|
|
+ watchdog_overflow_callback, NULL);
|
|
|
+ if (IS_ERR(evt)) {
|
|
|
+ pr_info("Perf event create on CPU %d failed with %ld\n", cpu,
|
|
|
+ PTR_ERR(evt));
|
|
|
+ return PTR_ERR(evt);
|
|
|
+ }
|
|
|
+ this_cpu_write(watchdog_ev, evt);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* hardlockup_detector_perf_disable - Disable the local event
|
|
|
*/
|
|
@@ -315,3 +336,19 @@ void __init hardlockup_detector_perf_restart(void)
|
|
|
perf_event_enable(event);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hardlockup_detector_perf_init - Probe whether NMI event is available at all
|
|
|
+ */
|
|
|
+int __init hardlockup_detector_perf_init(void)
|
|
|
+{
|
|
|
+ int ret = hardlockup_detector_event_create();
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
+ pr_info("Perf NMI watchdog permanetely disabled\n");
|
|
|
+ } else {
|
|
|
+ perf_event_release_kernel(this_cpu_read(watchdog_ev));
|
|
|
+ this_cpu_write(watchdog_ev, NULL);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|