aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c80
1 files changed, 78 insertions, 2 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 10c3510d72a9..e3219dfd736c 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -31,6 +31,8 @@
31#include <trace/events/power.h> 31#include <trace/events/power.h>
32#include <linux/cpufreq.h> 32#include <linux/cpufreq.h>
33#include <linux/cpuidle.h> 33#include <linux/cpuidle.h>
34#include <linux/timer.h>
35
34#include "../base.h" 36#include "../base.h"
35#include "power.h" 37#include "power.h"
36 38
@@ -391,6 +393,71 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
391 return error; 393 return error;
392} 394}
393 395
396#ifdef CONFIG_DPM_WATCHDOG
397struct dpm_watchdog {
398 struct device *dev;
399 struct task_struct *tsk;
400 struct timer_list timer;
401};
402
403#define DECLARE_DPM_WATCHDOG_ON_STACK(wd) \
404 struct dpm_watchdog wd
405
406/**
407 * dpm_watchdog_handler - Driver suspend / resume watchdog handler.
408 * @data: Watchdog object address.
409 *
410 * Called when a driver has timed out suspending or resuming.
411 * There's not much we can do here to recover so panic() to
412 * capture a crash-dump in pstore.
413 */
414static void dpm_watchdog_handler(unsigned long data)
415{
416 struct dpm_watchdog *wd = (void *)data;
417
418 dev_emerg(wd->dev, "**** DPM device timeout ****\n");
419 show_stack(wd->tsk, NULL);
420 panic("%s %s: unrecoverable failure\n",
421 dev_driver_string(wd->dev), dev_name(wd->dev));
422}
423
424/**
425 * dpm_watchdog_set - Enable pm watchdog for given device.
426 * @wd: Watchdog. Must be allocated on the stack.
427 * @dev: Device to handle.
428 */
429static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev)
430{
431 struct timer_list *timer = &wd->timer;
432
433 wd->dev = dev;
434 wd->tsk = current;
435
436 init_timer_on_stack(timer);
437 /* use same timeout value for both suspend and resume */
438 timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_TIMEOUT;
439 timer->function = dpm_watchdog_handler;
440 timer->data = (unsigned long)wd;
441 add_timer(timer);
442}
443
444/**
445 * dpm_watchdog_clear - Disable suspend/resume watchdog.
446 * @wd: Watchdog to disable.
447 */
448static void dpm_watchdog_clear(struct dpm_watchdog *wd)
449{
450 struct timer_list *timer = &wd->timer;
451
452 del_timer_sync(timer);
453 destroy_timer_on_stack(timer);
454}
455#else
456#define DECLARE_DPM_WATCHDOG_ON_STACK(wd)
457#define dpm_watchdog_set(x, y)
458#define dpm_watchdog_clear(x)
459#endif
460
394/*------------------------- Resume routines -------------------------*/ 461/*------------------------- Resume routines -------------------------*/
395 462
396/** 463/**
@@ -578,6 +645,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
578 pm_callback_t callback = NULL; 645 pm_callback_t callback = NULL;
579 char *info = NULL; 646 char *info = NULL;
580 int error = 0; 647 int error = 0;
648 DECLARE_DPM_WATCHDOG_ON_STACK(wd);
581 649
582 TRACE_DEVICE(dev); 650 TRACE_DEVICE(dev);
583 TRACE_RESUME(0); 651 TRACE_RESUME(0);
@@ -586,6 +654,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
586 goto Complete; 654 goto Complete;
587 655
588 dpm_wait(dev->parent, async); 656 dpm_wait(dev->parent, async);
657 dpm_watchdog_set(&wd, dev);
589 device_lock(dev); 658 device_lock(dev);
590 659
591 /* 660 /*
@@ -644,6 +713,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
644 713
645 Unlock: 714 Unlock:
646 device_unlock(dev); 715 device_unlock(dev);
716 dpm_watchdog_clear(&wd);
647 717
648 Complete: 718 Complete:
649 complete_all(&dev->power.completion); 719 complete_all(&dev->power.completion);
@@ -689,7 +759,7 @@ void dpm_resume(pm_message_t state)
689 async_error = 0; 759 async_error = 0;
690 760
691 list_for_each_entry(dev, &dpm_suspended_list, power.entry) { 761 list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
692 INIT_COMPLETION(dev->power.completion); 762 reinit_completion(&dev->power.completion);
693 if (is_async(dev)) { 763 if (is_async(dev)) {
694 get_device(dev); 764 get_device(dev);
695 async_schedule(async_resume, dev); 765 async_schedule(async_resume, dev);
@@ -1063,6 +1133,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1063 pm_callback_t callback = NULL; 1133 pm_callback_t callback = NULL;
1064 char *info = NULL; 1134 char *info = NULL;
1065 int error = 0; 1135 int error = 0;
1136 DECLARE_DPM_WATCHDOG_ON_STACK(wd);
1066 1137
1067 dpm_wait_for_children(dev, async); 1138 dpm_wait_for_children(dev, async);
1068 1139
@@ -1086,6 +1157,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1086 if (dev->power.syscore) 1157 if (dev->power.syscore)
1087 goto Complete; 1158 goto Complete;
1088 1159
1160 dpm_watchdog_set(&wd, dev);
1089 device_lock(dev); 1161 device_lock(dev);
1090 1162
1091 if (dev->pm_domain) { 1163 if (dev->pm_domain) {
@@ -1142,6 +1214,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1142 } 1214 }
1143 1215
1144 device_unlock(dev); 1216 device_unlock(dev);
1217 dpm_watchdog_clear(&wd);
1145 1218
1146 Complete: 1219 Complete:
1147 complete_all(&dev->power.completion); 1220 complete_all(&dev->power.completion);
@@ -1167,7 +1240,7 @@ static void async_suspend(void *data, async_cookie_t cookie)
1167 1240
1168static int device_suspend(struct device *dev) 1241static int device_suspend(struct device *dev)
1169{ 1242{
1170 INIT_COMPLETION(dev->power.completion); 1243 reinit_completion(&dev->power.completion);
1171 1244
1172 if (pm_async_enabled && dev->power.async_suspend) { 1245 if (pm_async_enabled && dev->power.async_suspend) {
1173 get_device(dev); 1246 get_device(dev);
@@ -1280,6 +1353,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
1280 1353
1281 device_unlock(dev); 1354 device_unlock(dev);
1282 1355
1356 if (error)
1357 pm_runtime_put(dev);
1358
1283 return error; 1359 return error;
1284} 1360}
1285 1361