aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci/pci-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r--drivers/pci/pci-driver.c90
1 files changed, 59 insertions, 31 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index a13f53486114..2d04b285afea 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -287,6 +287,14 @@ static void pci_device_shutdown(struct device *dev)
#ifdef CONFIG_PM_SLEEP
+static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
+{
+ struct pci_driver *drv = pci_dev->driver;
+
+ return drv && (drv->suspend || drv->suspend_late || drv->resume
+ || drv->resume_early);
+}
+
/*
* Default "suspend" method for devices that have no driver provided suspend,
* or not even a driver at all.
@@ -304,14 +312,22 @@ static void pci_default_pm_suspend(struct pci_dev *pci_dev)
/*
* Default "resume" method for devices that have no driver provided resume,
- * or not even a driver at all.
+ * or not even a driver at all (first part).
*/
-static int pci_default_pm_resume(struct pci_dev *pci_dev)
+static void pci_default_pm_resume_early(struct pci_dev *pci_dev)
{
- int retval = 0;
-
/* restore the PCI config space */
pci_restore_state(pci_dev);
+}
+
+/*
+ * Default "resume" method for devices that have no driver provided resume,
+ * or not even a driver at all (second part).
+ */
+static int pci_default_pm_resume_late(struct pci_dev *pci_dev)
+{
+ int retval;
+
/* if the device was enabled before suspend, reenable */
retval = pci_reenable_device(pci_dev);
/*
@@ -358,10 +374,12 @@ static int pci_legacy_resume(struct device *dev)
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
- if (drv && drv->resume)
+ if (drv && drv->resume) {
error = drv->resume(pci_dev);
- else
- error = pci_default_pm_resume(pci_dev);
+ } else {
+ pci_default_pm_resume_early(pci_dev);
+ error = pci_default_pm_resume_late(pci_dev);
+ }
return error;
}
@@ -407,10 +425,8 @@ static int pci_pm_suspend(struct device *dev)
if (drv->pm->suspend) {
error = drv->pm->suspend(dev);
suspend_report_result(drv->pm->suspend, error);
- } else {
- pci_default_pm_suspend(pci_dev);
}
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_suspend(dev, PMSG_SUSPEND);
}
pci_fixup_device(pci_fixup_suspend, pci_dev);
@@ -429,8 +445,10 @@ static int pci_pm_suspend_noirq(struct device *dev)
error = drv->pm->suspend_noirq(dev);
suspend_report_result(drv->pm->suspend_noirq, error);
}
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_suspend_late(dev, PMSG_SUSPEND);
+ } else {
+ pci_default_pm_suspend(pci_dev);
}
return error;
@@ -440,15 +458,17 @@ static int pci_pm_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
- int error;
+ int error = 0;
pci_fixup_device(pci_fixup_resume, pci_dev);
if (drv && drv->pm) {
- error = drv->pm->resume ? drv->pm->resume(dev) :
- pci_default_pm_resume(pci_dev);
- } else {
+ if (drv->pm->resume)
+ error = drv->pm->resume(dev);
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_resume(dev);
+ } else {
+ error = pci_default_pm_resume_late(pci_dev);
}
return error;
@@ -465,8 +485,10 @@ static int pci_pm_resume_noirq(struct device *dev)
if (drv && drv->pm) {
if (drv->pm->resume_noirq)
error = drv->pm->resume_noirq(dev);
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_resume_early(dev);
+ } else {
+ pci_default_pm_resume_early(pci_dev);
}
return error;
@@ -493,10 +515,8 @@ static int pci_pm_freeze(struct device *dev)
if (drv->pm->freeze) {
error = drv->pm->freeze(dev);
suspend_report_result(drv->pm->freeze, error);
- } else {
- pci_default_pm_suspend(pci_dev);
}
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_suspend(dev, PMSG_FREEZE);
pci_fixup_device(pci_fixup_suspend, pci_dev);
}
@@ -515,8 +535,10 @@ static int pci_pm_freeze_noirq(struct device *dev)
error = drv->pm->freeze_noirq(dev);
suspend_report_result(drv->pm->freeze_noirq, error);
}
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_suspend_late(dev, PMSG_FREEZE);
+ } else {
+ pci_default_pm_suspend(pci_dev);
}
return error;
@@ -524,14 +546,15 @@ static int pci_pm_freeze_noirq(struct device *dev)
static int pci_pm_thaw(struct device *dev)
{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
if (drv && drv->pm) {
if (drv->pm->thaw)
error = drv->pm->thaw(dev);
- } else {
- pci_fixup_device(pci_fixup_resume, to_pci_dev(dev));
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
+ pci_fixup_device(pci_fixup_resume, pci_dev);
error = pci_legacy_resume(dev);
}
@@ -547,7 +570,7 @@ static int pci_pm_thaw_noirq(struct device *dev)
if (drv && drv->pm) {
if (drv->pm->thaw_noirq)
error = drv->pm->thaw_noirq(dev);
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
pci_fixup_device(pci_fixup_resume_early, pci_dev);
error = pci_legacy_resume_early(dev);
}
@@ -557,17 +580,18 @@ static int pci_pm_thaw_noirq(struct device *dev)
static int pci_pm_poweroff(struct device *dev)
{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
+ pci_fixup_device(pci_fixup_suspend, pci_dev);
if (drv && drv->pm) {
if (drv->pm->poweroff) {
error = drv->pm->poweroff(dev);
suspend_report_result(drv->pm->poweroff, error);
}
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_suspend(dev, PMSG_HIBERNATE);
}
@@ -585,7 +609,7 @@ static int pci_pm_poweroff_noirq(struct device *dev)
error = drv->pm->poweroff_noirq(dev);
suspend_report_result(drv->pm->poweroff_noirq, error);
}
- } else {
+ } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) {
error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
}
@@ -596,13 +620,15 @@ static int pci_pm_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
- int error;
+ int error = 0;
if (drv && drv->pm) {
- error = drv->pm->restore ? drv->pm->restore(dev) :
- pci_default_pm_resume(pci_dev);
- } else {
+ if (drv->pm->restore)
+ error = drv->pm->restore(dev);
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_resume(dev);
+ } else {
+ error = pci_default_pm_resume_late(pci_dev);
}
pci_fixup_device(pci_fixup_resume, pci_dev);
@@ -620,8 +646,10 @@ static int pci_pm_restore_noirq(struct device *dev)
if (drv && drv->pm) {
if (drv->pm->restore_noirq)
error = drv->pm->restore_noirq(dev);
- } else {
+ } else if (pci_has_legacy_pm_support(pci_dev)) {
error = pci_legacy_resume_early(dev);
+ } else {
+ pci_default_pm_resume_early(pci_dev);
}
pci_fixup_device(pci_fixup_resume_early, pci_dev);