diff options
-rw-r--r-- | Documentation/power/pci.txt | 14 | ||||
-rw-r--r-- | drivers/base/power/main.c | 6 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 103 | ||||
-rw-r--r-- | include/linux/pm.h | 2 |
4 files changed, 108 insertions, 17 deletions
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt index ab4e7d0540c1..304162ea377e 100644 --- a/Documentation/power/pci.txt +++ b/Documentation/power/pci.txt | |||
@@ -980,6 +980,20 @@ positive value from pci_pm_prepare() if the ->prepare callback provided by the | |||
980 | driver of the device returns a positive value. That allows the driver to opt | 980 | driver of the device returns a positive value. That allows the driver to opt |
981 | out from using the direct-complete mechanism dynamically. | 981 | out from using the direct-complete mechanism dynamically. |
982 | 982 | ||
983 | The DPM_FLAG_SMART_SUSPEND flag tells the PCI bus type that from the driver's | ||
984 | perspective the device can be safely left in runtime suspend during system | ||
985 | suspend. That causes pci_pm_suspend(), pci_pm_freeze() and pci_pm_poweroff() | ||
986 | to skip resuming the device from runtime suspend unless there are PCI-specific | ||
987 | reasons for doing that. Also, it causes pci_pm_suspend_late/noirq(), | ||
988 | pci_pm_freeze_late/noirq() and pci_pm_poweroff_late/noirq() to return early | ||
989 | if the device remains in runtime suspend in the beginning of the "late" phase | ||
990 | of the system-wide transition under way. Moreover, if the device is in | ||
991 | runtime suspend in pci_pm_resume_noirq() or pci_pm_restore_noirq(), its runtime | ||
992 | power management status will be changed to "active" (as it is going to be put | ||
993 | into D0 going forward), but if it is in runtime suspend in pci_pm_thaw_noirq(), | ||
994 | the function will set the power.direct_complete flag for it (to make the PM core | ||
995 | skip the subsequent "thaw" callbacks for it) and return. | ||
996 | |||
983 | 3.2. Device Runtime Power Management | 997 | 3.2. Device Runtime Power Management |
984 | ------------------------------------ | 998 | ------------------------------------ |
985 | In addition to providing device power management callbacks PCI device drivers | 999 | In addition to providing device power management callbacks PCI device drivers |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 8d9024017645..6c6f1c74c24c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -1861,3 +1861,9 @@ void device_pm_check_callbacks(struct device *dev) | |||
1861 | !dev->driver->suspend && !dev->driver->resume)); | 1861 | !dev->driver->suspend && !dev->driver->resume)); |
1862 | spin_unlock_irq(&dev->power.lock); | 1862 | spin_unlock_irq(&dev->power.lock); |
1863 | } | 1863 | } |
1864 | |||
1865 | bool dev_pm_smart_suspend_and_suspended(struct device *dev) | ||
1866 | { | ||
1867 | return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && | ||
1868 | pm_runtime_status_suspended(dev); | ||
1869 | } | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c1aeeb10539e..d19bd54d337e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -734,18 +734,25 @@ static int pci_pm_suspend(struct device *dev) | |||
734 | 734 | ||
735 | if (!pm) { | 735 | if (!pm) { |
736 | pci_pm_default_suspend(pci_dev); | 736 | pci_pm_default_suspend(pci_dev); |
737 | goto Fixup; | 737 | return 0; |
738 | } | 738 | } |
739 | 739 | ||
740 | /* | 740 | /* |
741 | * PCI devices suspended at run time need to be resumed at this point, | 741 | * PCI devices suspended at run time may need to be resumed at this |
742 | * because in general it is necessary to reconfigure them for system | 742 | * point, because in general it may be necessary to reconfigure them for |
743 | * suspend. Namely, if the device is supposed to wake up the system | 743 | * system suspend. Namely, if the device is expected to wake up the |
744 | * from the sleep state, we may need to reconfigure it for this purpose. | 744 | * system from the sleep state, it may have to be reconfigured for this |
745 | * In turn, if the device is not supposed to wake up the system from the | 745 | * purpose, or if the device is not expected to wake up the system from |
746 | * sleep state, we'll have to prevent it from signaling wake-up. | 746 | * the sleep state, it should be prevented from signaling wakeup events |
747 | * going forward. | ||
748 | * | ||
749 | * Also if the driver of the device does not indicate that its system | ||
750 | * suspend callbacks can cope with runtime-suspended devices, it is | ||
751 | * better to resume the device from runtime suspend here. | ||
747 | */ | 752 | */ |
748 | pm_runtime_resume(dev); | 753 | if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || |
754 | !pci_dev_keep_suspended(pci_dev)) | ||
755 | pm_runtime_resume(dev); | ||
749 | 756 | ||
750 | pci_dev->state_saved = false; | 757 | pci_dev->state_saved = false; |
751 | if (pm->suspend) { | 758 | if (pm->suspend) { |
@@ -765,17 +772,27 @@ static int pci_pm_suspend(struct device *dev) | |||
765 | } | 772 | } |
766 | } | 773 | } |
767 | 774 | ||
768 | Fixup: | ||
769 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
770 | |||
771 | return 0; | 775 | return 0; |
772 | } | 776 | } |
773 | 777 | ||
778 | static int pci_pm_suspend_late(struct device *dev) | ||
779 | { | ||
780 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
781 | return 0; | ||
782 | |||
783 | pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev)); | ||
784 | |||
785 | return pm_generic_suspend_late(dev); | ||
786 | } | ||
787 | |||
774 | static int pci_pm_suspend_noirq(struct device *dev) | 788 | static int pci_pm_suspend_noirq(struct device *dev) |
775 | { | 789 | { |
776 | struct pci_dev *pci_dev = to_pci_dev(dev); | 790 | struct pci_dev *pci_dev = to_pci_dev(dev); |
777 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 791 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
778 | 792 | ||
793 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
794 | return 0; | ||
795 | |||
779 | if (pci_has_legacy_pm_support(pci_dev)) | 796 | if (pci_has_legacy_pm_support(pci_dev)) |
780 | return pci_legacy_suspend_late(dev, PMSG_SUSPEND); | 797 | return pci_legacy_suspend_late(dev, PMSG_SUSPEND); |
781 | 798 | ||
@@ -834,6 +851,14 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
834 | struct device_driver *drv = dev->driver; | 851 | struct device_driver *drv = dev->driver; |
835 | int error = 0; | 852 | int error = 0; |
836 | 853 | ||
854 | /* | ||
855 | * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend | ||
856 | * during system suspend, so update their runtime PM status to "active" | ||
857 | * as they are going to be put into D0 shortly. | ||
858 | */ | ||
859 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
860 | pm_runtime_set_active(dev); | ||
861 | |||
837 | pci_pm_default_resume_early(pci_dev); | 862 | pci_pm_default_resume_early(pci_dev); |
838 | 863 | ||
839 | if (pci_has_legacy_pm_support(pci_dev)) | 864 | if (pci_has_legacy_pm_support(pci_dev)) |
@@ -876,6 +901,7 @@ static int pci_pm_resume(struct device *dev) | |||
876 | #else /* !CONFIG_SUSPEND */ | 901 | #else /* !CONFIG_SUSPEND */ |
877 | 902 | ||
878 | #define pci_pm_suspend NULL | 903 | #define pci_pm_suspend NULL |
904 | #define pci_pm_suspend_late NULL | ||
879 | #define pci_pm_suspend_noirq NULL | 905 | #define pci_pm_suspend_noirq NULL |
880 | #define pci_pm_resume NULL | 906 | #define pci_pm_resume NULL |
881 | #define pci_pm_resume_noirq NULL | 907 | #define pci_pm_resume_noirq NULL |
@@ -910,7 +936,8 @@ static int pci_pm_freeze(struct device *dev) | |||
910 | * devices should not be touched during freeze/thaw transitions, | 936 | * devices should not be touched during freeze/thaw transitions, |
911 | * however. | 937 | * however. |
912 | */ | 938 | */ |
913 | pm_runtime_resume(dev); | 939 | if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) |
940 | pm_runtime_resume(dev); | ||
914 | 941 | ||
915 | pci_dev->state_saved = false; | 942 | pci_dev->state_saved = false; |
916 | if (pm->freeze) { | 943 | if (pm->freeze) { |
@@ -925,11 +952,22 @@ static int pci_pm_freeze(struct device *dev) | |||
925 | return 0; | 952 | return 0; |
926 | } | 953 | } |
927 | 954 | ||
955 | static int pci_pm_freeze_late(struct device *dev) | ||
956 | { | ||
957 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
958 | return 0; | ||
959 | |||
960 | return pm_generic_freeze_late(dev);; | ||
961 | } | ||
962 | |||
928 | static int pci_pm_freeze_noirq(struct device *dev) | 963 | static int pci_pm_freeze_noirq(struct device *dev) |
929 | { | 964 | { |
930 | struct pci_dev *pci_dev = to_pci_dev(dev); | 965 | struct pci_dev *pci_dev = to_pci_dev(dev); |
931 | struct device_driver *drv = dev->driver; | 966 | struct device_driver *drv = dev->driver; |
932 | 967 | ||
968 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
969 | return 0; | ||
970 | |||
933 | if (pci_has_legacy_pm_support(pci_dev)) | 971 | if (pci_has_legacy_pm_support(pci_dev)) |
934 | return pci_legacy_suspend_late(dev, PMSG_FREEZE); | 972 | return pci_legacy_suspend_late(dev, PMSG_FREEZE); |
935 | 973 | ||
@@ -959,6 +997,16 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
959 | struct device_driver *drv = dev->driver; | 997 | struct device_driver *drv = dev->driver; |
960 | int error = 0; | 998 | int error = 0; |
961 | 999 | ||
1000 | /* | ||
1001 | * If the device is in runtime suspend, the code below may not work | ||
1002 | * correctly with it, so skip that code and make the PM core skip all of | ||
1003 | * the subsequent "thaw" callbacks for the device. | ||
1004 | */ | ||
1005 | if (dev_pm_smart_suspend_and_suspended(dev)) { | ||
1006 | dev->power.direct_complete = true; | ||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
962 | if (pcibios_pm_ops.thaw_noirq) { | 1010 | if (pcibios_pm_ops.thaw_noirq) { |
963 | error = pcibios_pm_ops.thaw_noirq(dev); | 1011 | error = pcibios_pm_ops.thaw_noirq(dev); |
964 | if (error) | 1012 | if (error) |
@@ -1008,11 +1056,13 @@ static int pci_pm_poweroff(struct device *dev) | |||
1008 | 1056 | ||
1009 | if (!pm) { | 1057 | if (!pm) { |
1010 | pci_pm_default_suspend(pci_dev); | 1058 | pci_pm_default_suspend(pci_dev); |
1011 | goto Fixup; | 1059 | return 0; |
1012 | } | 1060 | } |
1013 | 1061 | ||
1014 | /* The reason to do that is the same as in pci_pm_suspend(). */ | 1062 | /* The reason to do that is the same as in pci_pm_suspend(). */ |
1015 | pm_runtime_resume(dev); | 1063 | if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || |
1064 | !pci_dev_keep_suspended(pci_dev)) | ||
1065 | pm_runtime_resume(dev); | ||
1016 | 1066 | ||
1017 | pci_dev->state_saved = false; | 1067 | pci_dev->state_saved = false; |
1018 | if (pm->poweroff) { | 1068 | if (pm->poweroff) { |
@@ -1024,17 +1074,27 @@ static int pci_pm_poweroff(struct device *dev) | |||
1024 | return error; | 1074 | return error; |
1025 | } | 1075 | } |
1026 | 1076 | ||
1027 | Fixup: | ||
1028 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
1029 | |||
1030 | return 0; | 1077 | return 0; |
1031 | } | 1078 | } |
1032 | 1079 | ||
1080 | static int pci_pm_poweroff_late(struct device *dev) | ||
1081 | { | ||
1082 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
1083 | return 0; | ||
1084 | |||
1085 | pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev)); | ||
1086 | |||
1087 | return pm_generic_poweroff_late(dev); | ||
1088 | } | ||
1089 | |||
1033 | static int pci_pm_poweroff_noirq(struct device *dev) | 1090 | static int pci_pm_poweroff_noirq(struct device *dev) |
1034 | { | 1091 | { |
1035 | struct pci_dev *pci_dev = to_pci_dev(dev); | 1092 | struct pci_dev *pci_dev = to_pci_dev(dev); |
1036 | struct device_driver *drv = dev->driver; | 1093 | struct device_driver *drv = dev->driver; |
1037 | 1094 | ||
1095 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
1096 | return 0; | ||
1097 | |||
1038 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) | 1098 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) |
1039 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | 1099 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); |
1040 | 1100 | ||
@@ -1076,6 +1136,10 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
1076 | struct device_driver *drv = dev->driver; | 1136 | struct device_driver *drv = dev->driver; |
1077 | int error = 0; | 1137 | int error = 0; |
1078 | 1138 | ||
1139 | /* This is analogous to the pci_pm_resume_noirq() case. */ | ||
1140 | if (dev_pm_smart_suspend_and_suspended(dev)) | ||
1141 | pm_runtime_set_active(dev); | ||
1142 | |||
1079 | if (pcibios_pm_ops.restore_noirq) { | 1143 | if (pcibios_pm_ops.restore_noirq) { |
1080 | error = pcibios_pm_ops.restore_noirq(dev); | 1144 | error = pcibios_pm_ops.restore_noirq(dev); |
1081 | if (error) | 1145 | if (error) |
@@ -1124,10 +1188,12 @@ static int pci_pm_restore(struct device *dev) | |||
1124 | #else /* !CONFIG_HIBERNATE_CALLBACKS */ | 1188 | #else /* !CONFIG_HIBERNATE_CALLBACKS */ |
1125 | 1189 | ||
1126 | #define pci_pm_freeze NULL | 1190 | #define pci_pm_freeze NULL |
1191 | #define pci_pm_freeze_late NULL | ||
1127 | #define pci_pm_freeze_noirq NULL | 1192 | #define pci_pm_freeze_noirq NULL |
1128 | #define pci_pm_thaw NULL | 1193 | #define pci_pm_thaw NULL |
1129 | #define pci_pm_thaw_noirq NULL | 1194 | #define pci_pm_thaw_noirq NULL |
1130 | #define pci_pm_poweroff NULL | 1195 | #define pci_pm_poweroff NULL |
1196 | #define pci_pm_poweroff_late NULL | ||
1131 | #define pci_pm_poweroff_noirq NULL | 1197 | #define pci_pm_poweroff_noirq NULL |
1132 | #define pci_pm_restore NULL | 1198 | #define pci_pm_restore NULL |
1133 | #define pci_pm_restore_noirq NULL | 1199 | #define pci_pm_restore_noirq NULL |
@@ -1243,10 +1309,13 @@ static const struct dev_pm_ops pci_dev_pm_ops = { | |||
1243 | .prepare = pci_pm_prepare, | 1309 | .prepare = pci_pm_prepare, |
1244 | .complete = pci_pm_complete, | 1310 | .complete = pci_pm_complete, |
1245 | .suspend = pci_pm_suspend, | 1311 | .suspend = pci_pm_suspend, |
1312 | .suspend_late = pci_pm_suspend_late, | ||
1246 | .resume = pci_pm_resume, | 1313 | .resume = pci_pm_resume, |
1247 | .freeze = pci_pm_freeze, | 1314 | .freeze = pci_pm_freeze, |
1315 | .freeze_late = pci_pm_freeze_late, | ||
1248 | .thaw = pci_pm_thaw, | 1316 | .thaw = pci_pm_thaw, |
1249 | .poweroff = pci_pm_poweroff, | 1317 | .poweroff = pci_pm_poweroff, |
1318 | .poweroff_late = pci_pm_poweroff_late, | ||
1250 | .restore = pci_pm_restore, | 1319 | .restore = pci_pm_restore, |
1251 | .suspend_noirq = pci_pm_suspend_noirq, | 1320 | .suspend_noirq = pci_pm_suspend_noirq, |
1252 | .resume_noirq = pci_pm_resume_noirq, | 1321 | .resume_noirq = pci_pm_resume_noirq, |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 43b5418e05bb..65d39115f06d 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -765,6 +765,8 @@ extern int pm_generic_poweroff_late(struct device *dev); | |||
765 | extern int pm_generic_poweroff(struct device *dev); | 765 | extern int pm_generic_poweroff(struct device *dev); |
766 | extern void pm_generic_complete(struct device *dev); | 766 | extern void pm_generic_complete(struct device *dev); |
767 | 767 | ||
768 | extern bool dev_pm_smart_suspend_and_suspended(struct device *dev); | ||
769 | |||
768 | #else /* !CONFIG_PM_SLEEP */ | 770 | #else /* !CONFIG_PM_SLEEP */ |
769 | 771 | ||
770 | #define device_pm_lock() do {} while (0) | 772 | #define device_pm_lock() do {} while (0) |