aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/main.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-01-23 01:45:46 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-23 01:45:46 -0500
commit6be325719b3e54624397e413efd4b33a997e55a3 (patch)
tree57f321a56794cab2222e179b16731e0d76a4a68a /drivers/base/power/main.c
parent26d92f9276a56d55511a427fb70bd70886af647a (diff)
parent92dcffb916d309aa01778bf8963a6932e4014d07 (diff)
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c145
1 files changed, 127 insertions, 18 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 8aa2443182d5..a5142bddef41 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -23,8 +23,8 @@
23#include <linux/pm.h> 23#include <linux/pm.h>
24#include <linux/pm_runtime.h> 24#include <linux/pm_runtime.h>
25#include <linux/resume-trace.h> 25#include <linux/resume-trace.h>
26#include <linux/rwsem.h>
27#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/sched.h>
28 28
29#include "../base.h" 29#include "../base.h"
30#include "power.h" 30#include "power.h"
@@ -161,6 +161,32 @@ void device_pm_move_last(struct device *dev)
161 list_move_tail(&dev->power.entry, &dpm_list); 161 list_move_tail(&dev->power.entry, &dpm_list);
162} 162}
163 163
164static ktime_t initcall_debug_start(struct device *dev)
165{
166 ktime_t calltime = ktime_set(0, 0);
167
168 if (initcall_debug) {
169 pr_info("calling %s+ @ %i\n",
170 dev_name(dev), task_pid_nr(current));
171 calltime = ktime_get();
172 }
173
174 return calltime;
175}
176
177static void initcall_debug_report(struct device *dev, ktime_t calltime,
178 int error)
179{
180 ktime_t delta, rettime;
181
182 if (initcall_debug) {
183 rettime = ktime_get();
184 delta = ktime_sub(rettime, calltime);
185 pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
186 error, (unsigned long long)ktime_to_ns(delta) >> 10);
187 }
188}
189
164/** 190/**
165 * pm_op - Execute the PM operation appropriate for given PM event. 191 * pm_op - Execute the PM operation appropriate for given PM event.
166 * @dev: Device to handle. 192 * @dev: Device to handle.
@@ -172,6 +198,9 @@ static int pm_op(struct device *dev,
172 pm_message_t state) 198 pm_message_t state)
173{ 199{
174 int error = 0; 200 int error = 0;
201 ktime_t calltime;
202
203 calltime = initcall_debug_start(dev);
175 204
176 switch (state.event) { 205 switch (state.event) {
177#ifdef CONFIG_SUSPEND 206#ifdef CONFIG_SUSPEND
@@ -219,6 +248,9 @@ static int pm_op(struct device *dev,
219 default: 248 default:
220 error = -EINVAL; 249 error = -EINVAL;
221 } 250 }
251
252 initcall_debug_report(dev, calltime, error);
253
222 return error; 254 return error;
223} 255}
224 256
@@ -236,6 +268,13 @@ static int pm_noirq_op(struct device *dev,
236 pm_message_t state) 268 pm_message_t state)
237{ 269{
238 int error = 0; 270 int error = 0;
271 ktime_t calltime, delta, rettime;
272
273 if (initcall_debug) {
274 pr_info("calling %s_i+ @ %i\n",
275 dev_name(dev), task_pid_nr(current));
276 calltime = ktime_get();
277 }
239 278
240 switch (state.event) { 279 switch (state.event) {
241#ifdef CONFIG_SUSPEND 280#ifdef CONFIG_SUSPEND
@@ -283,6 +322,15 @@ static int pm_noirq_op(struct device *dev,
283 default: 322 default:
284 error = -EINVAL; 323 error = -EINVAL;
285 } 324 }
325
326 if (initcall_debug) {
327 rettime = ktime_get();
328 delta = ktime_sub(rettime, calltime);
329 printk("initcall %s_i+ returned %d after %Ld usecs\n",
330 dev_name(dev), error,
331 (unsigned long long)ktime_to_ns(delta) >> 10);
332 }
333
286 return error; 334 return error;
287} 335}
288 336
@@ -324,6 +372,23 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
324 kobject_name(&dev->kobj), pm_verb(state.event), info, error); 372 kobject_name(&dev->kobj), pm_verb(state.event), info, error);
325} 373}
326 374
375static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
376{
377 ktime_t calltime;
378 s64 usecs64;
379 int usecs;
380
381 calltime = ktime_get();
382 usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
383 do_div(usecs64, NSEC_PER_USEC);
384 usecs = usecs64;
385 if (usecs == 0)
386 usecs = 1;
387 pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n",
388 info ?: "", info ? " " : "", pm_verb(state.event),
389 usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
390}
391
327/*------------------------- Resume routines -------------------------*/ 392/*------------------------- Resume routines -------------------------*/
328 393
329/** 394/**
@@ -341,14 +406,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
341 TRACE_DEVICE(dev); 406 TRACE_DEVICE(dev);
342 TRACE_RESUME(0); 407 TRACE_RESUME(0);
343 408
344 if (!dev->bus) 409 if (dev->bus && dev->bus->pm) {
345 goto End;
346
347 if (dev->bus->pm) {
348 pm_dev_dbg(dev, state, "EARLY "); 410 pm_dev_dbg(dev, state, "EARLY ");
349 error = pm_noirq_op(dev, dev->bus->pm, state); 411 error = pm_noirq_op(dev, dev->bus->pm, state);
350 } 412 }
351 End: 413
352 TRACE_RESUME(error); 414 TRACE_RESUME(error);
353 return error; 415 return error;
354} 416}
@@ -363,6 +425,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
363void dpm_resume_noirq(pm_message_t state) 425void dpm_resume_noirq(pm_message_t state)
364{ 426{
365 struct device *dev; 427 struct device *dev;
428 ktime_t starttime = ktime_get();
366 429
367 mutex_lock(&dpm_list_mtx); 430 mutex_lock(&dpm_list_mtx);
368 transition_started = false; 431 transition_started = false;
@@ -376,11 +439,32 @@ void dpm_resume_noirq(pm_message_t state)
376 pm_dev_err(dev, state, " early", error); 439 pm_dev_err(dev, state, " early", error);
377 } 440 }
378 mutex_unlock(&dpm_list_mtx); 441 mutex_unlock(&dpm_list_mtx);
442 dpm_show_time(starttime, state, "early");
379 resume_device_irqs(); 443 resume_device_irqs();
380} 444}
381EXPORT_SYMBOL_GPL(dpm_resume_noirq); 445EXPORT_SYMBOL_GPL(dpm_resume_noirq);
382 446
383/** 447/**
448 * legacy_resume - Execute a legacy (bus or class) resume callback for device.
449 * @dev: Device to resume.
450 * @cb: Resume callback to execute.
451 */
452static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
453{
454 int error;
455 ktime_t calltime;
456
457 calltime = initcall_debug_start(dev);
458
459 error = cb(dev);
460 suspend_report_result(cb, error);
461
462 initcall_debug_report(dev, calltime, error);
463
464 return error;
465}
466
467/**
384 * device_resume - Execute "resume" callbacks for given device. 468 * device_resume - Execute "resume" callbacks for given device.
385 * @dev: Device to handle. 469 * @dev: Device to handle.
386 * @state: PM transition of the system being carried out. 470 * @state: PM transition of the system being carried out.
@@ -400,7 +484,7 @@ static int device_resume(struct device *dev, pm_message_t state)
400 error = pm_op(dev, dev->bus->pm, state); 484 error = pm_op(dev, dev->bus->pm, state);
401 } else if (dev->bus->resume) { 485 } else if (dev->bus->resume) {
402 pm_dev_dbg(dev, state, "legacy "); 486 pm_dev_dbg(dev, state, "legacy ");
403 error = dev->bus->resume(dev); 487 error = legacy_resume(dev, dev->bus->resume);
404 } 488 }
405 if (error) 489 if (error)
406 goto End; 490 goto End;
@@ -421,7 +505,7 @@ static int device_resume(struct device *dev, pm_message_t state)
421 error = pm_op(dev, dev->class->pm, state); 505 error = pm_op(dev, dev->class->pm, state);
422 } else if (dev->class->resume) { 506 } else if (dev->class->resume) {
423 pm_dev_dbg(dev, state, "legacy class "); 507 pm_dev_dbg(dev, state, "legacy class ");
424 error = dev->class->resume(dev); 508 error = legacy_resume(dev, dev->class->resume);
425 } 509 }
426 } 510 }
427 End: 511 End:
@@ -441,6 +525,7 @@ static int device_resume(struct device *dev, pm_message_t state)
441static void dpm_resume(pm_message_t state) 525static void dpm_resume(pm_message_t state)
442{ 526{
443 struct list_head list; 527 struct list_head list;
528 ktime_t starttime = ktime_get();
444 529
445 INIT_LIST_HEAD(&list); 530 INIT_LIST_HEAD(&list);
446 mutex_lock(&dpm_list_mtx); 531 mutex_lock(&dpm_list_mtx);
@@ -469,6 +554,7 @@ static void dpm_resume(pm_message_t state)
469 } 554 }
470 list_splice(&list, &dpm_list); 555 list_splice(&list, &dpm_list);
471 mutex_unlock(&dpm_list_mtx); 556 mutex_unlock(&dpm_list_mtx);
557 dpm_show_time(starttime, state, NULL);
472} 558}
473 559
474/** 560/**
@@ -521,7 +607,7 @@ static void dpm_complete(pm_message_t state)
521 mutex_unlock(&dpm_list_mtx); 607 mutex_unlock(&dpm_list_mtx);
522 608
523 device_complete(dev, state); 609 device_complete(dev, state);
524 pm_runtime_put_noidle(dev); 610 pm_runtime_put_sync(dev);
525 611
526 mutex_lock(&dpm_list_mtx); 612 mutex_lock(&dpm_list_mtx);
527 } 613 }
@@ -584,10 +670,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
584{ 670{
585 int error = 0; 671 int error = 0;
586 672
587 if (!dev->bus) 673 if (dev->bus && dev->bus->pm) {
588 return 0;
589
590 if (dev->bus->pm) {
591 pm_dev_dbg(dev, state, "LATE "); 674 pm_dev_dbg(dev, state, "LATE ");
592 error = pm_noirq_op(dev, dev->bus->pm, state); 675 error = pm_noirq_op(dev, dev->bus->pm, state);
593 } 676 }
@@ -604,6 +687,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
604int dpm_suspend_noirq(pm_message_t state) 687int dpm_suspend_noirq(pm_message_t state)
605{ 688{
606 struct device *dev; 689 struct device *dev;
690 ktime_t starttime = ktime_get();
607 int error = 0; 691 int error = 0;
608 692
609 suspend_device_irqs(); 693 suspend_device_irqs();
@@ -619,11 +703,35 @@ int dpm_suspend_noirq(pm_message_t state)
619 mutex_unlock(&dpm_list_mtx); 703 mutex_unlock(&dpm_list_mtx);
620 if (error) 704 if (error)
621 dpm_resume_noirq(resume_event(state)); 705 dpm_resume_noirq(resume_event(state));
706 else
707 dpm_show_time(starttime, state, "late");
622 return error; 708 return error;
623} 709}
624EXPORT_SYMBOL_GPL(dpm_suspend_noirq); 710EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
625 711
626/** 712/**
713 * legacy_suspend - Execute a legacy (bus or class) suspend callback for device.
714 * @dev: Device to suspend.
715 * @state: PM transition of the system being carried out.
716 * @cb: Suspend callback to execute.
717 */
718static int legacy_suspend(struct device *dev, pm_message_t state,
719 int (*cb)(struct device *dev, pm_message_t state))
720{
721 int error;
722 ktime_t calltime;
723
724 calltime = initcall_debug_start(dev);
725
726 error = cb(dev, state);
727 suspend_report_result(cb, error);
728
729 initcall_debug_report(dev, calltime, error);
730
731 return error;
732}
733
734/**
627 * device_suspend - Execute "suspend" callbacks for given device. 735 * device_suspend - Execute "suspend" callbacks for given device.
628 * @dev: Device to handle. 736 * @dev: Device to handle.
629 * @state: PM transition of the system being carried out. 737 * @state: PM transition of the system being carried out.
@@ -640,8 +748,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
640 error = pm_op(dev, dev->class->pm, state); 748 error = pm_op(dev, dev->class->pm, state);
641 } else if (dev->class->suspend) { 749 } else if (dev->class->suspend) {
642 pm_dev_dbg(dev, state, "legacy class "); 750 pm_dev_dbg(dev, state, "legacy class ");
643 error = dev->class->suspend(dev, state); 751 error = legacy_suspend(dev, state, dev->class->suspend);
644 suspend_report_result(dev->class->suspend, error);
645 } 752 }
646 if (error) 753 if (error)
647 goto End; 754 goto End;
@@ -662,8 +769,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
662 error = pm_op(dev, dev->bus->pm, state); 769 error = pm_op(dev, dev->bus->pm, state);
663 } else if (dev->bus->suspend) { 770 } else if (dev->bus->suspend) {
664 pm_dev_dbg(dev, state, "legacy "); 771 pm_dev_dbg(dev, state, "legacy ");
665 error = dev->bus->suspend(dev, state); 772 error = legacy_suspend(dev, state, dev->bus->suspend);
666 suspend_report_result(dev->bus->suspend, error);
667 } 773 }
668 } 774 }
669 End: 775 End:
@@ -679,6 +785,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
679static int dpm_suspend(pm_message_t state) 785static int dpm_suspend(pm_message_t state)
680{ 786{
681 struct list_head list; 787 struct list_head list;
788 ktime_t starttime = ktime_get();
682 int error = 0; 789 int error = 0;
683 790
684 INIT_LIST_HEAD(&list); 791 INIT_LIST_HEAD(&list);
@@ -704,6 +811,8 @@ static int dpm_suspend(pm_message_t state)
704 } 811 }
705 list_splice(&list, dpm_list.prev); 812 list_splice(&list, dpm_list.prev);
706 mutex_unlock(&dpm_list_mtx); 813 mutex_unlock(&dpm_list_mtx);
814 if (!error)
815 dpm_show_time(starttime, state, NULL);
707 return error; 816 return error;
708} 817}
709 818
@@ -772,7 +881,7 @@ static int dpm_prepare(pm_message_t state)
772 pm_runtime_get_noresume(dev); 881 pm_runtime_get_noresume(dev);
773 if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) { 882 if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
774 /* Wake-up requested during system sleep transition. */ 883 /* Wake-up requested during system sleep transition. */
775 pm_runtime_put_noidle(dev); 884 pm_runtime_put_sync(dev);
776 error = -EBUSY; 885 error = -EBUSY;
777 } else { 886 } else {
778 error = device_prepare(dev, state); 887 error = device_prepare(dev, state);