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:
@@ -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,
|
||||
|
Reference in New Issue
Block a user