Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / drivers / watchdog / watchdog_dev.c
index 3bab324..3a3d8b5 100644 (file)
@@ -401,7 +401,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
        if (watchdog_pretimeout_invalid(wdd, timeout))
                return -EINVAL;
 
-       if (wdd->ops->set_pretimeout)
+       if (wdd->ops->set_pretimeout && (wdd->info->options & WDIOF_PRETIMEOUT))
                err = wdd->ops->set_pretimeout(wdd, timeout);
        else
                wdd->pretimeout = timeout;
@@ -1096,6 +1096,8 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
                watchdog_stop(wdd);
        }
 
+       watchdog_hrtimer_pretimeout_stop(wdd);
+
        mutex_lock(&wd_data->lock);
        wd_data->wdd = NULL;
        wdd->wd_data = NULL;
@@ -1103,7 +1105,6 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
 
        hrtimer_cancel(&wd_data->timer);
        kthread_cancel_work_sync(&wd_data->work);
-       watchdog_hrtimer_pretimeout_stop(wdd);
 
        put_device(&wd_data->dev);
 }
@@ -1172,7 +1173,10 @@ int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
 
        wd_data->last_hw_keepalive = ktime_sub(now, ms_to_ktime(last_ping_ms));
 
-       return __watchdog_ping(wdd);
+       if (watchdog_hw_running(wdd) && handle_boot_enabled)
+               return __watchdog_ping(wdd);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(watchdog_set_last_hw_keepalive);
 
@@ -1227,6 +1231,53 @@ void __exit watchdog_dev_exit(void)
        kthread_destroy_worker(watchdog_kworker);
 }
 
+int watchdog_dev_suspend(struct watchdog_device *wdd)
+{
+       struct watchdog_core_data *wd_data = wdd->wd_data;
+       int ret = 0;
+
+       if (!wdd->wd_data)
+               return -ENODEV;
+
+       /* ping for the last time before suspend */
+       mutex_lock(&wd_data->lock);
+       if (watchdog_worker_should_ping(wd_data))
+               ret = __watchdog_ping(wd_data->wdd);
+       mutex_unlock(&wd_data->lock);
+
+       if (ret)
+               return ret;
+
+       /*
+        * make sure that watchdog worker will not kick in when the wdog is
+        * suspended
+        */
+       hrtimer_cancel(&wd_data->timer);
+       kthread_cancel_work_sync(&wd_data->work);
+
+       return 0;
+}
+
+int watchdog_dev_resume(struct watchdog_device *wdd)
+{
+       struct watchdog_core_data *wd_data = wdd->wd_data;
+       int ret = 0;
+
+       if (!wdd->wd_data)
+               return -ENODEV;
+
+       /*
+        * __watchdog_ping will also retrigger hrtimer and therefore restore the
+        * ping worker if needed.
+        */
+       mutex_lock(&wd_data->lock);
+       if (watchdog_worker_should_ping(wd_data))
+               ret = __watchdog_ping(wd_data->wdd);
+       mutex_unlock(&wd_data->lock);
+
+       return ret;
+}
+
 module_param(handle_boot_enabled, bool, 0444);
 MODULE_PARM_DESC(handle_boot_enabled,
        "Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default="