diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-26 20:22:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-26 20:22:53 -0500 |
commit | 06a79b82b2a3e4bebb9a20638ca208c780e9e507 (patch) | |
tree | 594a11b60ba56d7ae62f8affa4cd61836e70e4b1 /drivers | |
parent | 4912002fffa377e66c5caefc2c311732a4ad5fb8 (diff) | |
parent | a9c9b4429df437982d2fbfab1f4b46b01329e9ed (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
PM / Hibernate: Fix preallocating of memory
PM / Hibernate: Remove swsusp.c finally
PM / Hibernate: Remove trailing space in message
PM: Allow SCSI devices to suspend/resume asynchronously
PM: Allow USB devices to suspend/resume asynchronously
USB: implement non-tree resume ordering constraints for PCI host controllers
PM: Allow PCI devices to suspend/resume asynchronously
PM / Hibernate: Swap, remove useless check from swsusp_read()
PM / Hibernate: Really deprecate deprecated user ioctls
PM: Allow device drivers to use dpm_wait()
PM: Start asynchronous resume threads upfront
PM: Add facility for advanced testing of async suspend/resume
PM: Add a switch for disabling/enabling asynchronous suspend/resume
PM: Asynchronous suspend and resume of devices
PM: Add parent information to timing messages
PM: Document device power attributes in sysfs
PM / Runtime: Add sysfs switch for disabling device run-time PM
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/power/main.c | 143 | ||||
-rw-r--r-- | drivers/base/power/power.h | 6 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 45 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 100 | ||||
-rw-r--r-- | drivers/pci/pci.c | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 1 | ||||
-rw-r--r-- | drivers/pci/probe.c | 1 | ||||
-rw-r--r-- | drivers/scsi/hosts.c | 4 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 8 | ||||
-rw-r--r-- | drivers/usb/core/endpoint.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 127 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 1 |
14 files changed, 428 insertions, 15 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a5142bddef41..0e26a6f6fd48 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 @@ | |||
42 | LIST_HEAD(dpm_list); | 43 | LIST_HEAD(dpm_list); |
43 | 44 | ||
44 | static DEFINE_MUTEX(dpm_list_mtx); | 45 | static DEFINE_MUTEX(dpm_list_mtx); |
46 | static 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; | |||
56 | void device_pm_init(struct device *dev) | 58 | void 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 | */ | ||
199 | static void dpm_wait(struct device *dev, bool async) | ||
200 | { | ||
201 | if (!dev) | ||
202 | return; | ||
203 | |||
204 | if (async || (pm_async_enabled && dev->power.async_suspend)) | ||
205 | wait_for_completion(&dev->power.completion); | ||
206 | } | ||
207 | |||
208 | static int dpm_wait_fn(struct device *dev, void *async_ptr) | ||
209 | { | ||
210 | dpm_wait(dev, *((bool *)async_ptr)); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static 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. |
@@ -271,8 +300,9 @@ static int pm_noirq_op(struct device *dev, | |||
271 | ktime_t calltime, delta, rettime; | 300 | ktime_t calltime, delta, rettime; |
272 | 301 | ||
273 | if (initcall_debug) { | 302 | if (initcall_debug) { |
274 | pr_info("calling %s_i+ @ %i\n", | 303 | pr_info("calling %s+ @ %i, parent: %s\n", |
275 | dev_name(dev), task_pid_nr(current)); | 304 | dev_name(dev), task_pid_nr(current), |
305 | dev->parent ? dev_name(dev->parent) : "none"); | ||
276 | calltime = ktime_get(); | 306 | calltime = ktime_get(); |
277 | } | 307 | } |
278 | 308 | ||
@@ -468,16 +498,20 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) | |||
468 | * device_resume - Execute "resume" callbacks for given device. | 498 | * device_resume - Execute "resume" callbacks for given device. |
469 | * @dev: Device to handle. | 499 | * @dev: Device to handle. |
470 | * @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. | ||
471 | */ | 502 | */ |
472 | static int device_resume(struct device *dev, pm_message_t state) | 503 | static int device_resume(struct device *dev, pm_message_t state, bool async) |
473 | { | 504 | { |
474 | int error = 0; | 505 | int error = 0; |
475 | 506 | ||
476 | TRACE_DEVICE(dev); | 507 | TRACE_DEVICE(dev); |
477 | TRACE_RESUME(0); | 508 | TRACE_RESUME(0); |
478 | 509 | ||
510 | dpm_wait(dev->parent, async); | ||
479 | down(&dev->sem); | 511 | down(&dev->sem); |
480 | 512 | ||
513 | dev->power.status = DPM_RESUMING; | ||
514 | |||
481 | if (dev->bus) { | 515 | if (dev->bus) { |
482 | if (dev->bus->pm) { | 516 | if (dev->bus->pm) { |
483 | pm_dev_dbg(dev, state, ""); | 517 | pm_dev_dbg(dev, state, ""); |
@@ -510,11 +544,29 @@ static int device_resume(struct device *dev, pm_message_t state) | |||
510 | } | 544 | } |
511 | End: | 545 | End: |
512 | up(&dev->sem); | 546 | up(&dev->sem); |
547 | complete_all(&dev->power.completion); | ||
513 | 548 | ||
514 | TRACE_RESUME(error); | 549 | TRACE_RESUME(error); |
515 | return error; | 550 | return error; |
516 | } | 551 | } |
517 | 552 | ||
553 | static void async_resume(void *data, async_cookie_t cookie) | ||
554 | { | ||
555 | struct device *dev = (struct device *)data; | ||
556 | int error; | ||
557 | |||
558 | error = device_resume(dev, pm_transition, true); | ||
559 | if (error) | ||
560 | pm_dev_err(dev, pm_transition, " async", error); | ||
561 | put_device(dev); | ||
562 | } | ||
563 | |||
564 | static bool is_async(struct device *dev) | ||
565 | { | ||
566 | return dev->power.async_suspend && pm_async_enabled | ||
567 | && !pm_trace_is_enabled(); | ||
568 | } | ||
569 | |||
518 | /** | 570 | /** |
519 | * dpm_resume - Execute "resume" callbacks for non-sysdev devices. | 571 | * dpm_resume - Execute "resume" callbacks for non-sysdev devices. |
520 | * @state: PM transition of the system being carried out. | 572 | * @state: PM transition of the system being carried out. |
@@ -525,21 +577,33 @@ static int device_resume(struct device *dev, pm_message_t state) | |||
525 | static void dpm_resume(pm_message_t state) | 577 | static void dpm_resume(pm_message_t state) |
526 | { | 578 | { |
527 | struct list_head list; | 579 | struct list_head list; |
580 | struct device *dev; | ||
528 | ktime_t starttime = ktime_get(); | 581 | ktime_t starttime = ktime_get(); |
529 | 582 | ||
530 | INIT_LIST_HEAD(&list); | 583 | INIT_LIST_HEAD(&list); |
531 | mutex_lock(&dpm_list_mtx); | 584 | mutex_lock(&dpm_list_mtx); |
532 | while (!list_empty(&dpm_list)) { | 585 | pm_transition = state; |
533 | struct device *dev = to_device(dpm_list.next); | 586 | |
587 | list_for_each_entry(dev, &dpm_list, power.entry) { | ||
588 | if (dev->power.status < DPM_OFF) | ||
589 | continue; | ||
590 | |||
591 | INIT_COMPLETION(dev->power.completion); | ||
592 | if (is_async(dev)) { | ||
593 | get_device(dev); | ||
594 | async_schedule(async_resume, dev); | ||
595 | } | ||
596 | } | ||
534 | 597 | ||
598 | while (!list_empty(&dpm_list)) { | ||
599 | dev = to_device(dpm_list.next); | ||
535 | get_device(dev); | 600 | get_device(dev); |
536 | if (dev->power.status >= DPM_OFF) { | 601 | if (dev->power.status >= DPM_OFF && !is_async(dev)) { |
537 | int error; | 602 | int error; |
538 | 603 | ||
539 | dev->power.status = DPM_RESUMING; | ||
540 | mutex_unlock(&dpm_list_mtx); | 604 | mutex_unlock(&dpm_list_mtx); |
541 | 605 | ||
542 | error = device_resume(dev, state); | 606 | error = device_resume(dev, state, false); |
543 | 607 | ||
544 | mutex_lock(&dpm_list_mtx); | 608 | mutex_lock(&dpm_list_mtx); |
545 | if (error) | 609 | if (error) |
@@ -554,6 +618,7 @@ static void dpm_resume(pm_message_t state) | |||
554 | } | 618 | } |
555 | list_splice(&list, &dpm_list); | 619 | list_splice(&list, &dpm_list); |
556 | mutex_unlock(&dpm_list_mtx); | 620 | mutex_unlock(&dpm_list_mtx); |
621 | async_synchronize_full(); | ||
557 | dpm_show_time(starttime, state, NULL); | 622 | dpm_show_time(starttime, state, NULL); |
558 | } | 623 | } |
559 | 624 | ||
@@ -731,17 +796,24 @@ static int legacy_suspend(struct device *dev, pm_message_t state, | |||
731 | return error; | 796 | return error; |
732 | } | 797 | } |
733 | 798 | ||
799 | static int async_error; | ||
800 | |||
734 | /** | 801 | /** |
735 | * device_suspend - Execute "suspend" callbacks for given device. | 802 | * device_suspend - Execute "suspend" callbacks for given device. |
736 | * @dev: Device to handle. | 803 | * @dev: Device to handle. |
737 | * @state: PM transition of the system being carried out. | 804 | * @state: PM transition of the system being carried out. |
805 | * @async: If true, the device is being suspended asynchronously. | ||
738 | */ | 806 | */ |
739 | static int device_suspend(struct device *dev, pm_message_t state) | 807 | static int __device_suspend(struct device *dev, pm_message_t state, bool async) |
740 | { | 808 | { |
741 | int error = 0; | 809 | int error = 0; |
742 | 810 | ||
811 | dpm_wait_for_children(dev, async); | ||
743 | down(&dev->sem); | 812 | down(&dev->sem); |
744 | 813 | ||
814 | if (async_error) | ||
815 | goto End; | ||
816 | |||
745 | if (dev->class) { | 817 | if (dev->class) { |
746 | if (dev->class->pm) { | 818 | if (dev->class->pm) { |
747 | pm_dev_dbg(dev, state, "class "); | 819 | pm_dev_dbg(dev, state, "class "); |
@@ -772,12 +844,44 @@ static int device_suspend(struct device *dev, pm_message_t state) | |||
772 | error = legacy_suspend(dev, state, dev->bus->suspend); | 844 | error = legacy_suspend(dev, state, dev->bus->suspend); |
773 | } | 845 | } |
774 | } | 846 | } |
847 | |||
848 | if (!error) | ||
849 | dev->power.status = DPM_OFF; | ||
850 | |||
775 | End: | 851 | End: |
776 | up(&dev->sem); | 852 | up(&dev->sem); |
853 | complete_all(&dev->power.completion); | ||
777 | 854 | ||
778 | return error; | 855 | return error; |
779 | } | 856 | } |
780 | 857 | ||
858 | static void async_suspend(void *data, async_cookie_t cookie) | ||
859 | { | ||
860 | struct device *dev = (struct device *)data; | ||
861 | int error; | ||
862 | |||
863 | error = __device_suspend(dev, pm_transition, true); | ||
864 | if (error) { | ||
865 | pm_dev_err(dev, pm_transition, " async", error); | ||
866 | async_error = error; | ||
867 | } | ||
868 | |||
869 | put_device(dev); | ||
870 | } | ||
871 | |||
872 | static int device_suspend(struct device *dev) | ||
873 | { | ||
874 | INIT_COMPLETION(dev->power.completion); | ||
875 | |||
876 | if (pm_async_enabled && dev->power.async_suspend) { | ||
877 | get_device(dev); | ||
878 | async_schedule(async_suspend, dev); | ||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | return __device_suspend(dev, pm_transition, false); | ||
883 | } | ||
884 | |||
781 | /** | 885 | /** |
782 | * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. | 886 | * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. |
783 | * @state: PM transition of the system being carried out. | 887 | * @state: PM transition of the system being carried out. |
@@ -790,13 +894,15 @@ static int dpm_suspend(pm_message_t state) | |||
790 | 894 | ||
791 | INIT_LIST_HEAD(&list); | 895 | INIT_LIST_HEAD(&list); |
792 | mutex_lock(&dpm_list_mtx); | 896 | mutex_lock(&dpm_list_mtx); |
897 | pm_transition = state; | ||
898 | async_error = 0; | ||
793 | while (!list_empty(&dpm_list)) { | 899 | while (!list_empty(&dpm_list)) { |
794 | struct device *dev = to_device(dpm_list.prev); | 900 | struct device *dev = to_device(dpm_list.prev); |
795 | 901 | ||
796 | get_device(dev); | 902 | get_device(dev); |
797 | mutex_unlock(&dpm_list_mtx); | 903 | mutex_unlock(&dpm_list_mtx); |
798 | 904 | ||
799 | error = device_suspend(dev, state); | 905 | error = device_suspend(dev); |
800 | 906 | ||
801 | mutex_lock(&dpm_list_mtx); | 907 | mutex_lock(&dpm_list_mtx); |
802 | if (error) { | 908 | if (error) { |
@@ -804,13 +910,17 @@ static int dpm_suspend(pm_message_t state) | |||
804 | put_device(dev); | 910 | put_device(dev); |
805 | break; | 911 | break; |
806 | } | 912 | } |
807 | dev->power.status = DPM_OFF; | ||
808 | if (!list_empty(&dev->power.entry)) | 913 | if (!list_empty(&dev->power.entry)) |
809 | list_move(&dev->power.entry, &list); | 914 | list_move(&dev->power.entry, &list); |
810 | put_device(dev); | 915 | put_device(dev); |
916 | if (async_error) | ||
917 | break; | ||
811 | } | 918 | } |
812 | list_splice(&list, dpm_list.prev); | 919 | list_splice(&list, dpm_list.prev); |
813 | mutex_unlock(&dpm_list_mtx); | 920 | mutex_unlock(&dpm_list_mtx); |
921 | async_synchronize_full(); | ||
922 | if (!error) | ||
923 | error = async_error; | ||
814 | if (!error) | 924 | if (!error) |
815 | dpm_show_time(starttime, state, NULL); | 925 | dpm_show_time(starttime, state, NULL); |
816 | return error; | 926 | return error; |
@@ -936,3 +1046,14 @@ void __suspend_report_result(const char *function, void *fn, int ret) | |||
936 | printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret); | 1046 | printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret); |
937 | } | 1047 | } |
938 | EXPORT_SYMBOL_GPL(__suspend_report_result); | 1048 | EXPORT_SYMBOL_GPL(__suspend_report_result); |
1049 | |||
1050 | /** | ||
1051 | * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete. | ||
1052 | * @dev: Device to wait for. | ||
1053 | * @subordinate: Device that needs to wait for @dev. | ||
1054 | */ | ||
1055 | void device_pm_wait_for_dev(struct device *subordinate, struct device *dev) | ||
1056 | { | ||
1057 | dpm_wait(dev, subordinate->power.async_suspend); | ||
1058 | } | ||
1059 | EXPORT_SYMBOL_GPL(device_pm_wait_for_dev); | ||
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index b8fa1aa5225a..c0bd03c83b9c 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(struct device *dev) {} | |||
12 | 12 | ||
13 | #ifdef CONFIG_PM_SLEEP | 13 | #ifdef CONFIG_PM_SLEEP |
14 | 14 | ||
15 | /* | 15 | /* kernel/power/main.c */ |
16 | * main.c | 16 | extern int pm_async_enabled; |
17 | */ | ||
18 | 17 | ||
18 | /* drivers/base/power/main.c */ | ||
19 | extern struct list_head dpm_list; /* The active device list */ | 19 | extern struct list_head dpm_list; /* The active device list */ |
20 | 20 | ||
21 | static inline struct device *to_device(struct list_head *entry) | 21 | static inline struct device *to_device(struct list_head *entry) |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index f8b044e8aef7..626dd147b75f 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -1011,6 +1011,50 @@ void pm_runtime_enable(struct device *dev) | |||
1011 | EXPORT_SYMBOL_GPL(pm_runtime_enable); | 1011 | EXPORT_SYMBOL_GPL(pm_runtime_enable); |
1012 | 1012 | ||
1013 | /** | 1013 | /** |
1014 | * pm_runtime_forbid - Block run-time PM of a device. | ||
1015 | * @dev: Device to handle. | ||
1016 | * | ||
1017 | * Increase the device's usage count and clear its power.runtime_auto flag, | ||
1018 | * so that it cannot be suspended at run time until pm_runtime_allow() is called | ||
1019 | * for it. | ||
1020 | */ | ||
1021 | void pm_runtime_forbid(struct device *dev) | ||
1022 | { | ||
1023 | spin_lock_irq(&dev->power.lock); | ||
1024 | if (!dev->power.runtime_auto) | ||
1025 | goto out; | ||
1026 | |||
1027 | dev->power.runtime_auto = false; | ||
1028 | atomic_inc(&dev->power.usage_count); | ||
1029 | __pm_runtime_resume(dev, false); | ||
1030 | |||
1031 | out: | ||
1032 | spin_unlock_irq(&dev->power.lock); | ||
1033 | } | ||
1034 | EXPORT_SYMBOL_GPL(pm_runtime_forbid); | ||
1035 | |||
1036 | /** | ||
1037 | * pm_runtime_allow - Unblock run-time PM of a device. | ||
1038 | * @dev: Device to handle. | ||
1039 | * | ||
1040 | * Decrease the device's usage count and set its power.runtime_auto flag. | ||
1041 | */ | ||
1042 | void pm_runtime_allow(struct device *dev) | ||
1043 | { | ||
1044 | spin_lock_irq(&dev->power.lock); | ||
1045 | if (dev->power.runtime_auto) | ||
1046 | goto out; | ||
1047 | |||
1048 | dev->power.runtime_auto = true; | ||
1049 | if (atomic_dec_and_test(&dev->power.usage_count)) | ||
1050 | __pm_runtime_idle(dev); | ||
1051 | |||
1052 | out: | ||
1053 | spin_unlock_irq(&dev->power.lock); | ||
1054 | } | ||
1055 | EXPORT_SYMBOL_GPL(pm_runtime_allow); | ||
1056 | |||
1057 | /** | ||
1014 | * pm_runtime_init - Initialize run-time PM fields in given device object. | 1058 | * pm_runtime_init - Initialize run-time PM fields in given device object. |
1015 | * @dev: Device object to initialize. | 1059 | * @dev: Device object to initialize. |
1016 | */ | 1060 | */ |
@@ -1028,6 +1072,7 @@ void pm_runtime_init(struct device *dev) | |||
1028 | 1072 | ||
1029 | atomic_set(&dev->power.child_count, 0); | 1073 | atomic_set(&dev->power.child_count, 0); |
1030 | pm_suspend_ignore_children(dev, false); | 1074 | pm_suspend_ignore_children(dev, false); |
1075 | dev->power.runtime_auto = true; | ||
1031 | 1076 | ||
1032 | dev->power.request_pending = false; | 1077 | dev->power.request_pending = false; |
1033 | dev->power.request = RPM_REQ_NONE; | 1078 | dev->power.request = RPM_REQ_NONE; |
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 596aeecfdffe..86fd9373447e 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -4,9 +4,25 @@ | |||
4 | 4 | ||
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <linux/string.h> | 6 | #include <linux/string.h> |
7 | #include <linux/pm_runtime.h> | ||
7 | #include "power.h" | 8 | #include "power.h" |
8 | 9 | ||
9 | /* | 10 | /* |
11 | * control - Report/change current runtime PM setting of the device | ||
12 | * | ||
13 | * Runtime power management of a device can be blocked with the help of | ||
14 | * this attribute. All devices have one of the following two values for | ||
15 | * the power/control file: | ||
16 | * | ||
17 | * + "auto\n" to allow the device to be power managed at run time; | ||
18 | * + "on\n" to prevent the device from being power managed at run time; | ||
19 | * | ||
20 | * The default for all devices is "auto", which means that devices may be | ||
21 | * subject to automatic power management, depending on their drivers. | ||
22 | * Changing this attribute to "on" prevents the driver from power managing | ||
23 | * the device at run time. Doing that while the device is suspended causes | ||
24 | * it to be woken up. | ||
25 | * | ||
10 | * wakeup - Report/change current wakeup option for device | 26 | * wakeup - Report/change current wakeup option for device |
11 | * | 27 | * |
12 | * Some devices support "wakeup" events, which are hardware signals | 28 | * Some devices support "wakeup" events, which are hardware signals |
@@ -38,11 +54,61 @@ | |||
38 | * wakeup events internally (unless they are disabled), keeping | 54 | * wakeup events internally (unless they are disabled), keeping |
39 | * their hardware in low power modes whenever they're unused. This | 55 | * their hardware in low power modes whenever they're unused. This |
40 | * saves runtime power, without requiring system-wide sleep states. | 56 | * saves runtime power, without requiring system-wide sleep states. |
57 | * | ||
58 | * async - Report/change current async suspend setting for the device | ||
59 | * | ||
60 | * Asynchronous suspend and resume of the device during system-wide power | ||
61 | * state transitions can be enabled by writing "enabled" to this file. | ||
62 | * Analogously, if "disabled" is written to this file, the device will be | ||
63 | * suspended and resumed synchronously. | ||
64 | * | ||
65 | * All devices have one of the following two values for power/async: | ||
66 | * | ||
67 | * + "enabled\n" to permit the asynchronous suspend/resume of the device; | ||
68 | * + "disabled\n" to forbid it; | ||
69 | * | ||
70 | * NOTE: It generally is unsafe to permit the asynchronous suspend/resume | ||
71 | * of a device unless it is certain that all of the PM dependencies of the | ||
72 | * device are known to the PM core. However, for some devices this | ||
73 | * attribute is set to "enabled" by bus type code or device drivers and in | ||
74 | * that cases it should be safe to leave the default value. | ||
41 | */ | 75 | */ |
42 | 76 | ||
43 | static const char enabled[] = "enabled"; | 77 | static const char enabled[] = "enabled"; |
44 | static const char disabled[] = "disabled"; | 78 | static const char disabled[] = "disabled"; |
45 | 79 | ||
80 | #ifdef CONFIG_PM_RUNTIME | ||
81 | static const char ctrl_auto[] = "auto"; | ||
82 | static const char ctrl_on[] = "on"; | ||
83 | |||
84 | static ssize_t control_show(struct device *dev, struct device_attribute *attr, | ||
85 | char *buf) | ||
86 | { | ||
87 | return sprintf(buf, "%s\n", | ||
88 | dev->power.runtime_auto ? ctrl_auto : ctrl_on); | ||
89 | } | ||
90 | |||
91 | static ssize_t control_store(struct device * dev, struct device_attribute *attr, | ||
92 | const char * buf, size_t n) | ||
93 | { | ||
94 | char *cp; | ||
95 | int len = n; | ||
96 | |||
97 | cp = memchr(buf, '\n', n); | ||
98 | if (cp) | ||
99 | len = cp - buf; | ||
100 | if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0) | ||
101 | pm_runtime_allow(dev); | ||
102 | else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0) | ||
103 | pm_runtime_forbid(dev); | ||
104 | else | ||
105 | return -EINVAL; | ||
106 | return n; | ||
107 | } | ||
108 | |||
109 | static DEVICE_ATTR(control, 0644, control_show, control_store); | ||
110 | #endif | ||
111 | |||
46 | static ssize_t | 112 | static ssize_t |
47 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) | 113 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) |
48 | { | 114 | { |
@@ -77,9 +143,43 @@ wake_store(struct device * dev, struct device_attribute *attr, | |||
77 | 143 | ||
78 | static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); | 144 | static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); |
79 | 145 | ||
146 | #ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG | ||
147 | static ssize_t async_show(struct device *dev, struct device_attribute *attr, | ||
148 | char *buf) | ||
149 | { | ||
150 | return sprintf(buf, "%s\n", | ||
151 | device_async_suspend_enabled(dev) ? enabled : disabled); | ||
152 | } | ||
153 | |||
154 | static ssize_t async_store(struct device *dev, struct device_attribute *attr, | ||
155 | const char *buf, size_t n) | ||
156 | { | ||
157 | char *cp; | ||
158 | int len = n; | ||
159 | |||
160 | cp = memchr(buf, '\n', n); | ||
161 | if (cp) | ||
162 | len = cp - buf; | ||
163 | if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0) | ||
164 | device_enable_async_suspend(dev); | ||
165 | else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0) | ||
166 | device_disable_async_suspend(dev); | ||
167 | else | ||
168 | return -EINVAL; | ||
169 | return n; | ||
170 | } | ||
171 | |||
172 | static DEVICE_ATTR(async, 0644, async_show, async_store); | ||
173 | #endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */ | ||
80 | 174 | ||
81 | static struct attribute * power_attrs[] = { | 175 | static struct attribute * power_attrs[] = { |
176 | #ifdef CONFIG_PM_RUNTIME | ||
177 | &dev_attr_control.attr, | ||
178 | #endif | ||
82 | &dev_attr_wakeup.attr, | 179 | &dev_attr_wakeup.attr, |
180 | #ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG | ||
181 | &dev_attr_async.attr, | ||
182 | #endif | ||
83 | NULL, | 183 | NULL, |
84 | }; | 184 | }; |
85 | static struct attribute_group pm_attr_group = { | 185 | static struct attribute_group pm_attr_group = { |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f4a2738bf0bf..2b9ac9e594af 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1540,6 +1540,7 @@ void pci_pm_init(struct pci_dev *dev) | |||
1540 | int pm; | 1540 | int pm; |
1541 | u16 pmc; | 1541 | u16 pmc; |
1542 | 1542 | ||
1543 | device_enable_async_suspend(&dev->dev); | ||
1543 | dev->wakeup_prepared = false; | 1544 | dev->wakeup_prepared = false; |
1544 | dev->pm_cap = 0; | 1545 | dev->pm_cap = 0; |
1545 | 1546 | ||
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 0d34ff415399..e73effbe402c 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -285,6 +285,7 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq) | |||
285 | pci_name(pdev), | 285 | pci_name(pdev), |
286 | get_descriptor_id(pdev->pcie_type, service)); | 286 | get_descriptor_id(pdev->pcie_type, service)); |
287 | device->parent = &pdev->dev; | 287 | device->parent = &pdev->dev; |
288 | device_enable_async_suspend(device); | ||
288 | 289 | ||
289 | retval = device_register(device); | 290 | retval = device_register(device); |
290 | if (retval) | 291 | if (retval) |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 270d069819f7..2a943090a3b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1436,6 +1436,7 @@ struct pci_bus * pci_create_bus(struct device *parent, | |||
1436 | if (error) | 1436 | if (error) |
1437 | goto dev_reg_err; | 1437 | goto dev_reg_err; |
1438 | b->bridge = get_device(dev); | 1438 | b->bridge = get_device(dev); |
1439 | device_enable_async_suspend(b->bridge); | ||
1439 | 1440 | ||
1440 | if (!parent) | 1441 | if (!parent) |
1441 | set_dev_node(b->bridge, pcibus_to_node(b)); | 1442 | set_dev_node(b->bridge, pcibus_to_node(b)); |
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 554626e18062..09dbcb847b73 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -215,6 +215,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, | |||
215 | shost->shost_gendev.parent = dev ? dev : &platform_bus; | 215 | shost->shost_gendev.parent = dev ? dev : &platform_bus; |
216 | shost->dma_dev = dma_dev; | 216 | shost->dma_dev = dma_dev; |
217 | 217 | ||
218 | device_enable_async_suspend(&shost->shost_gendev); | ||
219 | |||
218 | error = device_add(&shost->shost_gendev); | 220 | error = device_add(&shost->shost_gendev); |
219 | if (error) | 221 | if (error) |
220 | goto out; | 222 | goto out; |
@@ -222,6 +224,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, | |||
222 | scsi_host_set_state(shost, SHOST_RUNNING); | 224 | scsi_host_set_state(shost, SHOST_RUNNING); |
223 | get_device(shost->shost_gendev.parent); | 225 | get_device(shost->shost_gendev.parent); |
224 | 226 | ||
227 | device_enable_async_suspend(&shost->shost_dev); | ||
228 | |||
225 | error = device_add(&shost->shost_dev); | 229 | error = device_add(&shost->shost_dev); |
226 | if (error) | 230 | if (error) |
227 | goto out_del_gendev; | 231 | goto out_del_gendev; |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index a4936c4e2f46..19ec9e2d3f39 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -847,6 +847,8 @@ static int scsi_target_add(struct scsi_target *starget) | |||
847 | if (starget->state != STARGET_CREATED) | 847 | if (starget->state != STARGET_CREATED) |
848 | return 0; | 848 | return 0; |
849 | 849 | ||
850 | device_enable_async_suspend(&starget->dev); | ||
851 | |||
850 | error = device_add(&starget->dev); | 852 | error = device_add(&starget->dev); |
851 | if (error) { | 853 | if (error) { |
852 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); | 854 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); |
@@ -887,11 +889,13 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
887 | return error; | 889 | return error; |
888 | 890 | ||
889 | transport_configure_device(&starget->dev); | 891 | transport_configure_device(&starget->dev); |
892 | device_enable_async_suspend(&sdev->sdev_gendev); | ||
890 | error = device_add(&sdev->sdev_gendev); | 893 | error = device_add(&sdev->sdev_gendev); |
891 | if (error) { | 894 | if (error) { |
892 | printk(KERN_INFO "error 1\n"); | 895 | printk(KERN_INFO "error 1\n"); |
893 | return error; | 896 | return error; |
894 | } | 897 | } |
898 | device_enable_async_suspend(&sdev->sdev_dev); | ||
895 | error = device_add(&sdev->sdev_dev); | 899 | error = device_add(&sdev->sdev_dev); |
896 | if (error) { | 900 | if (error) { |
897 | printk(KERN_INFO "error 2\n"); | 901 | printk(KERN_INFO "error 2\n"); |
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 60a45f1e3a67..f2f055eb6831 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -1022,6 +1022,14 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg) | |||
1022 | goto done; | 1022 | goto done; |
1023 | } | 1023 | } |
1024 | 1024 | ||
1025 | /* Non-root devices on a full/low-speed bus must wait for their | ||
1026 | * companion high-speed root hub, in case a handoff is needed. | ||
1027 | */ | ||
1028 | if (!(msg.event & PM_EVENT_AUTO) && udev->parent && | ||
1029 | udev->bus->hs_companion) | ||
1030 | device_pm_wait_for_dev(&udev->dev, | ||
1031 | &udev->bus->hs_companion->root_hub->dev); | ||
1032 | |||
1025 | if (udev->quirks & USB_QUIRK_RESET_RESUME) | 1033 | if (udev->quirks & USB_QUIRK_RESET_RESUME) |
1026 | udev->reset_resume = 1; | 1034 | udev->reset_resume = 1; |
1027 | 1035 | ||
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index fdfaa7885515..d26b9ea981f9 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c | |||
@@ -186,6 +186,7 @@ int usb_create_ep_devs(struct device *parent, | |||
186 | ep_dev->dev.parent = parent; | 186 | ep_dev->dev.parent = parent; |
187 | ep_dev->dev.release = ep_device_release; | 187 | ep_dev->dev.release = ep_device_release; |
188 | dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); | 188 | dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); |
189 | device_enable_async_suspend(&ep_dev->dev); | ||
189 | 190 | ||
190 | retval = device_register(&ep_dev->dev); | 191 | retval = device_register(&ep_dev->dev); |
191 | if (retval) | 192 | if (retval) |
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 2dcf906df569..15286533c15a 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
23 | 24 | ||
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
@@ -37,6 +38,122 @@ | |||
37 | 38 | ||
38 | /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ | 39 | /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ |
39 | 40 | ||
41 | #ifdef CONFIG_PM_SLEEP | ||
42 | |||
43 | /* Coordinate handoffs between EHCI and companion controllers | ||
44 | * during system resume | ||
45 | */ | ||
46 | |||
47 | static DEFINE_MUTEX(companions_mutex); | ||
48 | |||
49 | #define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI | ||
50 | #define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI | ||
51 | #define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI | ||
52 | |||
53 | enum companion_action { | ||
54 | SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS | ||
55 | }; | ||
56 | |||
57 | static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
58 | enum companion_action action) | ||
59 | { | ||
60 | struct pci_dev *companion; | ||
61 | struct usb_hcd *companion_hcd; | ||
62 | unsigned int slot = PCI_SLOT(pdev->devfn); | ||
63 | |||
64 | /* Iterate through other PCI functions in the same slot. | ||
65 | * If pdev is OHCI or UHCI then we are looking for EHCI, and | ||
66 | * vice versa. | ||
67 | */ | ||
68 | companion = NULL; | ||
69 | for (;;) { | ||
70 | companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion); | ||
71 | if (!companion) | ||
72 | break; | ||
73 | if (companion->bus != pdev->bus || | ||
74 | PCI_SLOT(companion->devfn) != slot) | ||
75 | continue; | ||
76 | |||
77 | companion_hcd = pci_get_drvdata(companion); | ||
78 | if (!companion_hcd) | ||
79 | continue; | ||
80 | |||
81 | /* For SET_HS_COMPANION, store a pointer to the EHCI bus in | ||
82 | * the OHCI/UHCI companion bus structure. | ||
83 | * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus | ||
84 | * in the OHCI/UHCI companion bus structure. | ||
85 | * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI | ||
86 | * companion controllers have fully resumed. | ||
87 | */ | ||
88 | |||
89 | if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && | ||
90 | companion->class == CL_EHCI) { | ||
91 | /* action must be SET_HS_COMPANION */ | ||
92 | dev_dbg(&companion->dev, "HS companion for %s\n", | ||
93 | dev_name(&pdev->dev)); | ||
94 | hcd->self.hs_companion = &companion_hcd->self; | ||
95 | |||
96 | } else if (pdev->class == CL_EHCI && | ||
97 | (companion->class == CL_OHCI || | ||
98 | companion->class == CL_UHCI)) { | ||
99 | switch (action) { | ||
100 | case SET_HS_COMPANION: | ||
101 | dev_dbg(&pdev->dev, "HS companion for %s\n", | ||
102 | dev_name(&companion->dev)); | ||
103 | companion_hcd->self.hs_companion = &hcd->self; | ||
104 | break; | ||
105 | case CLEAR_HS_COMPANION: | ||
106 | companion_hcd->self.hs_companion = NULL; | ||
107 | break; | ||
108 | case WAIT_FOR_COMPANIONS: | ||
109 | device_pm_wait_for_dev(&pdev->dev, | ||
110 | &companion->dev); | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) | ||
118 | { | ||
119 | mutex_lock(&companions_mutex); | ||
120 | dev_set_drvdata(&pdev->dev, hcd); | ||
121 | companion_common(pdev, hcd, SET_HS_COMPANION); | ||
122 | mutex_unlock(&companions_mutex); | ||
123 | } | ||
124 | |||
125 | static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) | ||
126 | { | ||
127 | mutex_lock(&companions_mutex); | ||
128 | dev_set_drvdata(&pdev->dev, NULL); | ||
129 | |||
130 | /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ | ||
131 | if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) | ||
132 | hcd->self.hs_companion = NULL; | ||
133 | |||
134 | /* Otherwise search for companion buses and clear their pointers */ | ||
135 | else | ||
136 | companion_common(pdev, hcd, CLEAR_HS_COMPANION); | ||
137 | mutex_unlock(&companions_mutex); | ||
138 | } | ||
139 | |||
140 | static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) | ||
141 | { | ||
142 | /* Only EHCI controllers need to wait. | ||
143 | * No locking is needed because a controller cannot be resumed | ||
144 | * while one of its companions is getting unbound. | ||
145 | */ | ||
146 | if (pdev->class == CL_EHCI) | ||
147 | companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); | ||
148 | } | ||
149 | |||
150 | #else /* !CONFIG_PM_SLEEP */ | ||
151 | |||
152 | static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} | ||
153 | static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} | ||
154 | static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} | ||
155 | |||
156 | #endif /* !CONFIG_PM_SLEEP */ | ||
40 | 157 | ||
41 | /*-------------------------------------------------------------------------*/ | 158 | /*-------------------------------------------------------------------------*/ |
42 | 159 | ||
@@ -123,7 +240,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
123 | if (region == PCI_ROM_RESOURCE) { | 240 | if (region == PCI_ROM_RESOURCE) { |
124 | dev_dbg(&dev->dev, "no i/o regions available\n"); | 241 | dev_dbg(&dev->dev, "no i/o regions available\n"); |
125 | retval = -EBUSY; | 242 | retval = -EBUSY; |
126 | goto err1; | 243 | goto err2; |
127 | } | 244 | } |
128 | } | 245 | } |
129 | 246 | ||
@@ -132,6 +249,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
132 | retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); | 249 | retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); |
133 | if (retval != 0) | 250 | if (retval != 0) |
134 | goto err4; | 251 | goto err4; |
252 | set_hs_companion(dev, hcd); | ||
135 | return retval; | 253 | return retval; |
136 | 254 | ||
137 | err4: | 255 | err4: |
@@ -142,6 +260,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
142 | } else | 260 | } else |
143 | release_region(hcd->rsrc_start, hcd->rsrc_len); | 261 | release_region(hcd->rsrc_start, hcd->rsrc_len); |
144 | err2: | 262 | err2: |
263 | clear_hs_companion(dev, hcd); | ||
145 | usb_put_hcd(hcd); | 264 | usb_put_hcd(hcd); |
146 | err1: | 265 | err1: |
147 | pci_disable_device(dev); | 266 | pci_disable_device(dev); |
@@ -180,6 +299,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev) | |||
180 | } else { | 299 | } else { |
181 | release_region(hcd->rsrc_start, hcd->rsrc_len); | 300 | release_region(hcd->rsrc_start, hcd->rsrc_len); |
182 | } | 301 | } |
302 | clear_hs_companion(dev, hcd); | ||
183 | usb_put_hcd(hcd); | 303 | usb_put_hcd(hcd); |
184 | pci_disable_device(dev); | 304 | pci_disable_device(dev); |
185 | } | 305 | } |
@@ -344,6 +464,11 @@ static int resume_common(struct device *dev, bool hibernated) | |||
344 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); | 464 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
345 | 465 | ||
346 | if (hcd->driver->pci_resume) { | 466 | if (hcd->driver->pci_resume) { |
467 | /* This call should be made only during system resume, | ||
468 | * not during runtime resume. | ||
469 | */ | ||
470 | wait_for_companions(pci_dev, hcd); | ||
471 | |||
347 | retval = hcd->driver->pci_resume(hcd, hibernated); | 472 | retval = hcd->driver->pci_resume(hcd, hibernated); |
348 | if (retval) { | 473 | if (retval) { |
349 | dev_err(dev, "PCI post-resume error %d!\n", retval); | 474 | dev_err(dev, "PCI post-resume error %d!\n", retval); |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 35cc8b9ba1f5..20ecb4cec8de 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1817,6 +1817,7 @@ int usb_new_device(struct usb_device *udev) | |||
1817 | /* Tell the world! */ | 1817 | /* Tell the world! */ |
1818 | announce_device(udev); | 1818 | announce_device(udev); |
1819 | 1819 | ||
1820 | device_enable_async_suspend(&udev->dev); | ||
1820 | /* Register the device. The device driver is responsible | 1821 | /* Register the device. The device driver is responsible |
1821 | * for configuring the device and invoking the add-device | 1822 | * for configuring the device and invoking the add-device |
1822 | * notifier chain (used by usbfs and possibly others). | 1823 | * notifier chain (used by usbfs and possibly others). |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 9bc95fec793f..df73574a9cc9 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1867,6 +1867,7 @@ free_interfaces: | |||
1867 | "adding %s (config #%d, interface %d)\n", | 1867 | "adding %s (config #%d, interface %d)\n", |
1868 | dev_name(&intf->dev), configuration, | 1868 | dev_name(&intf->dev), configuration, |
1869 | intf->cur_altsetting->desc.bInterfaceNumber); | 1869 | intf->cur_altsetting->desc.bInterfaceNumber); |
1870 | device_enable_async_suspend(&intf->dev); | ||
1870 | ret = device_add(&intf->dev); | 1871 | ret = device_add(&intf->dev); |
1871 | if (ret != 0) { | 1872 | if (ret != 0) { |
1872 | dev_err(&dev->dev, "device_add(%s) --> %d\n", | 1873 | dev_err(&dev->dev, "device_add(%s) --> %d\n", |