Merge branch 'pm-core'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 13 Nov 2017 00:41:26 +0000 (01:41 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 13 Nov 2017 00:41:26 +0000 (01:41 +0100)
* 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

17 files changed:
Documentation/driver-api/pm/devices.rst
Documentation/power/pci.txt
drivers/acpi/acpi_lpss.c
drivers/acpi/device_pm.c
drivers/base/dd.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/gpu/drm/i915/i915_drv.c
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
include/linux/acpi.h
include/linux/device.h
include/linux/pci.h
include/linux/pm.h

index b5d7d4948e933b0be10ad6e66bd68b6d6f023dc7..53c1b0b06da5faae4670b33dd37e365e145b4210 100644 (file)
@@ -354,6 +354,20 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``.
        is because all such devices are initially set to runtime-suspended with
        runtime PM disabled.
 
+       This feature also can be controlled by device drivers by using the
+       ``DPM_FLAG_NEVER_SKIP`` and ``DPM_FLAG_SMART_PREPARE`` driver power
+       management flags.  [Typically, they are set at the time the driver is
+       probed against the device in question by passing them to the
+       :c:func:`dev_pm_set_driver_flags` helper function.]  If the first of
+       these flags is set, the PM core will not apply the direct-complete
+       procedure described above to the given device and, consequenty, to any
+       of its ancestors.  The second flag, when set, informs the middle layer
+       code (bus types, device types, PM domains, classes) that it should take
+       the return value of the ``->prepare`` callback provided by the driver
+       into account and it may only return a positive value from its own
+       ``->prepare`` callback if the driver's one also has returned a positive
+       value.
+
     2. The ``->suspend`` methods should quiesce the device to stop it from
        performing I/O.  They also may save the device registers and put it into
        the appropriate low-power state, depending on the bus type the device is
@@ -752,6 +766,26 @@ the state of devices (possibly except for resuming them from runtime suspend)
 from their ``->prepare`` and ``->suspend`` callbacks (or equivalent) *before*
 invoking device drivers' ``->suspend`` callbacks (or equivalent).
 
+Some bus types and PM domains have a policy to resume all devices from runtime
+suspend upfront in their ``->suspend`` callbacks, but that may not be really
+necessary if the driver of the device can cope with runtime-suspended devices.
+The driver can indicate that by setting ``DPM_FLAG_SMART_SUSPEND`` in
+:c:member:`power.driver_flags` at the probe time, by passing it to the
+:c:func:`dev_pm_set_driver_flags` helper.  That also may cause middle-layer code
+(bus types, PM domains etc.) to skip the ``->suspend_late`` and
+``->suspend_noirq`` callbacks provided by the driver if the device remains in
+runtime suspend at the beginning of the ``suspend_late`` phase of system-wide
+suspend (or in the ``poweroff_late`` phase of hibernation), when runtime PM
+has been disabled for it, under the assumption that its state should not change
+after that point until the system-wide transition is over.  If that happens, the
+driver's system-wide resume callbacks, if present, may still be invoked during
+the subsequent system-wide resume transition and the device's runtime power
+management status may be set to "active" before enabling runtime PM for it,
+so the driver must be prepared to cope with the invocation of its system-wide
+resume callbacks back-to-back with its ``->runtime_suspend`` one (without the
+intervening ``->runtime_resume`` and so on) and the final state of the device
+must reflect the "active" status for runtime PM in that case.
+
 During system-wide resume from a sleep state it's easiest to put devices into
 the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`.
 Refer to that document for more information regarding this particular issue as
index a1b7f715893050bc16a94b8ae63b50b9c51d3479..304162ea377eddd3c2b133fbda1f23378e8f6967 100644 (file)
@@ -961,6 +961,39 @@ dev_pm_ops to indicate that one suspend routine is to be pointed to by the
 .suspend(), .freeze(), and .poweroff() members and one resume routine is to
 be pointed to by the .resume(), .thaw(), and .restore() members.
 
+3.1.19. Driver Flags for Power Management
+
+The PM core allows device drivers to set flags that influence the handling of
+power management for the devices by the core itself and by middle layer code
+including the PCI bus type.  The flags should be set once at the driver probe
+time with the help of the dev_pm_set_driver_flags() function and they should not
+be updated directly afterwards.
+
+The DPM_FLAG_NEVER_SKIP flag prevents the PM core from using the direct-complete
+mechanism allowing device suspend/resume callbacks to be skipped if the device
+is in runtime suspend when the system suspend starts.  That also affects all of
+the ancestors of the device, so this flag should only be used if absolutely
+necessary.
+
+The DPM_FLAG_SMART_PREPARE flag instructs the PCI bus type to only return a
+positive value from pci_pm_prepare() if the ->prepare callback provided by the
+driver of the device returns a positive value.  That allows the driver to opt
+out from using the direct-complete mechanism dynamically.
+
+The DPM_FLAG_SMART_SUSPEND flag tells the PCI bus type that from the driver's
+perspective the device can be safely left in runtime suspend during system
+suspend.  That causes pci_pm_suspend(), pci_pm_freeze() and pci_pm_poweroff()
+to skip resuming the device from runtime suspend unless there are PCI-specific
+reasons for doing that.  Also, it causes pci_pm_suspend_late/noirq(),
+pci_pm_freeze_late/noirq() and pci_pm_poweroff_late/noirq() to return early
+if the device remains in runtime suspend in the beginning of the "late" phase
+of the system-wide transition under way.  Moreover, if the device is in
+runtime suspend in pci_pm_resume_noirq() or pci_pm_restore_noirq(), its runtime
+power management status will be changed to "active" (as it is going to be put
+into D0 going forward), but if it is in runtime suspend in pci_pm_thaw_noirq(),
+the function will set the power.direct_complete flag for it (to make the PM core
+skip the subsequent "thaw" callbacks for it) and return.
+
 3.2. Device Runtime Power Management
 ------------------------------------
 In addition to providing device power management callbacks PCI device drivers
index 04d32bdb5a95b573d3c3cac5d724b86969e574b9..de7385b824e153e1b5587bd134b7d42ca640d0e7 100644 (file)
@@ -849,8 +849,12 @@ static int acpi_lpss_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int acpi_lpss_suspend_late(struct device *dev)
 {
-       int ret = pm_generic_suspend_late(dev);
+       int ret;
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
 
+       ret = pm_generic_suspend_late(dev);
        return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
 }
 
@@ -889,10 +893,17 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
                .complete = acpi_subsys_complete,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_lpss_suspend_late,
+               .suspend_noirq = acpi_subsys_suspend_noirq,
+               .resume_noirq = acpi_subsys_resume_noirq,
                .resume_early = acpi_lpss_resume_early,
                .freeze = acpi_subsys_freeze,
+               .freeze_late = acpi_subsys_freeze_late,
+               .freeze_noirq = acpi_subsys_freeze_noirq,
+               .thaw_noirq = acpi_subsys_thaw_noirq,
                .poweroff = acpi_subsys_suspend,
                .poweroff_late = acpi_lpss_suspend_late,
+               .poweroff_noirq = acpi_subsys_suspend_noirq,
+               .restore_noirq = acpi_subsys_resume_noirq,
                .restore_early = acpi_lpss_resume_early,
 #endif
                .runtime_suspend = acpi_lpss_runtime_suspend,
index 69ffd1dc1de73370d716bf6a1f530327376467e8..e4ffaeec9ec204110f7e50c5cff49172a486f081 100644 (file)
@@ -939,7 +939,8 @@ static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev)
        u32 sys_target = acpi_target_system_state();
        int ret, state;
 
-       if (device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
+       if (!pm_runtime_suspended(dev) || !adev ||
+           device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
                return true;
 
        if (sys_target == ACPI_STATE_S0)
@@ -962,14 +963,16 @@ static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev)
 int acpi_subsys_prepare(struct device *dev)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
-       int ret;
 
-       ret = pm_generic_prepare(dev);
-       if (ret < 0)
-               return ret;
+       if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) {
+               int ret = dev->driver->pm->prepare(dev);
 
-       if (!adev || !pm_runtime_suspended(dev))
-               return 0;
+               if (ret < 0)
+                       return ret;
+
+               if (!ret && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE))
+                       return 0;
+       }
 
        return !acpi_dev_needs_resume(dev, adev);
 }
@@ -996,12 +999,17 @@ EXPORT_SYMBOL_GPL(acpi_subsys_complete);
  * acpi_subsys_suspend - Run the device driver's suspend callback.
  * @dev: Device to handle.
  *
- * Follow PCI and resume devices suspended at run time before running their
- * system suspend callbacks.
+ * Follow PCI and resume devices from runtime suspend before running their
+ * system suspend callbacks, unless the driver can cope with runtime-suspended
+ * devices during system suspend and there are no ACPI-specific reasons for
+ * resuming them.
  */
 int acpi_subsys_suspend(struct device *dev)
 {
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+           acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
+               pm_runtime_resume(dev);
+
        return pm_generic_suspend(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
@@ -1015,11 +1023,47 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
  */
 int acpi_subsys_suspend_late(struct device *dev)
 {
-       int ret = pm_generic_suspend_late(dev);
+       int ret;
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       ret = pm_generic_suspend_late(dev);
        return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev));
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
 
+/**
+ * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback.
+ * @dev: Device to suspend.
+ */
+int acpi_subsys_suspend_noirq(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_suspend_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq);
+
+/**
+ * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_resume_noirq(struct device *dev)
+{
+       /*
+        * 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 will be put into D0 going forward.
+        */
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               pm_runtime_set_active(dev);
+
+       return pm_generic_resume_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
+
 /**
  * acpi_subsys_resume_early - Resume device using ACPI.
  * @dev: Device to Resume.
@@ -1047,11 +1091,60 @@ int acpi_subsys_freeze(struct device *dev)
         * runtime-suspended devices should not be touched during freeze/thaw
         * transitions.
         */
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
+               pm_runtime_resume(dev);
+
        return pm_generic_freeze(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
 
+/**
+ * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze_late(struct device *dev)
+{
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_freeze_late(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late);
+
+/**
+ * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze_noirq(struct device *dev)
+{
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_freeze_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq);
+
+/**
+ * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_thaw_noirq(struct device *dev)
+{
+       /*
+        * If the device is in runtime suspend, the "thaw" code may not work
+        * correctly with it, so skip the driver callback 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;
+       }
+
+       return pm_generic_thaw_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq);
 #endif /* CONFIG_PM_SLEEP */
 
 static struct dev_pm_domain acpi_general_pm_domain = {
@@ -1063,10 +1156,17 @@ static struct dev_pm_domain acpi_general_pm_domain = {
                .complete = acpi_subsys_complete,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_subsys_suspend_late,
+               .suspend_noirq = acpi_subsys_suspend_noirq,
+               .resume_noirq = acpi_subsys_resume_noirq,
                .resume_early = acpi_subsys_resume_early,
                .freeze = acpi_subsys_freeze,
+               .freeze_late = acpi_subsys_freeze_late,
+               .freeze_noirq = acpi_subsys_freeze_noirq,
+               .thaw_noirq = acpi_subsys_thaw_noirq,
                .poweroff = acpi_subsys_suspend,
                .poweroff_late = acpi_subsys_suspend_late,
+               .poweroff_noirq = acpi_subsys_suspend_noirq,
+               .restore_noirq = acpi_subsys_resume_noirq,
                .restore_early = acpi_subsys_resume_early,
 #endif
        },
index ad44b40fe2847d219e50a5d51d799f2541b5d6d0..45575e134696280b4b2de4635b9631f1737b0f58 100644 (file)
@@ -464,6 +464,7 @@ pinctrl_bind_failed:
        if (dev->pm_domain && dev->pm_domain->dismiss)
                dev->pm_domain->dismiss(dev);
        pm_runtime_reinit(dev);
+       dev_pm_set_driver_flags(dev, 0);
 
        switch (ret) {
        case -EPROBE_DEFER:
@@ -869,6 +870,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
                if (dev->pm_domain && dev->pm_domain->dismiss)
                        dev->pm_domain->dismiss(dev);
                pm_runtime_reinit(dev);
+               dev_pm_set_driver_flags(dev, 0);
 
                klist_remove(&dev->p->knode_driver);
                device_pm_check_callbacks(dev);
index 770b1539a083d111ba1a65b569d3a75eaa81dd38..6c6f1c74c24cdee9250a1e90b2352e80636bb61b 100644 (file)
@@ -528,7 +528,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
 /*------------------------- Resume routines -------------------------*/
 
 /**
- * device_resume_noirq - Execute an "early resume" callback for given device.
+ * device_resume_noirq - Execute a "noirq resume" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being resumed asynchronously.
@@ -848,16 +848,10 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
                goto Driver;
        }
 
-       if (dev->class) {
-               if (dev->class->pm) {
-                       info = "class ";
-                       callback = pm_op(dev->class->pm, state);
-                       goto Driver;
-               } else if (dev->class->resume) {
-                       info = "legacy class ";
-                       callback = dev->class->resume;
-                       goto End;
-               }
+       if (dev->class && dev->class->pm) {
+               info = "class ";
+               callback = pm_op(dev->class->pm, state);
+               goto Driver;
        }
 
        if (dev->bus) {
@@ -1083,7 +1077,7 @@ static pm_message_t resume_event(pm_message_t sleep_state)
 }
 
 /**
- * device_suspend_noirq - Execute a "late suspend" callback for given device.
+ * __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1243,7 +1237,7 @@ int dpm_suspend_noirq(pm_message_t state)
 }
 
 /**
- * device_suspend_late - Execute a "late suspend" callback for given device.
+ * __device_suspend_late - Execute a "late suspend" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1445,7 +1439,7 @@ static void dpm_clear_suppliers_direct_complete(struct device *dev)
 }
 
 /**
- * device_suspend - Execute "suspend" callbacks for given device.
+ * __device_suspend - Execute "suspend" callbacks for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1508,17 +1502,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto Run;
        }
 
-       if (dev->class) {
-               if (dev->class->pm) {
-                       info = "class ";
-                       callback = pm_op(dev->class->pm, state);
-                       goto Run;
-               } else if (dev->class->suspend) {
-                       pm_dev_dbg(dev, state, "legacy class ");
-                       error = legacy_suspend(dev, state, dev->class->suspend,
-                                               "legacy class ");
-                       goto End;
-               }
+       if (dev->class && dev->class->pm) {
+               info = "class ";
+               callback = pm_op(dev->class->pm, state);
+               goto Run;
        }
 
        if (dev->bus) {
@@ -1665,6 +1652,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
        if (dev->power.syscore)
                return 0;
 
+       WARN_ON(dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
+               !pm_runtime_enabled(dev));
+
        /*
         * If a device's parent goes into runtime suspend at the wrong time,
         * it won't be possible to resume the device.  To prevent this we
@@ -1713,7 +1703,9 @@ unlock:
         * applies to suspend transitions, however.
         */
        spin_lock_irq(&dev->power.lock);
-       dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;
+       dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&
+               pm_runtime_suspended(dev) && ret > 0 &&
+               !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP);
        spin_unlock_irq(&dev->power.lock);
        return 0;
 }
@@ -1862,11 +1854,16 @@ void device_pm_check_callbacks(struct device *dev)
        dev->power.no_pm_callbacks =
                (!dev->bus || (pm_ops_is_empty(dev->bus->pm) &&
                 !dev->bus->suspend && !dev->bus->resume)) &&
-               (!dev->class || (pm_ops_is_empty(dev->class->pm) &&
-                !dev->class->suspend && !dev->class->resume)) &&
+               (!dev->class || pm_ops_is_empty(dev->class->pm)) &&
                (!dev->type || pm_ops_is_empty(dev->type->pm)) &&
                (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) &&
                (!dev->driver || (pm_ops_is_empty(dev->driver->pm) &&
                 !dev->driver->suspend && !dev->driver->resume));
        spin_unlock_irq(&dev->power.lock);
 }
+
+bool dev_pm_smart_suspend_and_suspended(struct device *dev)
+{
+       return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
+               pm_runtime_status_suspended(dev);
+}
index 13e0159055431b1988ad941d7afe7b34bcc3cef7..e57b5d2f81cfa63838bf27ed9474dd559ccb54dd 100644 (file)
@@ -894,9 +894,9 @@ static void pm_runtime_work(struct work_struct *work)
  *
  * Check if the time is right and queue a suspend request.
  */
-static void pm_suspend_timer_fn(unsigned long data)
+static void pm_suspend_timer_fn(struct timer_list *t)
 {
-       struct device *dev = (struct device *)data;
+       struct device *dev = from_timer(dev, t, power.suspend_timer);
        unsigned long flags;
        unsigned long expires;
 
@@ -1499,8 +1499,7 @@ void pm_runtime_init(struct device *dev)
        INIT_WORK(&dev->power.work, pm_runtime_work);
 
        dev->power.timer_expires = 0;
-       setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
-                       (unsigned long)dev);
+       timer_setup(&dev->power.suspend_timer, pm_suspend_timer_fn, 0);
 
        init_waitqueue_head(&dev->power.wait_queue);
 }
index cdd6f256da597cb2abad069538d09723b2250d87..680ee1d36ac9a7f31b182b977f062aed1a590c8b 100644 (file)
@@ -54,7 +54,7 @@ static unsigned int saved_count;
 
 static DEFINE_SPINLOCK(events_lock);
 
-static void pm_wakeup_timer_fn(unsigned long data);
+static void pm_wakeup_timer_fn(struct timer_list *t);
 
 static LIST_HEAD(wakeup_sources);
 
@@ -176,7 +176,7 @@ void wakeup_source_add(struct wakeup_source *ws)
                return;
 
        spin_lock_init(&ws->lock);
-       setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
+       timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
        ws->active = false;
        ws->last_time = ktime_get();
 
@@ -481,8 +481,7 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws)
         * Use timer struct to check if the given source is initialized
         * by wakeup_source_add.
         */
-       return ws->timer.function != pm_wakeup_timer_fn ||
-                  ws->timer.data != (unsigned long)ws;
+       return ws->timer.function != (TIMER_FUNC_TYPE)pm_wakeup_timer_fn;
 }
 
 /*
@@ -724,9 +723,9 @@ EXPORT_SYMBOL_GPL(pm_relax);
  * in @data if it is currently active and its timer has not been canceled and
  * the expiration time of the timer is not in future.
  */
-static void pm_wakeup_timer_fn(unsigned long data)
+static void pm_wakeup_timer_fn(struct timer_list *t)
 {
-       struct wakeup_source *ws = (struct wakeup_source *)data;
+       struct wakeup_source *ws = from_timer(ws, t, timer);
        unsigned long flags;
 
        spin_lock_irqsave(&ws->lock, flags);
index 9f45cfeae775545f7dc85688f1f2a20a3de9c561..f124de3a0668d5f02f3b0015bdacd4c78177f8cc 100644 (file)
@@ -1304,7 +1304,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
         * becaue the HDA driver may require us to enable the audio power
         * domain during system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        ret = i915_driver_init_early(dev_priv, ent);
        if (ret < 0)
index 78b3172c8e6e298fa8f74c93db2850c4f96b95a8..f4f17552c9b804c3667c6d3a7c702ac30a4eaac0 100644 (file)
@@ -225,7 +225,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * MEI requires to resume from runtime suspend mode
         * in order to perform link reset flow upon system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        /*
         * ME maps runtime suspend/resume to D0i states,
index 0566f9bfa7de6c68c44d245e7e1deec84c345f71..e1b909123fb02d25539c8645cc51e4f4960035ff 100644 (file)
@@ -141,7 +141,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * MEI requires to resume from runtime suspend mode
         * in order to perform link reset flow upon system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        /*
         * TXE maps runtime suspend/resume to own power gating states,
index 9be563067c0cd2c149b7b8ff5fe04791ba85b5bb..07b8a9b385abcb43506e42625204b0734d26e3d0 100644 (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,13 +1070,17 @@ static int pci_pm_poweroff(struct device *dev)
                        return error;
        }
 
- Fixup:
-       pci_fixup_device(pci_fixup_suspend, pci_dev);
+       return 0;
+}
 
-       if (pcibios_pm_ops.poweroff)
-               return pcibios_pm_ops.poweroff(dev);
+static int pci_pm_poweroff_late(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
 
-       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)
@@ -1040,6 +1088,9 @@ 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,
index 6078dfc11b112a88aec1c58eb911de9f996b6644..374f5686e2bc13923a88c2b207b1b51ab651e847 100644 (file)
@@ -2166,8 +2166,7 @@ bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
 
        if (!pm_runtime_suspended(dev)
            || pci_target_state(pci_dev, wakeup) != pci_dev->current_state
-           || platform_pci_need_resume(pci_dev)
-           || (pci_dev->dev_flags & PCI_DEV_FLAGS_NEEDS_RESUME))
+           || platform_pci_need_resume(pci_dev))
                return false;
 
        /*
index 0ada2a948b44c29e1a47b941daa298f519860512..dc1ebfeeb5ecc10e248f57084f80c72d32c6c14a 100644 (file)
@@ -885,17 +885,27 @@ int acpi_dev_suspend_late(struct device *dev);
 int acpi_subsys_prepare(struct device *dev);
 void acpi_subsys_complete(struct device *dev);
 int acpi_subsys_suspend_late(struct device *dev);
+int acpi_subsys_suspend_noirq(struct device *dev);
+int acpi_subsys_resume_noirq(struct device *dev);
 int acpi_subsys_resume_early(struct device *dev);
 int acpi_subsys_suspend(struct device *dev);
 int acpi_subsys_freeze(struct device *dev);
+int acpi_subsys_freeze_late(struct device *dev);
+int acpi_subsys_freeze_noirq(struct device *dev);
+int acpi_subsys_thaw_noirq(struct device *dev);
 #else
 static inline int acpi_dev_resume_early(struct device *dev) { return 0; }
 static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
 static inline void acpi_subsys_complete(struct device *dev) {}
 static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; }
+static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; }
+static inline int acpi_subsys_resume_noirq(struct device *dev) { return 0; }
 static inline int acpi_subsys_resume_early(struct device *dev) { return 0; }
 static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
 static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
+static inline int acpi_subsys_freeze_late(struct device *dev) { return 0; }
+static inline int acpi_subsys_freeze_noirq(struct device *dev) { return 0; }
+static inline int acpi_subsys_thaw_noirq(struct device *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_ACPI
index 66fe271c2544d5cf861e1e5c58e23a0793ba1ed6..fb9451599aca948082a7a194556a7f5272f05115 100644 (file)
@@ -370,9 +370,6 @@ int subsys_virtual_register(struct bus_type *subsys,
  * @devnode:   Callback to provide the devtmpfs.
  * @class_release: Called to release this class.
  * @dev_release: Called to release the device.
- * @suspend:   Used to put the device to sleep mode, usually to a low power
- *             state.
- * @resume:    Used to bring the device from the sleep mode.
  * @shutdown_pre: Called at shut-down time before driver shutdown.
  * @ns_type:   Callbacks so sysfs can detemine namespaces.
  * @namespace: Namespace of the device belongs to this class.
@@ -400,8 +397,6 @@ struct class {
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
 
-       int (*suspend)(struct device *dev, pm_message_t state);
-       int (*resume)(struct device *dev);
        int (*shutdown_pre)(struct device *dev);
 
        const struct kobj_ns_type_operations *ns_type;
@@ -1075,6 +1070,16 @@ static inline void dev_pm_syscore_device(struct device *dev, bool val)
 #endif
 }
 
+static inline void dev_pm_set_driver_flags(struct device *dev, u32 flags)
+{
+       dev->power.driver_flags = flags;
+}
+
+static inline bool dev_pm_test_driver_flags(struct device *dev, u32 flags)
+{
+       return !!(dev->power.driver_flags & flags);
+}
+
 static inline void device_lock(struct device *dev)
 {
        mutex_lock(&dev->mutex);
index d16a7c037ec0bca6176aaf0212d73af45387c7e3..e920a2527797e0bbd4ff67d7903dae7a0cc8d64b 100644 (file)
@@ -206,13 +206,8 @@ enum pci_dev_flags {
        PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = (__force pci_dev_flags_t) (1 << 9),
        /* Do not use FLR even if device advertises PCI_AF_CAP */
        PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
-       /*
-        * Resume before calling the driver's system suspend hooks, disabling
-        * the direct_complete optimization.
-        */
-       PCI_DEV_FLAGS_NEEDS_RESUME = (__force pci_dev_flags_t) (1 << 11),
        /* Don't use Relaxed Ordering for TLPs directed at this device */
-       PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 12),
+       PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
 };
 
 enum pci_irq_reroute_variant {
index a0ceeccf284630933b6ca211e6860f510c9c3a5a..65d39115f06d8780399e469ed44fc1c90f074e69 100644 (file)
@@ -550,6 +550,33 @@ struct pm_subsys_data {
 #endif
 };
 
+/*
+ * Driver flags to control system suspend/resume behavior.
+ *
+ * These flags can be set by device drivers at the probe time.  They need not be
+ * cleared by the drivers as the driver core will take care of that.
+ *
+ * NEVER_SKIP: Do not skip system suspend/resume callbacks for the device.
+ * SMART_PREPARE: Check the return value of the driver's ->prepare callback.
+ * SMART_SUSPEND: No need to resume the device from runtime suspend.
+ *
+ * Setting SMART_PREPARE instructs bus types and PM domains which may want
+ * system suspend/resume callbacks to be skipped for the device to return 0 from
+ * their ->prepare callbacks if the driver's ->prepare callback returns 0 (in
+ * other words, the system suspend/resume callbacks can only be skipped for the
+ * device if its driver doesn't object against that).  This flag has no effect
+ * if NEVER_SKIP is set.
+ *
+ * Setting SMART_SUSPEND instructs bus types and PM domains which may want to
+ * runtime resume the device upfront during system suspend that doing so is not
+ * necessary from the driver's perspective.  It also may cause them to skip
+ * invocations of the ->suspend_late and ->suspend_noirq callbacks provided by
+ * the driver if they decide to leave the device in runtime suspend.
+ */
+#define DPM_FLAG_NEVER_SKIP    BIT(0)
+#define DPM_FLAG_SMART_PREPARE BIT(1)
+#define DPM_FLAG_SMART_SUSPEND BIT(2)
+
 struct dev_pm_info {
        pm_message_t            power_state;
        unsigned int            can_wakeup:1;
@@ -561,6 +588,7 @@ struct dev_pm_info {
        bool                    is_late_suspended:1;
        bool                    early_init:1;   /* Owned by the PM core */
        bool                    direct_complete:1;      /* Owned by the PM core */
+       u32                     driver_flags;
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
@@ -737,6 +765,8 @@ extern int pm_generic_poweroff_late(struct device *dev);
 extern int pm_generic_poweroff(struct device *dev);
 extern void pm_generic_complete(struct device *dev);
 
+extern bool dev_pm_smart_suspend_and_suspended(struct device *dev);
+
 #else /* !CONFIG_PM_SLEEP */
 
 #define device_pm_lock() do {} while (0)