Merge branch 'pm-core'

* pm-core:
  ACPI / PM: Take SMART_SUSPEND driver flag into account
  PCI / PM: Take SMART_SUSPEND driver flag into account
  PCI / PM: Drop unnecessary invocations of pcibios_pm_ops callbacks
  PM / core: Add SMART_SUSPEND driver flag
  PCI / PM: Use the NEVER_SKIP driver flag
  PM / core: Add NEVER_SKIP and SMART_PREPARE driver flags
  PM / core: Convert timers to use timer_setup()
  PM / core: Fix kerneldoc comments of four functions
  PM / core: Drop legacy class suspend/resume operations
This commit is contained in:
Rafael J. Wysocki
2017-11-13 01:41:26 +01:00
17 changed files with 371 additions and 103 deletions

View File

@@ -682,8 +682,11 @@ static int pci_pm_prepare(struct device *dev)
if (drv && drv->pm && drv->pm->prepare) {
int error = drv->pm->prepare(dev);
if (error)
if (error < 0)
return error;
if (!error && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE))
return 0;
}
return pci_dev_keep_suspended(to_pci_dev(dev));
}
@@ -724,18 +727,25 @@ static int pci_pm_suspend(struct device *dev)
if (!pm) {
pci_pm_default_suspend(pci_dev);
goto Fixup;
return 0;
}
/*
* PCI devices suspended at run time need to be resumed at this point,
* because in general it is necessary to reconfigure them for system
* suspend. Namely, if the device is supposed to wake up the system
* from the sleep state, we may need to reconfigure it for this purpose.
* In turn, if the device is not supposed to wake up the system from the
* sleep state, we'll have to prevent it from signaling wake-up.
* PCI devices suspended at run time may need to be resumed at this
* point, because in general it may be necessary to reconfigure them for
* system suspend. Namely, if the device is expected to wake up the
* system from the sleep state, it may have to be reconfigured for this
* purpose, or if the device is not expected to wake up the system from
* the sleep state, it should be prevented from signaling wakeup events
* going forward.
*
* Also if the driver of the device does not indicate that its system
* suspend callbacks can cope with runtime-suspended devices, it is
* better to resume the device from runtime suspend here.
*/
pm_runtime_resume(dev);
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
!pci_dev_keep_suspended(pci_dev))
pm_runtime_resume(dev);
pci_dev->state_saved = false;
if (pm->suspend) {
@@ -755,17 +765,27 @@ static int pci_pm_suspend(struct device *dev)
}
}
Fixup:
pci_fixup_device(pci_fixup_suspend, pci_dev);
return 0;
}
static int pci_pm_suspend_late(struct device *dev)
{
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
return pm_generic_suspend_late(dev);
}
static int pci_pm_suspend_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
@@ -827,6 +847,14 @@ static int pci_pm_resume_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
/*
* Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
* during system suspend, so update their runtime PM status to "active"
* as they are going to be put into D0 shortly.
*/
if (dev_pm_smart_suspend_and_suspended(dev))
pm_runtime_set_active(dev);
pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
@@ -869,6 +897,7 @@ static int pci_pm_resume(struct device *dev)
#else /* !CONFIG_SUSPEND */
#define pci_pm_suspend NULL
#define pci_pm_suspend_late NULL
#define pci_pm_suspend_noirq NULL
#define pci_pm_resume NULL
#define pci_pm_resume_noirq NULL
@@ -903,7 +932,8 @@ static int pci_pm_freeze(struct device *dev)
* devices should not be touched during freeze/thaw transitions,
* however.
*/
pm_runtime_resume(dev);
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
pm_runtime_resume(dev);
pci_dev->state_saved = false;
if (pm->freeze) {
@@ -915,17 +945,25 @@ static int pci_pm_freeze(struct device *dev)
return error;
}
if (pcibios_pm_ops.freeze)
return pcibios_pm_ops.freeze(dev);
return 0;
}
static int pci_pm_freeze_late(struct device *dev)
{
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
return pm_generic_freeze_late(dev);;
}
static int pci_pm_freeze_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend_late(dev, PMSG_FREEZE);
@@ -955,6 +993,16 @@ static int pci_pm_thaw_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
/*
* If the device is in runtime suspend, the code below may not work
* correctly with it, so skip that code and make the PM core skip all of
* the subsequent "thaw" callbacks for the device.
*/
if (dev_pm_smart_suspend_and_suspended(dev)) {
dev->power.direct_complete = true;
return 0;
}
if (pcibios_pm_ops.thaw_noirq) {
error = pcibios_pm_ops.thaw_noirq(dev);
if (error)
@@ -979,12 +1027,6 @@ static int pci_pm_thaw(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
if (pcibios_pm_ops.thaw) {
error = pcibios_pm_ops.thaw(dev);
if (error)
return error;
}
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume(dev);
@@ -1010,11 +1052,13 @@ static int pci_pm_poweroff(struct device *dev)
if (!pm) {
pci_pm_default_suspend(pci_dev);
goto Fixup;
return 0;
}
/* The reason to do that is the same as in pci_pm_suspend(). */
pm_runtime_resume(dev);
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
!pci_dev_keep_suspended(pci_dev))
pm_runtime_resume(dev);
pci_dev->state_saved = false;
if (pm->poweroff) {
@@ -1026,20 +1070,27 @@ static int pci_pm_poweroff(struct device *dev)
return error;
}
Fixup:
pci_fixup_device(pci_fixup_suspend, pci_dev);
if (pcibios_pm_ops.poweroff)
return pcibios_pm_ops.poweroff(dev);
return 0;
}
static int pci_pm_poweroff_late(struct device *dev)
{
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
return pm_generic_poweroff_late(dev);
}
static int pci_pm_poweroff_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
@@ -1081,6 +1132,10 @@ static int pci_pm_restore_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
/* This is analogous to the pci_pm_resume_noirq() case. */
if (dev_pm_smart_suspend_and_suspended(dev))
pm_runtime_set_active(dev);
if (pcibios_pm_ops.restore_noirq) {
error = pcibios_pm_ops.restore_noirq(dev);
if (error)
@@ -1104,12 +1159,6 @@ static int pci_pm_restore(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
if (pcibios_pm_ops.restore) {
error = pcibios_pm_ops.restore(dev);
if (error)
return error;
}
/*
* This is necessary for the hibernation error path in which restore is
* called without restoring the standard config registers of the device.
@@ -1135,10 +1184,12 @@ static int pci_pm_restore(struct device *dev)
#else /* !CONFIG_HIBERNATE_CALLBACKS */
#define pci_pm_freeze NULL
#define pci_pm_freeze_late NULL
#define pci_pm_freeze_noirq NULL
#define pci_pm_thaw NULL
#define pci_pm_thaw_noirq NULL
#define pci_pm_poweroff NULL
#define pci_pm_poweroff_late NULL
#define pci_pm_poweroff_noirq NULL
#define pci_pm_restore NULL
#define pci_pm_restore_noirq NULL
@@ -1254,10 +1305,13 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.complete = pci_pm_complete,
.suspend = pci_pm_suspend,
.suspend_late = pci_pm_suspend_late,
.resume = pci_pm_resume,
.freeze = pci_pm_freeze,
.freeze_late = pci_pm_freeze_late,
.thaw = pci_pm_thaw,
.poweroff = pci_pm_poweroff,
.poweroff_late = pci_pm_poweroff_late,
.restore = pci_pm_restore,
.suspend_noirq = pci_pm_suspend_noirq,
.resume_noirq = pci_pm_resume_noirq,