aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-26 06:12:22 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-06 07:57:46 -0500
commitc4b65157aeefad29b2351a00a010e8c40ce7fd0e (patch)
treeb1b8d90e30729fc4d7d918d1df7d014ba6d448c8
parent302666d8a55ce7eb5fb0bd9fbd9437d74e0ce77c (diff)
PCI / PM: Take SMART_SUSPEND driver flag into account
Make the PCI bus type take DPM_FLAG_SMART_SUSPEND into account in its system-wide PM callbacks and make sure that all code that should not run in parallel with pci_pm_runtime_resume() is executed in the "late" phases of system suspend, freeze and poweroff transitions. [Note that the pm_runtime_suspended() check in pci_dev_keep_suspended() is an optimization, because if is not passed, all of the subsequent checks may be skipped and some of them are much more overhead in general.] Also use the observation that if the device is in runtime suspend at the beginning of the "late" phase of a system-wide suspend-like transition, its state cannot change going forward (runtime PM is disabled for it at that time) until the transition is over and the subsequent system-wide PM callbacks should be skipped for it (as they generally assume the device to not be suspended), so add checks for that in pci_pm_suspend_late/noirq(), pci_pm_freeze_late/noirq() and pci_pm_poweroff_late/noirq(). Moreover, if pci_pm_resume_noirq() or pci_pm_restore_noirq() is called during the subsequent system-wide resume transition and if the device was left in runtime suspend previously, its runtime PM status needs to be changed to "active" as it is going to be put into the full-power state, so add checks for that too to these functions. In turn, if pci_pm_thaw_noirq() runs after the device has been left in runtime suspend, the subsequent "thaw" callbacks need to be skipped for it (as they may not work correctly with a suspended device), so set the power.direct_complete flag for the device then to make the PM core skip those callbacks. In addition to the above add a core helper for checking if DPM_FLAG_SMART_SUSPEND is set and the device runtime PM status is "suspended" at the same time, which is done quite often in the new code (and will be done elsewhere going forward too). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--Documentation/power/pci.txt14
-rw-r--r--drivers/base/power/main.c6
-rw-r--r--drivers/pci/pci-driver.c103
-rw-r--r--include/linux/pm.h2
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
980driver of the device returns a positive value. That allows the driver to opt 980driver of the device returns a positive value. That allows the driver to opt
981out from using the direct-complete mechanism dynamically. 981out from using the direct-complete mechanism dynamically.
982 982
983The DPM_FLAG_SMART_SUSPEND flag tells the PCI bus type that from the driver's
984perspective the device can be safely left in runtime suspend during system
985suspend. That causes pci_pm_suspend(), pci_pm_freeze() and pci_pm_poweroff()
986to skip resuming the device from runtime suspend unless there are PCI-specific
987reasons for doing that. Also, it causes pci_pm_suspend_late/noirq(),
988pci_pm_freeze_late/noirq() and pci_pm_poweroff_late/noirq() to return early
989if the device remains in runtime suspend in the beginning of the "late" phase
990of the system-wide transition under way. Moreover, if the device is in
991runtime suspend in pci_pm_resume_noirq() or pci_pm_restore_noirq(), its runtime
992power management status will be changed to "active" (as it is going to be put
993into D0 going forward), but if it is in runtime suspend in pci_pm_thaw_noirq(),
994the function will set the power.direct_complete flag for it (to make the PM core
995skip the subsequent "thaw" callbacks for it) and return.
996
9833.2. Device Runtime Power Management 9973.2. Device Runtime Power Management
984------------------------------------ 998------------------------------------
985In addition to providing device power management callbacks PCI device drivers 999In 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
1865bool 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
778static 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
774static int pci_pm_suspend_noirq(struct device *dev) 788static 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
955static 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
928static int pci_pm_freeze_noirq(struct device *dev) 963static 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
1080static 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
1033static int pci_pm_poweroff_noirq(struct device *dev) 1090static 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);
765extern int pm_generic_poweroff(struct device *dev); 765extern int pm_generic_poweroff(struct device *dev);
766extern void pm_generic_complete(struct device *dev); 766extern void pm_generic_complete(struct device *dev);
767 767
768extern 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)