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.c115
1 files changed, 109 insertions, 6 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 6ca5cdf63849..3b44c201ddad 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -25,6 +25,7 @@
25#include <linux/resume-trace.h> 25#include <linux/resume-trace.h>
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/async.h>
28 29
29#include "../base.h" 30#include "../base.h"
30#include "power.h" 31#include "power.h"
@@ -42,6 +43,7 @@
42LIST_HEAD(dpm_list); 43LIST_HEAD(dpm_list);
43 44
44static DEFINE_MUTEX(dpm_list_mtx); 45static DEFINE_MUTEX(dpm_list_mtx);
46static pm_message_t pm_transition;
45 47
46/* 48/*
47 * Set once the preparation of devices for a PM transition has started, reset 49 * Set once the preparation of devices for a PM transition has started, reset
@@ -56,6 +58,7 @@ static bool transition_started;
56void device_pm_init(struct device *dev) 58void device_pm_init(struct device *dev)
57{ 59{
58 dev->power.status = DPM_ON; 60 dev->power.status = DPM_ON;
61 init_completion(&dev->power.completion);
59 pm_runtime_init(dev); 62 pm_runtime_init(dev);
60} 63}
61 64
@@ -111,6 +114,7 @@ void device_pm_remove(struct device *dev)
111 pr_debug("PM: Removing info for %s:%s\n", 114 pr_debug("PM: Removing info for %s:%s\n",
112 dev->bus ? dev->bus->name : "No Bus", 115 dev->bus ? dev->bus->name : "No Bus",
113 kobject_name(&dev->kobj)); 116 kobject_name(&dev->kobj));
117 complete_all(&dev->power.completion);
114 mutex_lock(&dpm_list_mtx); 118 mutex_lock(&dpm_list_mtx);
115 list_del_init(&dev->power.entry); 119 list_del_init(&dev->power.entry);
116 mutex_unlock(&dpm_list_mtx); 120 mutex_unlock(&dpm_list_mtx);
@@ -188,6 +192,31 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
188} 192}
189 193
190/** 194/**
195 * dpm_wait - Wait for a PM operation to complete.
196 * @dev: Device to wait for.
197 * @async: If unset, wait only if the device's power.async_suspend flag is set.
198 */
199static void dpm_wait(struct device *dev, bool async)
200{
201 if (!dev)
202 return;
203
204 if (async || dev->power.async_suspend)
205 wait_for_completion(&dev->power.completion);
206}
207
208static int dpm_wait_fn(struct device *dev, void *async_ptr)
209{
210 dpm_wait(dev, *((bool *)async_ptr));
211 return 0;
212}
213
214static void dpm_wait_for_children(struct device *dev, bool async)
215{
216 device_for_each_child(dev, &async, dpm_wait_fn);
217}
218
219/**
191 * pm_op - Execute the PM operation appropriate for given PM event. 220 * pm_op - Execute the PM operation appropriate for given PM event.
192 * @dev: Device to handle. 221 * @dev: Device to handle.
193 * @ops: PM operations to choose from. 222 * @ops: PM operations to choose from.
@@ -466,17 +495,19 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
466} 495}
467 496
468/** 497/**
469 * device_resume - Execute "resume" callbacks for given device. 498 * __device_resume - Execute "resume" callbacks for given device.
470 * @dev: Device to handle. 499 * @dev: Device to handle.
471 * @state: PM transition of the system being carried out. 500 * @state: PM transition of the system being carried out.
501 * @async: If true, the device is being resumed asynchronously.
472 */ 502 */
473static int device_resume(struct device *dev, pm_message_t state) 503static int __device_resume(struct device *dev, pm_message_t state, bool async)
474{ 504{
475 int error = 0; 505 int error = 0;
476 506
477 TRACE_DEVICE(dev); 507 TRACE_DEVICE(dev);
478 TRACE_RESUME(0); 508 TRACE_RESUME(0);
479 509
510 dpm_wait(dev->parent, async);
480 down(&dev->sem); 511 down(&dev->sem);
481 512
482 if (dev->bus) { 513 if (dev->bus) {
@@ -511,11 +542,36 @@ static int device_resume(struct device *dev, pm_message_t state)
511 } 542 }
512 End: 543 End:
513 up(&dev->sem); 544 up(&dev->sem);
545 complete_all(&dev->power.completion);
514 546
515 TRACE_RESUME(error); 547 TRACE_RESUME(error);
516 return error; 548 return error;
517} 549}
518 550
551static void async_resume(void *data, async_cookie_t cookie)
552{
553 struct device *dev = (struct device *)data;
554 int error;
555
556 error = __device_resume(dev, pm_transition, true);
557 if (error)
558 pm_dev_err(dev, pm_transition, " async", error);
559 put_device(dev);
560}
561
562static int device_resume(struct device *dev)
563{
564 INIT_COMPLETION(dev->power.completion);
565
566 if (dev->power.async_suspend && !pm_trace_is_enabled()) {
567 get_device(dev);
568 async_schedule(async_resume, dev);
569 return 0;
570 }
571
572 return __device_resume(dev, pm_transition, false);
573}
574
519/** 575/**
520 * dpm_resume - Execute "resume" callbacks for non-sysdev devices. 576 * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
521 * @state: PM transition of the system being carried out. 577 * @state: PM transition of the system being carried out.
@@ -530,6 +586,7 @@ static void dpm_resume(pm_message_t state)
530 586
531 INIT_LIST_HEAD(&list); 587 INIT_LIST_HEAD(&list);
532 mutex_lock(&dpm_list_mtx); 588 mutex_lock(&dpm_list_mtx);
589 pm_transition = state;
533 while (!list_empty(&dpm_list)) { 590 while (!list_empty(&dpm_list)) {
534 struct device *dev = to_device(dpm_list.next); 591 struct device *dev = to_device(dpm_list.next);
535 592
@@ -540,7 +597,7 @@ static void dpm_resume(pm_message_t state)
540 dev->power.status = DPM_RESUMING; 597 dev->power.status = DPM_RESUMING;
541 mutex_unlock(&dpm_list_mtx); 598 mutex_unlock(&dpm_list_mtx);
542 599
543 error = device_resume(dev, state); 600 error = device_resume(dev);
544 601
545 mutex_lock(&dpm_list_mtx); 602 mutex_lock(&dpm_list_mtx);
546 if (error) 603 if (error)
@@ -555,6 +612,7 @@ static void dpm_resume(pm_message_t state)
555 } 612 }
556 list_splice(&list, &dpm_list); 613 list_splice(&list, &dpm_list);
557 mutex_unlock(&dpm_list_mtx); 614 mutex_unlock(&dpm_list_mtx);
615 async_synchronize_full();
558 dpm_show_time(starttime, state, NULL); 616 dpm_show_time(starttime, state, NULL);
559} 617}
560 618
@@ -732,17 +790,24 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
732 return error; 790 return error;
733} 791}
734 792
793static int async_error;
794
735/** 795/**
736 * device_suspend - Execute "suspend" callbacks for given device. 796 * device_suspend - Execute "suspend" callbacks for given device.
737 * @dev: Device to handle. 797 * @dev: Device to handle.
738 * @state: PM transition of the system being carried out. 798 * @state: PM transition of the system being carried out.
799 * @async: If true, the device is being suspended asynchronously.
739 */ 800 */
740static int device_suspend(struct device *dev, pm_message_t state) 801static int __device_suspend(struct device *dev, pm_message_t state, bool async)
741{ 802{
742 int error = 0; 803 int error = 0;
743 804
805 dpm_wait_for_children(dev, async);
744 down(&dev->sem); 806 down(&dev->sem);
745 807
808 if (async_error)
809 goto End;
810
746 if (dev->class) { 811 if (dev->class) {
747 if (dev->class->pm) { 812 if (dev->class->pm) {
748 pm_dev_dbg(dev, state, "class "); 813 pm_dev_dbg(dev, state, "class ");
@@ -773,12 +838,44 @@ static int device_suspend(struct device *dev, pm_message_t state)
773 error = legacy_suspend(dev, state, dev->bus->suspend); 838 error = legacy_suspend(dev, state, dev->bus->suspend);
774 } 839 }
775 } 840 }
841
842 if (!error)
843 dev->power.status = DPM_OFF;
844
776 End: 845 End:
777 up(&dev->sem); 846 up(&dev->sem);
847 complete_all(&dev->power.completion);
778 848
779 return error; 849 return error;
780} 850}
781 851
852static void async_suspend(void *data, async_cookie_t cookie)
853{
854 struct device *dev = (struct device *)data;
855 int error;
856
857 error = __device_suspend(dev, pm_transition, true);
858 if (error) {
859 pm_dev_err(dev, pm_transition, " async", error);
860 async_error = error;
861 }
862
863 put_device(dev);
864}
865
866static int device_suspend(struct device *dev)
867{
868 INIT_COMPLETION(dev->power.completion);
869
870 if (dev->power.async_suspend) {
871 get_device(dev);
872 async_schedule(async_suspend, dev);
873 return 0;
874 }
875
876 return __device_suspend(dev, pm_transition, false);
877}
878
782/** 879/**
783 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. 880 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
784 * @state: PM transition of the system being carried out. 881 * @state: PM transition of the system being carried out.
@@ -791,13 +888,15 @@ static int dpm_suspend(pm_message_t state)
791 888
792 INIT_LIST_HEAD(&list); 889 INIT_LIST_HEAD(&list);
793 mutex_lock(&dpm_list_mtx); 890 mutex_lock(&dpm_list_mtx);
891 pm_transition = state;
892 async_error = 0;
794 while (!list_empty(&dpm_list)) { 893 while (!list_empty(&dpm_list)) {
795 struct device *dev = to_device(dpm_list.prev); 894 struct device *dev = to_device(dpm_list.prev);
796 895
797 get_device(dev); 896 get_device(dev);
798 mutex_unlock(&dpm_list_mtx); 897 mutex_unlock(&dpm_list_mtx);
799 898
800 error = device_suspend(dev, state); 899 error = device_suspend(dev);
801 900
802 mutex_lock(&dpm_list_mtx); 901 mutex_lock(&dpm_list_mtx);
803 if (error) { 902 if (error) {
@@ -805,13 +904,17 @@ static int dpm_suspend(pm_message_t state)
805 put_device(dev); 904 put_device(dev);
806 break; 905 break;
807 } 906 }
808 dev->power.status = DPM_OFF;
809 if (!list_empty(&dev->power.entry)) 907 if (!list_empty(&dev->power.entry))
810 list_move(&dev->power.entry, &list); 908 list_move(&dev->power.entry, &list);
811 put_device(dev); 909 put_device(dev);
910 if (async_error)
911 break;
812 } 912 }
813 list_splice(&list, dpm_list.prev); 913 list_splice(&list, dpm_list.prev);
814 mutex_unlock(&dpm_list_mtx); 914 mutex_unlock(&dpm_list_mtx);
915 async_synchronize_full();
916 if (!error)
917 error = async_error;
815 if (!error) 918 if (!error)
816 dpm_show_time(starttime, state, NULL); 919 dpm_show_time(starttime, state, NULL);
817 return error; 920 return error;