===================================================================
@@ -236,3 +236,8 @@ config PM_RUNTIME
and the bus type drivers of the buses the devices are on are
responsible for the actual handling of the autosuspend requests and
wake-up events.
+
+config PM_OPERATIONS
+ bool
+ depends on PM_SLEEP || PM_RUNTIME
+ default y
===================================================================
@@ -509,7 +509,7 @@ static int pci_restore_standard_config(s
return pci_restore_state(pci_dev);
}
-static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
+static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
{
pci_restore_standard_config(pci_dev);
pci_fixup_device(pci_fixup_resume_early, pci_dev);
@@ -653,7 +653,7 @@ static int pci_pm_resume_noirq(struct de
struct device_driver *drv = dev->driver;
int error = 0;
- pci_pm_default_resume_noirq(pci_dev);
+ pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -849,7 +849,7 @@ static int pci_pm_restore_noirq(struct d
struct device_driver *drv = dev->driver;
int error = 0;
- pci_pm_default_resume_noirq(pci_dev);
+ pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -901,6 +901,89 @@ static int pci_pm_restore(struct device
#endif /* !CONFIG_HIBERNATION */
+#endif /* !CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int pci_pm_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ pci_power_t prev = pci_dev->current_state;
+ int error;
+
+ if (!pm || !pm->runtime_suspend)
+ return -ENOSYS;
+
+ error = pm->runtime_suspend(dev);
+ suspend_report_result(pm->runtime_suspend, error);
+ if (error)
+ return error;
+
+ pci_fixup_device(pci_fixup_suspend, pci_dev);
+
+ if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+ && pci_dev->current_state != PCI_UNKNOWN) {
+ WARN_ONCE(pci_dev->current_state != prev,
+ "PCI PM: State of device not saved by %pF\n",
+ pm->runtime_suspend);
+ return 0;
+ }
+
+ if (!pci_dev->state_saved) {
+ pci_save_state(pci_dev);
+ if (!pci_is_bridge(pci_dev))
+ pci_prepare_to_sleep(pci_dev);
+ }
+
+ pci_pm_set_unknown_state(pci_dev);
+
+ return 0;
+}
+
+static int pci_pm_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int error;
+
+ if (!pm || !pm->runtime_resume)
+ return -ENOSYS;
+
+ pci_pm_default_resume_early(pci_dev);
+ pci_pm_default_resume(pci_dev);
+
+ return pm->runtime_resume(dev);
+}
+
+static int pci_pm_runtime_idle(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (!pm)
+ return -ENOSYS;
+
+ if (pm->runtime_idle) {
+ int ret = pm->runtime_idle(dev);
+ if (ret)
+ return ret;
+ }
+
+ pm_runtime_suspend(dev);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define pci_pm_runtime_suspend NULL
+#define pci_pm_runtime_resume NULL
+#define pci_pm_runtime_idle NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+#ifdef COMFIG_PM_OPERATIONS
+
const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.complete = pci_pm_complete,
@@ -916,15 +999,18 @@ const struct dev_pm_ops pci_dev_pm_ops =
.thaw_noirq = pci_pm_thaw_noirq,
.poweroff_noirq = pci_pm_poweroff_noirq,
.restore_noirq = pci_pm_restore_noirq,
+ .runtime_suspend = pci_pm_runtime_suspend,
+ .runtime_resume = pci_pm_runtime_resume,
+ .runtime_idle = pci_pm_runtime_idle,
};
#define PCI_PM_OPS_PTR (&pci_dev_pm_ops)
-#else /* !CONFIG_PM_SLEEP */
+#else /* !COMFIG_PM_OPERATIONS */
#define PCI_PM_OPS_PTR NULL
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* !COMFIG_PM_OPERATIONS */
/**
* __pci_register_driver - register a new pci driver