watchdog/perf: adapt the watchdog_perf interface for async model
[sfrench/cifs-2.6.git] / kernel / watchdog.c
index 10947c83507987ddd1ab06c179c148125c520172..237990e8d34539b2d33525cb4577abd94cdf872c 100644 (file)
@@ -208,7 +208,13 @@ void __weak watchdog_hardlockup_enable(unsigned int cpu) { }
 
 void __weak watchdog_hardlockup_disable(unsigned int cpu) { }
 
-/* Return 0, if a hardlockup watchdog is available. Error code otherwise */
+/*
+ * Watchdog-detector specific API.
+ *
+ * Return 0 when hardlockup watchdog is available, negative value otherwise.
+ * Note that the negative value means that a delayed probe might
+ * succeed later.
+ */
 int __weak __init watchdog_hardlockup_probe(void)
 {
        /*
@@ -954,6 +960,62 @@ static void __init watchdog_sysctl_init(void)
 #define watchdog_sysctl_init() do { } while (0)
 #endif /* CONFIG_SYSCTL */
 
+static void __init lockup_detector_delay_init(struct work_struct *work);
+static bool allow_lockup_detector_init_retry __initdata;
+
+static struct work_struct detector_work __initdata =
+               __WORK_INITIALIZER(detector_work, lockup_detector_delay_init);
+
+static void __init lockup_detector_delay_init(struct work_struct *work)
+{
+       int ret;
+
+       ret = watchdog_hardlockup_probe();
+       if (ret) {
+               pr_info("Delayed init of the lockup detector failed: %d\n", ret);
+               pr_info("Hard watchdog permanently disabled\n");
+               return;
+       }
+
+       allow_lockup_detector_init_retry = false;
+
+       watchdog_hardlockup_available = true;
+       lockup_detector_setup();
+}
+
+/*
+ * lockup_detector_retry_init - retry init lockup detector if possible.
+ *
+ * Retry hardlockup detector init. It is useful when it requires some
+ * functionality that has to be initialized later on a particular
+ * platform.
+ */
+void __init lockup_detector_retry_init(void)
+{
+       /* Must be called before late init calls */
+       if (!allow_lockup_detector_init_retry)
+               return;
+
+       schedule_work(&detector_work);
+}
+
+/*
+ * Ensure that optional delayed hardlockup init is proceed before
+ * the init code and memory is freed.
+ */
+static int __init lockup_detector_check(void)
+{
+       /* Prevent any later retry. */
+       allow_lockup_detector_init_retry = false;
+
+       /* Make sure no work is pending. */
+       flush_work(&detector_work);
+
+       return 0;
+
+}
+late_initcall_sync(lockup_detector_check);
+
 void __init lockup_detector_init(void)
 {
        if (tick_nohz_full_enabled())
@@ -964,6 +1026,9 @@ void __init lockup_detector_init(void)
 
        if (!watchdog_hardlockup_probe())
                watchdog_hardlockup_available = true;
+       else
+               allow_lockup_detector_init_retry = true;
+
        lockup_detector_setup();
        watchdog_sysctl_init();
 }