diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 12:24:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 12:24:44 -0400 |
commit | fc82e1d59a24cbac01c49d4eb3b28d6abc26a5f4 (patch) | |
tree | 5e01479d69e69dbbe483044b39afd2aa99d4f2b2 /drivers | |
parent | 48d5f6731837f0ec9a0e19ca763aa17d58385a98 (diff) | |
parent | bea3864fb627d110933cfb8babe048b63c4fc76e (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: (21 commits)
PM / Hibernate: Reduce autotuned default image size
PM / Core: Introduce struct syscore_ops for core subsystems PM
PM QoS: Make pm_qos settings readable
PM / OPP: opp_find_freq_exact() documentation fix
PM: Documentation/power/states.txt: fix repetition
PM: Make system-wide PM and runtime PM treat subsystems consistently
PM: Simplify kernel/power/Kconfig
PM: Add support for device power domains
PM: Drop pm_flags that is not necessary
PM: Allow pm_runtime_suspend() to succeed during system suspend
PM: Clean up PM_TRACE dependencies and drop unnecessary Kconfig option
PM: Remove CONFIG_PM_OPS
PM: Reorder power management Kconfig options
PM: Make CONFIG_PM depend on (CONFIG_PM_SLEEP || CONFIG_PM_RUNTIME)
PM / ACPI: Remove references to pm_flags from bus.c
PM: Do not create wakeup sysfs files for devices that cannot wake up
USB / Hub: Do not call device_set_wakeup_capable() under spinlock
PM: Use appropriate printk() priority level in trace.c
PM / Wakeup: Don't update events_check_enabled in pm_get_wakeup_count()
PM / Wakeup: Make pm_save_wakeup_count() work as documented
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/Kconfig | 1 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 23 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 4 | ||||
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 3 | ||||
-rw-r--r-- | drivers/base/power/main.c | 175 | ||||
-rw-r--r-- | drivers/base/power/opp.c | 2 | ||||
-rw-r--r-- | drivers/base/power/power.h | 21 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 37 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 78 | ||||
-rw-r--r-- | drivers/base/power/trace.c | 6 | ||||
-rw-r--r-- | drivers/base/power/wakeup.c | 109 | ||||
-rw-r--r-- | drivers/base/syscore.c | 117 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 8 | ||||
-rw-r--r-- | drivers/net/pch_gbe/pch_gbe_main.c | 2 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 4 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 10 |
21 files changed, 405 insertions, 207 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 2aa042a5da6d..3a17ca5fff6f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -7,7 +7,6 @@ menuconfig ACPI | |||
7 | depends on !IA64_HP_SIM | 7 | depends on !IA64_HP_SIM |
8 | depends on IA64 || X86 | 8 | depends on IA64 || X86 |
9 | depends on PCI | 9 | depends on PCI |
10 | depends on PM | ||
11 | select PNP | 10 | select PNP |
12 | default y | 11 | default y |
13 | help | 12 | help |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 7ced61f39492..9749980ca6ca 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <acpi/acpi_bus.h> | 40 | #include <acpi/acpi_bus.h> |
41 | #include <acpi/acpi_drivers.h> | 41 | #include <acpi/acpi_drivers.h> |
42 | #include <linux/dmi.h> | 42 | #include <linux/dmi.h> |
43 | #include <linux/suspend.h> | ||
43 | 44 | ||
44 | #include "internal.h" | 45 | #include "internal.h" |
45 | 46 | ||
@@ -1006,8 +1007,7 @@ struct kobject *acpi_kobj; | |||
1006 | 1007 | ||
1007 | static int __init acpi_init(void) | 1008 | static int __init acpi_init(void) |
1008 | { | 1009 | { |
1009 | int result = 0; | 1010 | int result; |
1010 | |||
1011 | 1011 | ||
1012 | if (acpi_disabled) { | 1012 | if (acpi_disabled) { |
1013 | printk(KERN_INFO PREFIX "Interpreter disabled.\n"); | 1013 | printk(KERN_INFO PREFIX "Interpreter disabled.\n"); |
@@ -1022,29 +1022,18 @@ static int __init acpi_init(void) | |||
1022 | 1022 | ||
1023 | init_acpi_device_notify(); | 1023 | init_acpi_device_notify(); |
1024 | result = acpi_bus_init(); | 1024 | result = acpi_bus_init(); |
1025 | 1025 | if (result) { | |
1026 | if (!result) { | ||
1027 | pci_mmcfg_late_init(); | ||
1028 | if (!(pm_flags & PM_APM)) | ||
1029 | pm_flags |= PM_ACPI; | ||
1030 | else { | ||
1031 | printk(KERN_INFO PREFIX | ||
1032 | "APM is already active, exiting\n"); | ||
1033 | disable_acpi(); | ||
1034 | result = -ENODEV; | ||
1035 | } | ||
1036 | } else | ||
1037 | disable_acpi(); | 1026 | disable_acpi(); |
1038 | |||
1039 | if (acpi_disabled) | ||
1040 | return result; | 1027 | return result; |
1028 | } | ||
1041 | 1029 | ||
1030 | pci_mmcfg_late_init(); | ||
1042 | acpi_scan_init(); | 1031 | acpi_scan_init(); |
1043 | acpi_ec_init(); | 1032 | acpi_ec_init(); |
1044 | acpi_debugfs_init(); | 1033 | acpi_debugfs_init(); |
1045 | acpi_sleep_proc_init(); | 1034 | acpi_sleep_proc_init(); |
1046 | acpi_wakeup_device_init(); | 1035 | acpi_wakeup_device_init(); |
1047 | return result; | 1036 | return 0; |
1048 | } | 1037 | } |
1049 | 1038 | ||
1050 | subsys_initcall(acpi_init); | 1039 | subsys_initcall(acpi_init); |
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index d6a8cd14de2e..8ea092fad3f6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -585,7 +585,7 @@ int acpi_suspend(u32 acpi_state) | |||
585 | return -EINVAL; | 585 | return -EINVAL; |
586 | } | 586 | } |
587 | 587 | ||
588 | #ifdef CONFIG_PM_OPS | 588 | #ifdef CONFIG_PM |
589 | /** | 589 | /** |
590 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device | 590 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device |
591 | * in the system sleep state given by %acpi_target_sleep_state | 591 | * in the system sleep state given by %acpi_target_sleep_state |
@@ -671,7 +671,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
671 | *d_min_p = d_min; | 671 | *d_min_p = d_min; |
672 | return d_max; | 672 | return d_max; |
673 | } | 673 | } |
674 | #endif /* CONFIG_PM_OPS */ | 674 | #endif /* CONFIG_PM */ |
675 | 675 | ||
676 | #ifdef CONFIG_PM_SLEEP | 676 | #ifdef CONFIG_PM_SLEEP |
677 | /** | 677 | /** |
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 5f51c3b4451e..4c5701c15f53 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | # Makefile for the Linux device tree | 1 | # Makefile for the Linux device tree |
2 | 2 | ||
3 | obj-y := core.o sys.o bus.o dd.o \ | 3 | obj-y := core.o sys.o bus.o dd.o syscore.o \ |
4 | driver.o class.o platform.o \ | 4 | driver.o class.o platform.o \ |
5 | cpu.o firmware.o init.o map.o devres.o \ | 5 | cpu.o firmware.o init.o map.o devres.o \ |
6 | attribute_container.o transport_class.o | 6 | attribute_container.o transport_class.o |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index abe46edfe5b4..118c1b92a511 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | obj-$(CONFIG_PM) += sysfs.o | 1 | obj-$(CONFIG_PM) += sysfs.o generic_ops.o |
2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o | 2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o |
3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o | 3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o |
4 | obj-$(CONFIG_PM_OPS) += generic_ops.o | ||
5 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
6 | obj-$(CONFIG_PM_OPP) += opp.o | 5 | obj-$(CONFIG_PM_OPP) += opp.o |
7 | 6 | ||
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 83404973f97a..052dc53eef38 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -423,26 +423,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
423 | TRACE_DEVICE(dev); | 423 | TRACE_DEVICE(dev); |
424 | TRACE_RESUME(0); | 424 | TRACE_RESUME(0); |
425 | 425 | ||
426 | if (dev->bus && dev->bus->pm) { | 426 | if (dev->pwr_domain) { |
427 | pm_dev_dbg(dev, state, "EARLY "); | 427 | pm_dev_dbg(dev, state, "EARLY power domain "); |
428 | error = pm_noirq_op(dev, dev->bus->pm, state); | 428 | pm_noirq_op(dev, &dev->pwr_domain->ops, state); |
429 | if (error) | ||
430 | goto End; | ||
431 | } | 429 | } |
432 | 430 | ||
433 | if (dev->type && dev->type->pm) { | 431 | if (dev->type && dev->type->pm) { |
434 | pm_dev_dbg(dev, state, "EARLY type "); | 432 | pm_dev_dbg(dev, state, "EARLY type "); |
435 | error = pm_noirq_op(dev, dev->type->pm, state); | 433 | error = pm_noirq_op(dev, dev->type->pm, state); |
436 | if (error) | 434 | } else if (dev->class && dev->class->pm) { |
437 | goto End; | ||
438 | } | ||
439 | |||
440 | if (dev->class && dev->class->pm) { | ||
441 | pm_dev_dbg(dev, state, "EARLY class "); | 435 | pm_dev_dbg(dev, state, "EARLY class "); |
442 | error = pm_noirq_op(dev, dev->class->pm, state); | 436 | error = pm_noirq_op(dev, dev->class->pm, state); |
437 | } else if (dev->bus && dev->bus->pm) { | ||
438 | pm_dev_dbg(dev, state, "EARLY "); | ||
439 | error = pm_noirq_op(dev, dev->bus->pm, state); | ||
443 | } | 440 | } |
444 | 441 | ||
445 | End: | ||
446 | TRACE_RESUME(error); | 442 | TRACE_RESUME(error); |
447 | return error; | 443 | return error; |
448 | } | 444 | } |
@@ -518,36 +514,39 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
518 | 514 | ||
519 | dev->power.in_suspend = false; | 515 | dev->power.in_suspend = false; |
520 | 516 | ||
521 | if (dev->bus) { | 517 | if (dev->pwr_domain) { |
522 | if (dev->bus->pm) { | 518 | pm_dev_dbg(dev, state, "power domain "); |
523 | pm_dev_dbg(dev, state, ""); | 519 | pm_op(dev, &dev->pwr_domain->ops, state); |
524 | error = pm_op(dev, dev->bus->pm, state); | ||
525 | } else if (dev->bus->resume) { | ||
526 | pm_dev_dbg(dev, state, "legacy "); | ||
527 | error = legacy_resume(dev, dev->bus->resume); | ||
528 | } | ||
529 | if (error) | ||
530 | goto End; | ||
531 | } | 520 | } |
532 | 521 | ||
533 | if (dev->type) { | 522 | if (dev->type && dev->type->pm) { |
534 | if (dev->type->pm) { | 523 | pm_dev_dbg(dev, state, "type "); |
535 | pm_dev_dbg(dev, state, "type "); | 524 | error = pm_op(dev, dev->type->pm, state); |
536 | error = pm_op(dev, dev->type->pm, state); | 525 | goto End; |
537 | } | ||
538 | if (error) | ||
539 | goto End; | ||
540 | } | 526 | } |
541 | 527 | ||
542 | if (dev->class) { | 528 | if (dev->class) { |
543 | if (dev->class->pm) { | 529 | if (dev->class->pm) { |
544 | pm_dev_dbg(dev, state, "class "); | 530 | pm_dev_dbg(dev, state, "class "); |
545 | error = pm_op(dev, dev->class->pm, state); | 531 | error = pm_op(dev, dev->class->pm, state); |
532 | goto End; | ||
546 | } else if (dev->class->resume) { | 533 | } else if (dev->class->resume) { |
547 | pm_dev_dbg(dev, state, "legacy class "); | 534 | pm_dev_dbg(dev, state, "legacy class "); |
548 | error = legacy_resume(dev, dev->class->resume); | 535 | error = legacy_resume(dev, dev->class->resume); |
536 | goto End; | ||
549 | } | 537 | } |
550 | } | 538 | } |
539 | |||
540 | if (dev->bus) { | ||
541 | if (dev->bus->pm) { | ||
542 | pm_dev_dbg(dev, state, ""); | ||
543 | error = pm_op(dev, dev->bus->pm, state); | ||
544 | } else if (dev->bus->resume) { | ||
545 | pm_dev_dbg(dev, state, "legacy "); | ||
546 | error = legacy_resume(dev, dev->bus->resume); | ||
547 | } | ||
548 | } | ||
549 | |||
551 | End: | 550 | End: |
552 | device_unlock(dev); | 551 | device_unlock(dev); |
553 | complete_all(&dev->power.completion); | 552 | complete_all(&dev->power.completion); |
@@ -629,19 +628,23 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
629 | { | 628 | { |
630 | device_lock(dev); | 629 | device_lock(dev); |
631 | 630 | ||
632 | if (dev->class && dev->class->pm && dev->class->pm->complete) { | 631 | if (dev->pwr_domain && dev->pwr_domain->ops.complete) { |
633 | pm_dev_dbg(dev, state, "completing class "); | 632 | pm_dev_dbg(dev, state, "completing power domain "); |
634 | dev->class->pm->complete(dev); | 633 | dev->pwr_domain->ops.complete(dev); |
635 | } | 634 | } |
636 | 635 | ||
637 | if (dev->type && dev->type->pm && dev->type->pm->complete) { | 636 | if (dev->type && dev->type->pm) { |
638 | pm_dev_dbg(dev, state, "completing type "); | 637 | pm_dev_dbg(dev, state, "completing type "); |
639 | dev->type->pm->complete(dev); | 638 | if (dev->type->pm->complete) |
640 | } | 639 | dev->type->pm->complete(dev); |
641 | 640 | } else if (dev->class && dev->class->pm) { | |
642 | if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { | 641 | pm_dev_dbg(dev, state, "completing class "); |
642 | if (dev->class->pm->complete) | ||
643 | dev->class->pm->complete(dev); | ||
644 | } else if (dev->bus && dev->bus->pm) { | ||
643 | pm_dev_dbg(dev, state, "completing "); | 645 | pm_dev_dbg(dev, state, "completing "); |
644 | dev->bus->pm->complete(dev); | 646 | if (dev->bus->pm->complete) |
647 | dev->bus->pm->complete(dev); | ||
645 | } | 648 | } |
646 | 649 | ||
647 | device_unlock(dev); | 650 | device_unlock(dev); |
@@ -669,7 +672,6 @@ static void dpm_complete(pm_message_t state) | |||
669 | mutex_unlock(&dpm_list_mtx); | 672 | mutex_unlock(&dpm_list_mtx); |
670 | 673 | ||
671 | device_complete(dev, state); | 674 | device_complete(dev, state); |
672 | pm_runtime_put_sync(dev); | ||
673 | 675 | ||
674 | mutex_lock(&dpm_list_mtx); | 676 | mutex_lock(&dpm_list_mtx); |
675 | put_device(dev); | 677 | put_device(dev); |
@@ -727,29 +729,31 @@ static pm_message_t resume_event(pm_message_t sleep_state) | |||
727 | */ | 729 | */ |
728 | static int device_suspend_noirq(struct device *dev, pm_message_t state) | 730 | static int device_suspend_noirq(struct device *dev, pm_message_t state) |
729 | { | 731 | { |
730 | int error = 0; | 732 | int error; |
731 | |||
732 | if (dev->class && dev->class->pm) { | ||
733 | pm_dev_dbg(dev, state, "LATE class "); | ||
734 | error = pm_noirq_op(dev, dev->class->pm, state); | ||
735 | if (error) | ||
736 | goto End; | ||
737 | } | ||
738 | 733 | ||
739 | if (dev->type && dev->type->pm) { | 734 | if (dev->type && dev->type->pm) { |
740 | pm_dev_dbg(dev, state, "LATE type "); | 735 | pm_dev_dbg(dev, state, "LATE type "); |
741 | error = pm_noirq_op(dev, dev->type->pm, state); | 736 | error = pm_noirq_op(dev, dev->type->pm, state); |
742 | if (error) | 737 | if (error) |
743 | goto End; | 738 | return error; |
744 | } | 739 | } else if (dev->class && dev->class->pm) { |
745 | 740 | pm_dev_dbg(dev, state, "LATE class "); | |
746 | if (dev->bus && dev->bus->pm) { | 741 | error = pm_noirq_op(dev, dev->class->pm, state); |
742 | if (error) | ||
743 | return error; | ||
744 | } else if (dev->bus && dev->bus->pm) { | ||
747 | pm_dev_dbg(dev, state, "LATE "); | 745 | pm_dev_dbg(dev, state, "LATE "); |
748 | error = pm_noirq_op(dev, dev->bus->pm, state); | 746 | error = pm_noirq_op(dev, dev->bus->pm, state); |
747 | if (error) | ||
748 | return error; | ||
749 | } | 749 | } |
750 | 750 | ||
751 | End: | 751 | if (dev->pwr_domain) { |
752 | return error; | 752 | pm_dev_dbg(dev, state, "LATE power domain "); |
753 | pm_noirq_op(dev, &dev->pwr_domain->ops, state); | ||
754 | } | ||
755 | |||
756 | return 0; | ||
753 | } | 757 | } |
754 | 758 | ||
755 | /** | 759 | /** |
@@ -836,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
836 | goto End; | 840 | goto End; |
837 | } | 841 | } |
838 | 842 | ||
843 | if (dev->type && dev->type->pm) { | ||
844 | pm_dev_dbg(dev, state, "type "); | ||
845 | error = pm_op(dev, dev->type->pm, state); | ||
846 | goto Domain; | ||
847 | } | ||
848 | |||
839 | if (dev->class) { | 849 | if (dev->class) { |
840 | if (dev->class->pm) { | 850 | if (dev->class->pm) { |
841 | pm_dev_dbg(dev, state, "class "); | 851 | pm_dev_dbg(dev, state, "class "); |
842 | error = pm_op(dev, dev->class->pm, state); | 852 | error = pm_op(dev, dev->class->pm, state); |
853 | goto Domain; | ||
843 | } else if (dev->class->suspend) { | 854 | } else if (dev->class->suspend) { |
844 | pm_dev_dbg(dev, state, "legacy class "); | 855 | pm_dev_dbg(dev, state, "legacy class "); |
845 | error = legacy_suspend(dev, state, dev->class->suspend); | 856 | error = legacy_suspend(dev, state, dev->class->suspend); |
857 | goto Domain; | ||
846 | } | 858 | } |
847 | if (error) | ||
848 | goto End; | ||
849 | } | ||
850 | |||
851 | if (dev->type) { | ||
852 | if (dev->type->pm) { | ||
853 | pm_dev_dbg(dev, state, "type "); | ||
854 | error = pm_op(dev, dev->type->pm, state); | ||
855 | } | ||
856 | if (error) | ||
857 | goto End; | ||
858 | } | 859 | } |
859 | 860 | ||
860 | if (dev->bus) { | 861 | if (dev->bus) { |
@@ -867,6 +868,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
867 | } | 868 | } |
868 | } | 869 | } |
869 | 870 | ||
871 | Domain: | ||
872 | if (!error && dev->pwr_domain) { | ||
873 | pm_dev_dbg(dev, state, "power domain "); | ||
874 | pm_op(dev, &dev->pwr_domain->ops, state); | ||
875 | } | ||
876 | |||
870 | End: | 877 | End: |
871 | device_unlock(dev); | 878 | device_unlock(dev); |
872 | complete_all(&dev->power.completion); | 879 | complete_all(&dev->power.completion); |
@@ -957,27 +964,34 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
957 | 964 | ||
958 | device_lock(dev); | 965 | device_lock(dev); |
959 | 966 | ||
960 | if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { | 967 | if (dev->type && dev->type->pm) { |
968 | pm_dev_dbg(dev, state, "preparing type "); | ||
969 | if (dev->type->pm->prepare) | ||
970 | error = dev->type->pm->prepare(dev); | ||
971 | suspend_report_result(dev->type->pm->prepare, error); | ||
972 | if (error) | ||
973 | goto End; | ||
974 | } else if (dev->class && dev->class->pm) { | ||
975 | pm_dev_dbg(dev, state, "preparing class "); | ||
976 | if (dev->class->pm->prepare) | ||
977 | error = dev->class->pm->prepare(dev); | ||
978 | suspend_report_result(dev->class->pm->prepare, error); | ||
979 | if (error) | ||
980 | goto End; | ||
981 | } else if (dev->bus && dev->bus->pm) { | ||
961 | pm_dev_dbg(dev, state, "preparing "); | 982 | pm_dev_dbg(dev, state, "preparing "); |
962 | error = dev->bus->pm->prepare(dev); | 983 | if (dev->bus->pm->prepare) |
984 | error = dev->bus->pm->prepare(dev); | ||
963 | suspend_report_result(dev->bus->pm->prepare, error); | 985 | suspend_report_result(dev->bus->pm->prepare, error); |
964 | if (error) | 986 | if (error) |
965 | goto End; | 987 | goto End; |
966 | } | 988 | } |
967 | 989 | ||
968 | if (dev->type && dev->type->pm && dev->type->pm->prepare) { | 990 | if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { |
969 | pm_dev_dbg(dev, state, "preparing type "); | 991 | pm_dev_dbg(dev, state, "preparing power domain "); |
970 | error = dev->type->pm->prepare(dev); | 992 | dev->pwr_domain->ops.prepare(dev); |
971 | suspend_report_result(dev->type->pm->prepare, error); | ||
972 | if (error) | ||
973 | goto End; | ||
974 | } | 993 | } |
975 | 994 | ||
976 | if (dev->class && dev->class->pm && dev->class->pm->prepare) { | ||
977 | pm_dev_dbg(dev, state, "preparing class "); | ||
978 | error = dev->class->pm->prepare(dev); | ||
979 | suspend_report_result(dev->class->pm->prepare, error); | ||
980 | } | ||
981 | End: | 995 | End: |
982 | device_unlock(dev); | 996 | device_unlock(dev); |
983 | 997 | ||
@@ -1005,12 +1019,9 @@ static int dpm_prepare(pm_message_t state) | |||
1005 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | 1019 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) |
1006 | pm_wakeup_event(dev, 0); | 1020 | pm_wakeup_event(dev, 0); |
1007 | 1021 | ||
1008 | if (pm_wakeup_pending()) { | 1022 | pm_runtime_put_sync(dev); |
1009 | pm_runtime_put_sync(dev); | 1023 | error = pm_wakeup_pending() ? |
1010 | error = -EBUSY; | 1024 | -EBUSY : device_prepare(dev, state); |
1011 | } else { | ||
1012 | error = device_prepare(dev, state); | ||
1013 | } | ||
1014 | 1025 | ||
1015 | mutex_lock(&dpm_list_mtx); | 1026 | mutex_lock(&dpm_list_mtx); |
1016 | if (error) { | 1027 | if (error) { |
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 2bb9b4cf59d7..56a6899f5e9e 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
@@ -222,7 +222,7 @@ int opp_get_opp_count(struct device *dev) | |||
222 | * opp_find_freq_exact() - search for an exact frequency | 222 | * opp_find_freq_exact() - search for an exact frequency |
223 | * @dev: device for which we do this operation | 223 | * @dev: device for which we do this operation |
224 | * @freq: frequency to search for | 224 | * @freq: frequency to search for |
225 | * @is_available: true/false - match for available opp | 225 | * @available: true/false - match for available opp |
226 | * | 226 | * |
227 | * Searches for exact match in the opp list and returns pointer to the matching | 227 | * Searches for exact match in the opp list and returns pointer to the matching |
228 | * opp if found, else returns ERR_PTR in case of error and should be handled | 228 | * opp if found, else returns ERR_PTR in case of error and should be handled |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 698dde742587..f2a25f18fde7 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -58,19 +58,18 @@ static inline void device_pm_move_last(struct device *dev) {} | |||
58 | * sysfs.c | 58 | * sysfs.c |
59 | */ | 59 | */ |
60 | 60 | ||
61 | extern int dpm_sysfs_add(struct device *); | 61 | extern int dpm_sysfs_add(struct device *dev); |
62 | extern void dpm_sysfs_remove(struct device *); | 62 | extern void dpm_sysfs_remove(struct device *dev); |
63 | extern void rpm_sysfs_remove(struct device *); | 63 | extern void rpm_sysfs_remove(struct device *dev); |
64 | extern int wakeup_sysfs_add(struct device *dev); | ||
65 | extern void wakeup_sysfs_remove(struct device *dev); | ||
64 | 66 | ||
65 | #else /* CONFIG_PM */ | 67 | #else /* CONFIG_PM */ |
66 | 68 | ||
67 | static inline int dpm_sysfs_add(struct device *dev) | 69 | static inline int dpm_sysfs_add(struct device *dev) { return 0; } |
68 | { | 70 | static inline void dpm_sysfs_remove(struct device *dev) {} |
69 | return 0; | 71 | static inline void rpm_sysfs_remove(struct device *dev) {} |
70 | } | 72 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } |
71 | 73 | static inline void wakeup_sysfs_remove(struct device *dev) {} | |
72 | static inline void dpm_sysfs_remove(struct device *dev) | ||
73 | { | ||
74 | } | ||
75 | 74 | ||
76 | #endif | 75 | #endif |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 42615b419dfb..54597c859ecb 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -168,6 +168,7 @@ static int rpm_check_suspend_allowed(struct device *dev) | |||
168 | static int rpm_idle(struct device *dev, int rpmflags) | 168 | static int rpm_idle(struct device *dev, int rpmflags) |
169 | { | 169 | { |
170 | int (*callback)(struct device *); | 170 | int (*callback)(struct device *); |
171 | int (*domain_callback)(struct device *); | ||
171 | int retval; | 172 | int retval; |
172 | 173 | ||
173 | retval = rpm_check_suspend_allowed(dev); | 174 | retval = rpm_check_suspend_allowed(dev); |
@@ -213,19 +214,28 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
213 | 214 | ||
214 | dev->power.idle_notification = true; | 215 | dev->power.idle_notification = true; |
215 | 216 | ||
216 | if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) | 217 | if (dev->type && dev->type->pm) |
217 | callback = dev->bus->pm->runtime_idle; | ||
218 | else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) | ||
219 | callback = dev->type->pm->runtime_idle; | 218 | callback = dev->type->pm->runtime_idle; |
220 | else if (dev->class && dev->class->pm) | 219 | else if (dev->class && dev->class->pm) |
221 | callback = dev->class->pm->runtime_idle; | 220 | callback = dev->class->pm->runtime_idle; |
221 | else if (dev->bus && dev->bus->pm) | ||
222 | callback = dev->bus->pm->runtime_idle; | ||
222 | else | 223 | else |
223 | callback = NULL; | 224 | callback = NULL; |
224 | 225 | ||
225 | if (callback) { | 226 | if (dev->pwr_domain) |
227 | domain_callback = dev->pwr_domain->ops.runtime_idle; | ||
228 | else | ||
229 | domain_callback = NULL; | ||
230 | |||
231 | if (callback || domain_callback) { | ||
226 | spin_unlock_irq(&dev->power.lock); | 232 | spin_unlock_irq(&dev->power.lock); |
227 | 233 | ||
228 | callback(dev); | 234 | if (domain_callback) |
235 | retval = domain_callback(dev); | ||
236 | |||
237 | if (!retval && callback) | ||
238 | callback(dev); | ||
229 | 239 | ||
230 | spin_lock_irq(&dev->power.lock); | 240 | spin_lock_irq(&dev->power.lock); |
231 | } | 241 | } |
@@ -372,12 +382,12 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
372 | 382 | ||
373 | __update_runtime_status(dev, RPM_SUSPENDING); | 383 | __update_runtime_status(dev, RPM_SUSPENDING); |
374 | 384 | ||
375 | if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) | 385 | if (dev->type && dev->type->pm) |
376 | callback = dev->bus->pm->runtime_suspend; | ||
377 | else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend) | ||
378 | callback = dev->type->pm->runtime_suspend; | 386 | callback = dev->type->pm->runtime_suspend; |
379 | else if (dev->class && dev->class->pm) | 387 | else if (dev->class && dev->class->pm) |
380 | callback = dev->class->pm->runtime_suspend; | 388 | callback = dev->class->pm->runtime_suspend; |
389 | else if (dev->bus && dev->bus->pm) | ||
390 | callback = dev->bus->pm->runtime_suspend; | ||
381 | else | 391 | else |
382 | callback = NULL; | 392 | callback = NULL; |
383 | 393 | ||
@@ -390,6 +400,8 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
390 | else | 400 | else |
391 | pm_runtime_cancel_pending(dev); | 401 | pm_runtime_cancel_pending(dev); |
392 | } else { | 402 | } else { |
403 | if (dev->pwr_domain) | ||
404 | rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev); | ||
393 | no_callback: | 405 | no_callback: |
394 | __update_runtime_status(dev, RPM_SUSPENDED); | 406 | __update_runtime_status(dev, RPM_SUSPENDED); |
395 | pm_runtime_deactivate_timer(dev); | 407 | pm_runtime_deactivate_timer(dev); |
@@ -569,12 +581,15 @@ static int rpm_resume(struct device *dev, int rpmflags) | |||
569 | 581 | ||
570 | __update_runtime_status(dev, RPM_RESUMING); | 582 | __update_runtime_status(dev, RPM_RESUMING); |
571 | 583 | ||
572 | if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) | 584 | if (dev->pwr_domain) |
573 | callback = dev->bus->pm->runtime_resume; | 585 | rpm_callback(dev->pwr_domain->ops.runtime_resume, dev); |
574 | else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume) | 586 | |
587 | if (dev->type && dev->type->pm) | ||
575 | callback = dev->type->pm->runtime_resume; | 588 | callback = dev->type->pm->runtime_resume; |
576 | else if (dev->class && dev->class->pm) | 589 | else if (dev->class && dev->class->pm) |
577 | callback = dev->class->pm->runtime_resume; | 590 | callback = dev->class->pm->runtime_resume; |
591 | else if (dev->bus && dev->bus->pm) | ||
592 | callback = dev->bus->pm->runtime_resume; | ||
578 | else | 593 | else |
579 | callback = NULL; | 594 | callback = NULL; |
580 | 595 | ||
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 0b1e46bf3e56..fff49bee781d 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -431,26 +431,18 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr, | |||
431 | static DEVICE_ATTR(async, 0644, async_show, async_store); | 431 | static DEVICE_ATTR(async, 0644, async_show, async_store); |
432 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ | 432 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ |
433 | 433 | ||
434 | static struct attribute * power_attrs[] = { | 434 | static struct attribute *power_attrs[] = { |
435 | &dev_attr_wakeup.attr, | ||
436 | #ifdef CONFIG_PM_SLEEP | ||
437 | &dev_attr_wakeup_count.attr, | ||
438 | &dev_attr_wakeup_active_count.attr, | ||
439 | &dev_attr_wakeup_hit_count.attr, | ||
440 | &dev_attr_wakeup_active.attr, | ||
441 | &dev_attr_wakeup_total_time_ms.attr, | ||
442 | &dev_attr_wakeup_max_time_ms.attr, | ||
443 | &dev_attr_wakeup_last_time_ms.attr, | ||
444 | #endif | ||
445 | #ifdef CONFIG_PM_ADVANCED_DEBUG | 435 | #ifdef CONFIG_PM_ADVANCED_DEBUG |
436 | #ifdef CONFIG_PM_SLEEP | ||
446 | &dev_attr_async.attr, | 437 | &dev_attr_async.attr, |
438 | #endif | ||
447 | #ifdef CONFIG_PM_RUNTIME | 439 | #ifdef CONFIG_PM_RUNTIME |
448 | &dev_attr_runtime_status.attr, | 440 | &dev_attr_runtime_status.attr, |
449 | &dev_attr_runtime_usage.attr, | 441 | &dev_attr_runtime_usage.attr, |
450 | &dev_attr_runtime_active_kids.attr, | 442 | &dev_attr_runtime_active_kids.attr, |
451 | &dev_attr_runtime_enabled.attr, | 443 | &dev_attr_runtime_enabled.attr, |
452 | #endif | 444 | #endif |
453 | #endif | 445 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ |
454 | NULL, | 446 | NULL, |
455 | }; | 447 | }; |
456 | static struct attribute_group pm_attr_group = { | 448 | static struct attribute_group pm_attr_group = { |
@@ -458,9 +450,26 @@ static struct attribute_group pm_attr_group = { | |||
458 | .attrs = power_attrs, | 450 | .attrs = power_attrs, |
459 | }; | 451 | }; |
460 | 452 | ||
461 | #ifdef CONFIG_PM_RUNTIME | 453 | static struct attribute *wakeup_attrs[] = { |
454 | #ifdef CONFIG_PM_SLEEP | ||
455 | &dev_attr_wakeup.attr, | ||
456 | &dev_attr_wakeup_count.attr, | ||
457 | &dev_attr_wakeup_active_count.attr, | ||
458 | &dev_attr_wakeup_hit_count.attr, | ||
459 | &dev_attr_wakeup_active.attr, | ||
460 | &dev_attr_wakeup_total_time_ms.attr, | ||
461 | &dev_attr_wakeup_max_time_ms.attr, | ||
462 | &dev_attr_wakeup_last_time_ms.attr, | ||
463 | #endif | ||
464 | NULL, | ||
465 | }; | ||
466 | static struct attribute_group pm_wakeup_attr_group = { | ||
467 | .name = power_group_name, | ||
468 | .attrs = wakeup_attrs, | ||
469 | }; | ||
462 | 470 | ||
463 | static struct attribute *runtime_attrs[] = { | 471 | static struct attribute *runtime_attrs[] = { |
472 | #ifdef CONFIG_PM_RUNTIME | ||
464 | #ifndef CONFIG_PM_ADVANCED_DEBUG | 473 | #ifndef CONFIG_PM_ADVANCED_DEBUG |
465 | &dev_attr_runtime_status.attr, | 474 | &dev_attr_runtime_status.attr, |
466 | #endif | 475 | #endif |
@@ -468,6 +477,7 @@ static struct attribute *runtime_attrs[] = { | |||
468 | &dev_attr_runtime_suspended_time.attr, | 477 | &dev_attr_runtime_suspended_time.attr, |
469 | &dev_attr_runtime_active_time.attr, | 478 | &dev_attr_runtime_active_time.attr, |
470 | &dev_attr_autosuspend_delay_ms.attr, | 479 | &dev_attr_autosuspend_delay_ms.attr, |
480 | #endif /* CONFIG_PM_RUNTIME */ | ||
471 | NULL, | 481 | NULL, |
472 | }; | 482 | }; |
473 | static struct attribute_group pm_runtime_attr_group = { | 483 | static struct attribute_group pm_runtime_attr_group = { |
@@ -480,35 +490,49 @@ int dpm_sysfs_add(struct device *dev) | |||
480 | int rc; | 490 | int rc; |
481 | 491 | ||
482 | rc = sysfs_create_group(&dev->kobj, &pm_attr_group); | 492 | rc = sysfs_create_group(&dev->kobj, &pm_attr_group); |
483 | if (rc == 0 && !dev->power.no_callbacks) { | 493 | if (rc) |
494 | return rc; | ||
495 | |||
496 | if (pm_runtime_callbacks_present(dev)) { | ||
484 | rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); | 497 | rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); |
485 | if (rc) | 498 | if (rc) |
486 | sysfs_remove_group(&dev->kobj, &pm_attr_group); | 499 | goto err_out; |
500 | } | ||
501 | |||
502 | if (device_can_wakeup(dev)) { | ||
503 | rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group); | ||
504 | if (rc) { | ||
505 | if (pm_runtime_callbacks_present(dev)) | ||
506 | sysfs_unmerge_group(&dev->kobj, | ||
507 | &pm_runtime_attr_group); | ||
508 | goto err_out; | ||
509 | } | ||
487 | } | 510 | } |
511 | return 0; | ||
512 | |||
513 | err_out: | ||
514 | sysfs_remove_group(&dev->kobj, &pm_attr_group); | ||
488 | return rc; | 515 | return rc; |
489 | } | 516 | } |
490 | 517 | ||
491 | void rpm_sysfs_remove(struct device *dev) | 518 | int wakeup_sysfs_add(struct device *dev) |
492 | { | 519 | { |
493 | sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); | 520 | return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group); |
494 | } | 521 | } |
495 | 522 | ||
496 | void dpm_sysfs_remove(struct device *dev) | 523 | void wakeup_sysfs_remove(struct device *dev) |
497 | { | 524 | { |
498 | rpm_sysfs_remove(dev); | 525 | sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); |
499 | sysfs_remove_group(&dev->kobj, &pm_attr_group); | ||
500 | } | 526 | } |
501 | 527 | ||
502 | #else /* CONFIG_PM_RUNTIME */ | 528 | void rpm_sysfs_remove(struct device *dev) |
503 | |||
504 | int dpm_sysfs_add(struct device * dev) | ||
505 | { | 529 | { |
506 | return sysfs_create_group(&dev->kobj, &pm_attr_group); | 530 | sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); |
507 | } | 531 | } |
508 | 532 | ||
509 | void dpm_sysfs_remove(struct device * dev) | 533 | void dpm_sysfs_remove(struct device *dev) |
510 | { | 534 | { |
535 | rpm_sysfs_remove(dev); | ||
536 | sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); | ||
511 | sysfs_remove_group(&dev->kobj, &pm_attr_group); | 537 | sysfs_remove_group(&dev->kobj, &pm_attr_group); |
512 | } | 538 | } |
513 | |||
514 | #endif | ||
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 9f4258df4cfd..c80e138b62fe 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c | |||
@@ -112,7 +112,7 @@ static unsigned int read_magic_time(void) | |||
112 | unsigned int val; | 112 | unsigned int val; |
113 | 113 | ||
114 | get_rtc_time(&time); | 114 | get_rtc_time(&time); |
115 | printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", | 115 | pr_info("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", |
116 | time.tm_hour, time.tm_min, time.tm_sec, | 116 | time.tm_hour, time.tm_min, time.tm_sec, |
117 | time.tm_mon + 1, time.tm_mday, time.tm_year % 100); | 117 | time.tm_mon + 1, time.tm_mday, time.tm_year % 100); |
118 | val = time.tm_year; /* 100 years */ | 118 | val = time.tm_year; /* 100 years */ |
@@ -179,7 +179,7 @@ static int show_file_hash(unsigned int value) | |||
179 | unsigned int hash = hash_string(lineno, file, FILEHASH); | 179 | unsigned int hash = hash_string(lineno, file, FILEHASH); |
180 | if (hash != value) | 180 | if (hash != value) |
181 | continue; | 181 | continue; |
182 | printk(" hash matches %s:%u\n", file, lineno); | 182 | pr_info(" hash matches %s:%u\n", file, lineno); |
183 | match++; | 183 | match++; |
184 | } | 184 | } |
185 | return match; | 185 | return match; |
@@ -255,7 +255,7 @@ static int late_resume_init(void) | |||
255 | val = val / FILEHASH; | 255 | val = val / FILEHASH; |
256 | dev = val /* % DEVHASH */; | 256 | dev = val /* % DEVHASH */; |
257 | 257 | ||
258 | printk(" Magic number: %d:%d:%d\n", user, file, dev); | 258 | pr_info(" Magic number: %d:%d:%d\n", user, file, dev); |
259 | show_file_hash(file); | 259 | show_file_hash(file); |
260 | show_dev_hash(dev); | 260 | show_dev_hash(dev); |
261 | return 0; | 261 | return 0; |
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 8ec406d8f548..4573c83df6dd 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c | |||
@@ -24,12 +24,26 @@ | |||
24 | */ | 24 | */ |
25 | bool events_check_enabled; | 25 | bool events_check_enabled; |
26 | 26 | ||
27 | /* The counter of registered wakeup events. */ | 27 | /* |
28 | static atomic_t event_count = ATOMIC_INIT(0); | 28 | * Combined counters of registered wakeup events and wakeup events in progress. |
29 | /* A preserved old value of event_count. */ | 29 | * They need to be modified together atomically, so it's better to use one |
30 | * atomic variable to hold them both. | ||
31 | */ | ||
32 | static atomic_t combined_event_count = ATOMIC_INIT(0); | ||
33 | |||
34 | #define IN_PROGRESS_BITS (sizeof(int) * 4) | ||
35 | #define MAX_IN_PROGRESS ((1 << IN_PROGRESS_BITS) - 1) | ||
36 | |||
37 | static void split_counters(unsigned int *cnt, unsigned int *inpr) | ||
38 | { | ||
39 | unsigned int comb = atomic_read(&combined_event_count); | ||
40 | |||
41 | *cnt = (comb >> IN_PROGRESS_BITS); | ||
42 | *inpr = comb & MAX_IN_PROGRESS; | ||
43 | } | ||
44 | |||
45 | /* A preserved old value of the events counter. */ | ||
30 | static unsigned int saved_count; | 46 | static unsigned int saved_count; |
31 | /* The counter of wakeup events being processed. */ | ||
32 | static atomic_t events_in_progress = ATOMIC_INIT(0); | ||
33 | 47 | ||
34 | static DEFINE_SPINLOCK(events_lock); | 48 | static DEFINE_SPINLOCK(events_lock); |
35 | 49 | ||
@@ -228,6 +242,35 @@ int device_wakeup_disable(struct device *dev) | |||
228 | EXPORT_SYMBOL_GPL(device_wakeup_disable); | 242 | EXPORT_SYMBOL_GPL(device_wakeup_disable); |
229 | 243 | ||
230 | /** | 244 | /** |
245 | * device_set_wakeup_capable - Set/reset device wakeup capability flag. | ||
246 | * @dev: Device to handle. | ||
247 | * @capable: Whether or not @dev is capable of waking up the system from sleep. | ||
248 | * | ||
249 | * If @capable is set, set the @dev's power.can_wakeup flag and add its | ||
250 | * wakeup-related attributes to sysfs. Otherwise, unset the @dev's | ||
251 | * power.can_wakeup flag and remove its wakeup-related attributes from sysfs. | ||
252 | * | ||
253 | * This function may sleep and it can't be called from any context where | ||
254 | * sleeping is not allowed. | ||
255 | */ | ||
256 | void device_set_wakeup_capable(struct device *dev, bool capable) | ||
257 | { | ||
258 | if (!!dev->power.can_wakeup == !!capable) | ||
259 | return; | ||
260 | |||
261 | if (device_is_registered(dev)) { | ||
262 | if (capable) { | ||
263 | if (wakeup_sysfs_add(dev)) | ||
264 | return; | ||
265 | } else { | ||
266 | wakeup_sysfs_remove(dev); | ||
267 | } | ||
268 | } | ||
269 | dev->power.can_wakeup = capable; | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(device_set_wakeup_capable); | ||
272 | |||
273 | /** | ||
231 | * device_init_wakeup - Device wakeup initialization. | 274 | * device_init_wakeup - Device wakeup initialization. |
232 | * @dev: Device to handle. | 275 | * @dev: Device to handle. |
233 | * @enable: Whether or not to enable @dev as a wakeup device. | 276 | * @enable: Whether or not to enable @dev as a wakeup device. |
@@ -307,7 +350,8 @@ static void wakeup_source_activate(struct wakeup_source *ws) | |||
307 | ws->timer_expires = jiffies; | 350 | ws->timer_expires = jiffies; |
308 | ws->last_time = ktime_get(); | 351 | ws->last_time = ktime_get(); |
309 | 352 | ||
310 | atomic_inc(&events_in_progress); | 353 | /* Increment the counter of events in progress. */ |
354 | atomic_inc(&combined_event_count); | ||
311 | } | 355 | } |
312 | 356 | ||
313 | /** | 357 | /** |
@@ -394,14 +438,10 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) | |||
394 | del_timer(&ws->timer); | 438 | del_timer(&ws->timer); |
395 | 439 | ||
396 | /* | 440 | /* |
397 | * event_count has to be incremented before events_in_progress is | 441 | * Increment the counter of registered wakeup events and decrement the |
398 | * modified, so that the callers of pm_check_wakeup_events() and | 442 | * couter of wakeup events in progress simultaneously. |
399 | * pm_save_wakeup_count() don't see the old value of event_count and | ||
400 | * events_in_progress equal to zero at the same time. | ||
401 | */ | 443 | */ |
402 | atomic_inc(&event_count); | 444 | atomic_add(MAX_IN_PROGRESS, &combined_event_count); |
403 | smp_mb__before_atomic_dec(); | ||
404 | atomic_dec(&events_in_progress); | ||
405 | } | 445 | } |
406 | 446 | ||
407 | /** | 447 | /** |
@@ -556,8 +596,10 @@ bool pm_wakeup_pending(void) | |||
556 | 596 | ||
557 | spin_lock_irqsave(&events_lock, flags); | 597 | spin_lock_irqsave(&events_lock, flags); |
558 | if (events_check_enabled) { | 598 | if (events_check_enabled) { |
559 | ret = ((unsigned int)atomic_read(&event_count) != saved_count) | 599 | unsigned int cnt, inpr; |
560 | || atomic_read(&events_in_progress); | 600 | |
601 | split_counters(&cnt, &inpr); | ||
602 | ret = (cnt != saved_count || inpr > 0); | ||
561 | events_check_enabled = !ret; | 603 | events_check_enabled = !ret; |
562 | } | 604 | } |
563 | spin_unlock_irqrestore(&events_lock, flags); | 605 | spin_unlock_irqrestore(&events_lock, flags); |
@@ -573,25 +615,25 @@ bool pm_wakeup_pending(void) | |||
573 | * Store the number of registered wakeup events at the address in @count. Block | 615 | * Store the number of registered wakeup events at the address in @count. Block |
574 | * if the current number of wakeup events being processed is nonzero. | 616 | * if the current number of wakeup events being processed is nonzero. |
575 | * | 617 | * |
576 | * Return false if the wait for the number of wakeup events being processed to | 618 | * Return 'false' if the wait for the number of wakeup events being processed to |
577 | * drop down to zero has been interrupted by a signal (and the current number | 619 | * drop down to zero has been interrupted by a signal (and the current number |
578 | * of wakeup events being processed is still nonzero). Otherwise return true. | 620 | * of wakeup events being processed is still nonzero). Otherwise return 'true'. |
579 | */ | 621 | */ |
580 | bool pm_get_wakeup_count(unsigned int *count) | 622 | bool pm_get_wakeup_count(unsigned int *count) |
581 | { | 623 | { |
582 | bool ret; | 624 | unsigned int cnt, inpr; |
583 | |||
584 | if (capable(CAP_SYS_ADMIN)) | ||
585 | events_check_enabled = false; | ||
586 | 625 | ||
587 | while (atomic_read(&events_in_progress) && !signal_pending(current)) { | 626 | for (;;) { |
627 | split_counters(&cnt, &inpr); | ||
628 | if (inpr == 0 || signal_pending(current)) | ||
629 | break; | ||
588 | pm_wakeup_update_hit_counts(); | 630 | pm_wakeup_update_hit_counts(); |
589 | schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); | 631 | schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); |
590 | } | 632 | } |
591 | 633 | ||
592 | ret = !atomic_read(&events_in_progress); | 634 | split_counters(&cnt, &inpr); |
593 | *count = atomic_read(&event_count); | 635 | *count = cnt; |
594 | return ret; | 636 | return !inpr; |
595 | } | 637 | } |
596 | 638 | ||
597 | /** | 639 | /** |
@@ -600,24 +642,25 @@ bool pm_get_wakeup_count(unsigned int *count) | |||
600 | * | 642 | * |
601 | * If @count is equal to the current number of registered wakeup events and the | 643 | * If @count is equal to the current number of registered wakeup events and the |
602 | * current number of wakeup events being processed is zero, store @count as the | 644 | * current number of wakeup events being processed is zero, store @count as the |
603 | * old number of registered wakeup events to be used by pm_check_wakeup_events() | 645 | * old number of registered wakeup events for pm_check_wakeup_events(), enable |
604 | * and return true. Otherwise return false. | 646 | * wakeup events detection and return 'true'. Otherwise disable wakeup events |
647 | * detection and return 'false'. | ||
605 | */ | 648 | */ |
606 | bool pm_save_wakeup_count(unsigned int count) | 649 | bool pm_save_wakeup_count(unsigned int count) |
607 | { | 650 | { |
608 | bool ret = false; | 651 | unsigned int cnt, inpr; |
609 | 652 | ||
653 | events_check_enabled = false; | ||
610 | spin_lock_irq(&events_lock); | 654 | spin_lock_irq(&events_lock); |
611 | if (count == (unsigned int)atomic_read(&event_count) | 655 | split_counters(&cnt, &inpr); |
612 | && !atomic_read(&events_in_progress)) { | 656 | if (cnt == count && inpr == 0) { |
613 | saved_count = count; | 657 | saved_count = count; |
614 | events_check_enabled = true; | 658 | events_check_enabled = true; |
615 | ret = true; | ||
616 | } | 659 | } |
617 | spin_unlock_irq(&events_lock); | 660 | spin_unlock_irq(&events_lock); |
618 | if (!ret) | 661 | if (!events_check_enabled) |
619 | pm_wakeup_update_hit_counts(); | 662 | pm_wakeup_update_hit_counts(); |
620 | return ret; | 663 | return events_check_enabled; |
621 | } | 664 | } |
622 | 665 | ||
623 | static struct dentry *wakeup_sources_stats_dentry; | 666 | static struct dentry *wakeup_sources_stats_dentry; |
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c new file mode 100644 index 000000000000..90af2943f9e4 --- /dev/null +++ b/drivers/base/syscore.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * syscore.c - Execution of system core operations. | ||
3 | * | ||
4 | * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
5 | * | ||
6 | * This file is released under the GPLv2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/syscore_ops.h> | ||
10 | #include <linux/mutex.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | static LIST_HEAD(syscore_ops_list); | ||
14 | static DEFINE_MUTEX(syscore_ops_lock); | ||
15 | |||
16 | /** | ||
17 | * register_syscore_ops - Register a set of system core operations. | ||
18 | * @ops: System core operations to register. | ||
19 | */ | ||
20 | void register_syscore_ops(struct syscore_ops *ops) | ||
21 | { | ||
22 | mutex_lock(&syscore_ops_lock); | ||
23 | list_add_tail(&ops->node, &syscore_ops_list); | ||
24 | mutex_unlock(&syscore_ops_lock); | ||
25 | } | ||
26 | EXPORT_SYMBOL_GPL(register_syscore_ops); | ||
27 | |||
28 | /** | ||
29 | * unregister_syscore_ops - Unregister a set of system core operations. | ||
30 | * @ops: System core operations to unregister. | ||
31 | */ | ||
32 | void unregister_syscore_ops(struct syscore_ops *ops) | ||
33 | { | ||
34 | mutex_lock(&syscore_ops_lock); | ||
35 | list_del(&ops->node); | ||
36 | mutex_unlock(&syscore_ops_lock); | ||
37 | } | ||
38 | EXPORT_SYMBOL_GPL(unregister_syscore_ops); | ||
39 | |||
40 | #ifdef CONFIG_PM_SLEEP | ||
41 | /** | ||
42 | * syscore_suspend - Execute all the registered system core suspend callbacks. | ||
43 | * | ||
44 | * This function is executed with one CPU on-line and disabled interrupts. | ||
45 | */ | ||
46 | int syscore_suspend(void) | ||
47 | { | ||
48 | struct syscore_ops *ops; | ||
49 | int ret = 0; | ||
50 | |||
51 | WARN_ONCE(!irqs_disabled(), | ||
52 | "Interrupts enabled before system core suspend.\n"); | ||
53 | |||
54 | list_for_each_entry_reverse(ops, &syscore_ops_list, node) | ||
55 | if (ops->suspend) { | ||
56 | if (initcall_debug) | ||
57 | pr_info("PM: Calling %pF\n", ops->suspend); | ||
58 | ret = ops->suspend(); | ||
59 | if (ret) | ||
60 | goto err_out; | ||
61 | WARN_ONCE(!irqs_disabled(), | ||
62 | "Interrupts enabled after %pF\n", ops->suspend); | ||
63 | } | ||
64 | |||
65 | return 0; | ||
66 | |||
67 | err_out: | ||
68 | pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend); | ||
69 | |||
70 | list_for_each_entry_continue(ops, &syscore_ops_list, node) | ||
71 | if (ops->resume) | ||
72 | ops->resume(); | ||
73 | |||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * syscore_resume - Execute all the registered system core resume callbacks. | ||
79 | * | ||
80 | * This function is executed with one CPU on-line and disabled interrupts. | ||
81 | */ | ||
82 | void syscore_resume(void) | ||
83 | { | ||
84 | struct syscore_ops *ops; | ||
85 | |||
86 | WARN_ONCE(!irqs_disabled(), | ||
87 | "Interrupts enabled before system core resume.\n"); | ||
88 | |||
89 | list_for_each_entry(ops, &syscore_ops_list, node) | ||
90 | if (ops->resume) { | ||
91 | if (initcall_debug) | ||
92 | pr_info("PM: Calling %pF\n", ops->resume); | ||
93 | ops->resume(); | ||
94 | WARN_ONCE(!irqs_disabled(), | ||
95 | "Interrupts enabled after %pF\n", ops->resume); | ||
96 | } | ||
97 | } | ||
98 | #endif /* CONFIG_PM_SLEEP */ | ||
99 | |||
100 | /** | ||
101 | * syscore_shutdown - Execute all the registered system core shutdown callbacks. | ||
102 | */ | ||
103 | void syscore_shutdown(void) | ||
104 | { | ||
105 | struct syscore_ops *ops; | ||
106 | |||
107 | mutex_lock(&syscore_ops_lock); | ||
108 | |||
109 | list_for_each_entry_reverse(ops, &syscore_ops_list, node) | ||
110 | if (ops->shutdown) { | ||
111 | if (initcall_debug) | ||
112 | pr_info("PM: Calling %pF\n", ops->shutdown); | ||
113 | ops->shutdown(); | ||
114 | } | ||
115 | |||
116 | mutex_unlock(&syscore_ops_lock); | ||
117 | } | ||
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2e5022849f18..6d513a383340 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -5338,7 +5338,7 @@ void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) | |||
5338 | __e1000e_disable_aspm(pdev, state); | 5338 | __e1000e_disable_aspm(pdev, state); |
5339 | } | 5339 | } |
5340 | 5340 | ||
5341 | #ifdef CONFIG_PM_OPS | 5341 | #ifdef CONFIG_PM |
5342 | static bool e1000e_pm_ready(struct e1000_adapter *adapter) | 5342 | static bool e1000e_pm_ready(struct e1000_adapter *adapter) |
5343 | { | 5343 | { |
5344 | return !!adapter->tx_ring->buffer_info; | 5344 | return !!adapter->tx_ring->buffer_info; |
@@ -5489,7 +5489,7 @@ static int e1000_runtime_resume(struct device *dev) | |||
5489 | return __e1000_resume(pdev); | 5489 | return __e1000_resume(pdev); |
5490 | } | 5490 | } |
5491 | #endif /* CONFIG_PM_RUNTIME */ | 5491 | #endif /* CONFIG_PM_RUNTIME */ |
5492 | #endif /* CONFIG_PM_OPS */ | 5492 | #endif /* CONFIG_PM */ |
5493 | 5493 | ||
5494 | static void e1000_shutdown(struct pci_dev *pdev) | 5494 | static void e1000_shutdown(struct pci_dev *pdev) |
5495 | { | 5495 | { |
@@ -6196,7 +6196,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { | |||
6196 | }; | 6196 | }; |
6197 | MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); | 6197 | MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); |
6198 | 6198 | ||
6199 | #ifdef CONFIG_PM_OPS | 6199 | #ifdef CONFIG_PM |
6200 | static const struct dev_pm_ops e1000_pm_ops = { | 6200 | static const struct dev_pm_ops e1000_pm_ops = { |
6201 | SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume) | 6201 | SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume) |
6202 | SET_RUNTIME_PM_OPS(e1000_runtime_suspend, | 6202 | SET_RUNTIME_PM_OPS(e1000_runtime_suspend, |
@@ -6210,7 +6210,7 @@ static struct pci_driver e1000_driver = { | |||
6210 | .id_table = e1000_pci_tbl, | 6210 | .id_table = e1000_pci_tbl, |
6211 | .probe = e1000_probe, | 6211 | .probe = e1000_probe, |
6212 | .remove = __devexit_p(e1000_remove), | 6212 | .remove = __devexit_p(e1000_remove), |
6213 | #ifdef CONFIG_PM_OPS | 6213 | #ifdef CONFIG_PM |
6214 | .driver.pm = &e1000_pm_ops, | 6214 | .driver.pm = &e1000_pm_ops, |
6215 | #endif | 6215 | #endif |
6216 | .shutdown = e1000_shutdown, | 6216 | .shutdown = e1000_shutdown, |
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index b99e90aca37d..8c66e22c3a0a 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c | |||
@@ -2446,7 +2446,7 @@ static struct pci_driver pch_gbe_pcidev = { | |||
2446 | .id_table = pch_gbe_pcidev_id, | 2446 | .id_table = pch_gbe_pcidev_id, |
2447 | .probe = pch_gbe_probe, | 2447 | .probe = pch_gbe_probe, |
2448 | .remove = pch_gbe_remove, | 2448 | .remove = pch_gbe_remove, |
2449 | #ifdef CONFIG_PM_OPS | 2449 | #ifdef CONFIG_PM |
2450 | .driver.pm = &pch_gbe_pm_ops, | 2450 | .driver.pm = &pch_gbe_pm_ops, |
2451 | #endif | 2451 | #endif |
2452 | .shutdown = pch_gbe_shutdown, | 2452 | .shutdown = pch_gbe_shutdown, |
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 88246dd46452..d86ea8b01137 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -431,7 +431,7 @@ static void pci_device_shutdown(struct device *dev) | |||
431 | pci_msix_shutdown(pci_dev); | 431 | pci_msix_shutdown(pci_dev); |
432 | } | 432 | } |
433 | 433 | ||
434 | #ifdef CONFIG_PM_OPS | 434 | #ifdef CONFIG_PM |
435 | 435 | ||
436 | /* Auxiliary functions used for system resume and run-time resume. */ | 436 | /* Auxiliary functions used for system resume and run-time resume. */ |
437 | 437 | ||
@@ -1059,7 +1059,7 @@ static int pci_pm_runtime_idle(struct device *dev) | |||
1059 | 1059 | ||
1060 | #endif /* !CONFIG_PM_RUNTIME */ | 1060 | #endif /* !CONFIG_PM_RUNTIME */ |
1061 | 1061 | ||
1062 | #ifdef CONFIG_PM_OPS | 1062 | #ifdef CONFIG_PM |
1063 | 1063 | ||
1064 | const struct dev_pm_ops pci_dev_pm_ops = { | 1064 | const struct dev_pm_ops pci_dev_pm_ops = { |
1065 | .prepare = pci_pm_prepare, | 1065 | .prepare = pci_pm_prepare, |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2e9a87e8e7d8..ef6de669424b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -165,7 +165,7 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o | |||
165 | scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o | 165 | scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o |
166 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o | 166 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o |
167 | scsi_mod-y += scsi_trace.o | 167 | scsi_mod-y += scsi_trace.o |
168 | scsi_mod-$(CONFIG_PM_OPS) += scsi_pm.o | 168 | scsi_mod-$(CONFIG_PM) += scsi_pm.o |
169 | 169 | ||
170 | scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o | 170 | scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o |
171 | 171 | ||
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index b4056d14f812..342ee1a9c41d 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -146,7 +146,7 @@ static inline void scsi_netlink_exit(void) {} | |||
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | /* scsi_pm.c */ | 148 | /* scsi_pm.c */ |
149 | #ifdef CONFIG_PM_OPS | 149 | #ifdef CONFIG_PM |
150 | extern const struct dev_pm_ops scsi_bus_pm_ops; | 150 | extern const struct dev_pm_ops scsi_bus_pm_ops; |
151 | #endif | 151 | #endif |
152 | #ifdef CONFIG_PM_RUNTIME | 152 | #ifdef CONFIG_PM_RUNTIME |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 490ce213204e..e44ff64233fd 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -383,7 +383,7 @@ struct bus_type scsi_bus_type = { | |||
383 | .name = "scsi", | 383 | .name = "scsi", |
384 | .match = scsi_bus_match, | 384 | .match = scsi_bus_match, |
385 | .uevent = scsi_bus_uevent, | 385 | .uevent = scsi_bus_uevent, |
386 | #ifdef CONFIG_PM_OPS | 386 | #ifdef CONFIG_PM |
387 | .pm = &scsi_bus_pm_ops, | 387 | .pm = &scsi_bus_pm_ops, |
388 | #endif | 388 | #endif |
389 | }; | 389 | }; |
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index f71e8e307e0f..64a035ba2eab 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -335,7 +335,7 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) | |||
335 | } | 335 | } |
336 | EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); | 336 | EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); |
337 | 337 | ||
338 | #ifdef CONFIG_PM_OPS | 338 | #ifdef CONFIG_PM |
339 | 339 | ||
340 | #ifdef CONFIG_PPC_PMAC | 340 | #ifdef CONFIG_PPC_PMAC |
341 | static void powermac_set_asic(struct pci_dev *pci_dev, int enable) | 341 | static void powermac_set_asic(struct pci_dev *pci_dev, int enable) |
@@ -580,4 +580,4 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = { | |||
580 | }; | 580 | }; |
581 | EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); | 581 | EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); |
582 | 582 | ||
583 | #endif /* CONFIG_PM_OPS */ | 583 | #endif /* CONFIG_PM */ |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0f299b7aad60..19d3435e6140 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1465,6 +1465,7 @@ void usb_set_device_state(struct usb_device *udev, | |||
1465 | enum usb_device_state new_state) | 1465 | enum usb_device_state new_state) |
1466 | { | 1466 | { |
1467 | unsigned long flags; | 1467 | unsigned long flags; |
1468 | int wakeup = -1; | ||
1468 | 1469 | ||
1469 | spin_lock_irqsave(&device_state_lock, flags); | 1470 | spin_lock_irqsave(&device_state_lock, flags); |
1470 | if (udev->state == USB_STATE_NOTATTACHED) | 1471 | if (udev->state == USB_STATE_NOTATTACHED) |
@@ -1479,11 +1480,10 @@ void usb_set_device_state(struct usb_device *udev, | |||
1479 | || new_state == USB_STATE_SUSPENDED) | 1480 | || new_state == USB_STATE_SUSPENDED) |
1480 | ; /* No change to wakeup settings */ | 1481 | ; /* No change to wakeup settings */ |
1481 | else if (new_state == USB_STATE_CONFIGURED) | 1482 | else if (new_state == USB_STATE_CONFIGURED) |
1482 | device_set_wakeup_capable(&udev->dev, | 1483 | wakeup = udev->actconfig->desc.bmAttributes |
1483 | (udev->actconfig->desc.bmAttributes | 1484 | & USB_CONFIG_ATT_WAKEUP; |
1484 | & USB_CONFIG_ATT_WAKEUP)); | ||
1485 | else | 1485 | else |
1486 | device_set_wakeup_capable(&udev->dev, 0); | 1486 | wakeup = 0; |
1487 | } | 1487 | } |
1488 | if (udev->state == USB_STATE_SUSPENDED && | 1488 | if (udev->state == USB_STATE_SUSPENDED && |
1489 | new_state != USB_STATE_SUSPENDED) | 1489 | new_state != USB_STATE_SUSPENDED) |
@@ -1495,6 +1495,8 @@ void usb_set_device_state(struct usb_device *udev, | |||
1495 | } else | 1495 | } else |
1496 | recursively_mark_NOTATTACHED(udev); | 1496 | recursively_mark_NOTATTACHED(udev); |
1497 | spin_unlock_irqrestore(&device_state_lock, flags); | 1497 | spin_unlock_irqrestore(&device_state_lock, flags); |
1498 | if (wakeup >= 0) | ||
1499 | device_set_wakeup_capable(&udev->dev, wakeup); | ||
1498 | } | 1500 | } |
1499 | EXPORT_SYMBOL_GPL(usb_set_device_state); | 1501 | EXPORT_SYMBOL_GPL(usb_set_device_state); |
1500 | 1502 | ||