PM / Runtime: Rework the "runtime idle" helper routine
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 3 Jun 2013 19:49:52 +0000 (21:49 +0200)
committerlintao <lintao@rock-chips.com>
Fri, 7 Mar 2014 04:52:24 +0000 (12:52 +0800)
The "runtime idle" helper routine, rpm_idle(), currently ignores
return values from .runtime_idle() callbacks executed by it.
However, it turns out that many subsystems use
pm_generic_runtime_idle() which checks the return value of the
driver's callback and executes pm_runtime_suspend() for the device
unless that value is not 0.  If that logic is moved to rpm_idle()
instead, pm_generic_runtime_idle() can be dropped and its users
will not need any .runtime_idle() callbacks any more.

Moreover, the PCI, SCSI, and SATA subsystems' .runtime_idle()
routines, pci_pm_runtime_idle(), scsi_runtime_idle(), and
ata_port_runtime_idle(), respectively, as well as a few drivers'
ones may be simplified if rpm_idle() calls rpm_suspend() after 0 has
been returned by the .runtime_idle() callback executed by it.

To reduce overall code bloat, make the changes described above.

Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Kevin Hilman <khilman@linaro.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
23 files changed:
Documentation/power/runtime_pm.txt
arch/arm/mach-omap2/omap_device.c
drivers/acpi/device_pm.c
drivers/amba/bus.c
drivers/ata/libata-core.c
drivers/base/platform.c
drivers/base/power/domain.c
drivers/base/power/generic_ops.c
drivers/base/power/runtime.c
drivers/dma/intel_mid_dma.c
drivers/gpio/gpio-langwell.c
drivers/i2c/i2c-core.c
drivers/mfd/ab8500-gpadc.c
drivers/mmc/core/bus.c
drivers/mmc/core/sdio_bus.c
drivers/pci/pci-driver.c
drivers/scsi/scsi_pm.c
drivers/sh/pm_runtime.c
drivers/spi/spi.c
drivers/tty/serial/mfd.c
drivers/usb/core/driver.c
drivers/usb/core/port.c
include/linux/pm_runtime.h

index 6c9f5d9aa115d04ee86c5297f5e3051bee31c0b9..6c470c71ba274818af86a96f76697e561d66112e 100644 (file)
@@ -660,11 +660,6 @@ Subsystems may wish to conserve code space by using the set of generic power
 management callbacks provided by the PM core, defined in
 driver/base/power/generic_ops.c:
 
-  int pm_generic_runtime_idle(struct device *dev);
-    - invoke the ->runtime_idle() callback provided by the driver of this
-      device, if defined, and call pm_runtime_suspend() for this device if the
-      return value is 0 or the callback is not defined
-
   int pm_generic_runtime_suspend(struct device *dev);
     - invoke the ->runtime_suspend() callback provided by the driver of this
       device and return its result, or return -EINVAL if not defined
index e6d230700b2bdf3d0702de3b4e9cfeef67d6801e..e37feb2f05a3355b4ebc52bad9246451ee859409 100644 (file)
@@ -591,11 +591,6 @@ static int _od_runtime_suspend(struct device *dev)
        return ret;
 }
 
-static int _od_runtime_idle(struct device *dev)
-{
-       return pm_generic_runtime_idle(dev);
-}
-
 static int _od_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -653,7 +648,7 @@ static int _od_resume_noirq(struct device *dev)
 struct dev_pm_domain omap_device_pm_domain = {
        .ops = {
                SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
-                                  _od_runtime_idle)
+                                  NULL)
                USE_PLATFORM_PM_SLEEP_OPS
                .suspend_noirq = _od_suspend_noirq,
                .resume_noirq = _od_resume_noirq,
index 553527c2532b789de12c864eb653cf020ffba9b0..4a02e3d889d2f99d701e7e24cf14931b05a9d481 100644 (file)
@@ -921,7 +921,6 @@ static struct dev_pm_domain acpi_general_pm_domain = {
 #ifdef CONFIG_PM_RUNTIME
                .runtime_suspend = acpi_subsys_runtime_suspend,
                .runtime_resume = acpi_subsys_runtime_resume,
-               .runtime_idle = pm_generic_runtime_idle,
 #endif
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
index 54ef6951d946094bf9b43430274f5ad957e5aec9..7e35fed9d5bf3517312ed5eab30afa144ff426ce 100644 (file)
@@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = {
        SET_RUNTIME_PM_OPS(
                amba_pm_runtime_suspend,
                amba_pm_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index 8cacd1693f030d74e7e838e1ccc7459cb26d85c5..315cbce5cca84c8b7bec4dbe88edc6cb3b8be2f1 100644 (file)
@@ -5440,7 +5440,7 @@ static int ata_port_runtime_idle(struct device *dev)
                                return -EBUSY;
        }
 
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 static int ata_port_runtime_suspend(struct device *dev)
index 9eda84246ffd5eda7d1d6947ef27a5ba05a75951..96a930387ebc749977b3f4ec6007f1478ba95fe3 100644 (file)
@@ -888,7 +888,6 @@ int platform_pm_restore(struct device *dev)
 static const struct dev_pm_ops platform_dev_pm_ops = {
        .runtime_suspend = pm_generic_runtime_suspend,
        .runtime_resume = pm_generic_runtime_resume,
-       .runtime_idle = pm_generic_runtime_idle,
        USE_PLATFORM_PM_SLEEP_OPS
 };
 
index 7072404c8b6da6ddb7ba6633cab5da087e49868e..bfb8955c406c5ef02d819d4d5fa02d709f0a6ec0 100644 (file)
@@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->max_off_time_changed = true;
        genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
        genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
-       genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
        genpd->domain.ops.prepare = pm_genpd_prepare;
        genpd->domain.ops.suspend = pm_genpd_suspend;
        genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
index bfd898b8988e37ca0dcc985fc28c57fdcde27fa0..5ee030a864f9266bb6c8ea18dd897e736fd2727c 100644 (file)
 #include <linux/export.h>
 
 #ifdef CONFIG_PM_RUNTIME
-/**
- * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
- * @dev: Device to handle.
- *
- * If PM operations are defined for the @dev's driver and they include
- * ->runtime_idle(), execute it and return its error code, if nonzero.
- * Otherwise, execute pm_runtime_suspend() for the device and return 0.
- */
-int pm_generic_runtime_idle(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm && pm->runtime_idle) {
-               int ret = pm->runtime_idle(dev);
-               if (ret)
-                       return ret;
-       }
-
-       pm_runtime_suspend(dev);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
-
 /**
  * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
  * @dev: Device to suspend.
index ef13ad08afb2cf845340bb28463ad3df63e5b04b..268a35097578d94f78f4baef4d9cc8b3fa1c31cd 100644 (file)
@@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
        /* Pending requests need to be canceled. */
        dev->power.request = RPM_REQ_NONE;
 
-       if (dev->power.no_callbacks) {
-               /* Assume ->runtime_idle() callback would have suspended. */
-               retval = rpm_suspend(dev, rpmflags);
+       if (dev->power.no_callbacks)
                goto out;
-       }
 
        /* Carry out an asynchronous or a synchronous idle notification. */
        if (rpmflags & RPM_ASYNC) {
@@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
                        dev->power.request_pending = true;
                        queue_work(pm_wq, &dev->power.work);
                }
-               goto out;
+               trace_rpm_return_int(dev, _THIS_IP_, 0);
+               return 0;
        }
 
        dev->power.idle_notification = true;
@@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
                callback = dev->driver->pm->runtime_idle;
 
        if (callback)
-               __rpm_callback(callback, dev);
+               retval = __rpm_callback(callback, dev);
 
        dev->power.idle_notification = false;
        wake_up_all(&dev->power.wait_queue);
 
  out:
        trace_rpm_return_int(dev, _THIS_IP_, retval);
-       return retval;
+       return retval ? retval : rpm_suspend(dev, rpmflags);
 }
 
 /**
index a0de82e21a7c30d00f122071783c9280583990f4..a975ebebea8aaf9b8950497eefdcaf3793d930d2 100644 (file)
@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
                        return -EAGAIN;
        }
 
-       return pm_schedule_suspend(dev, 0);
+       return 0;
 }
 
 /******************************************************************************
index 62ef10a641c4250b273263c78e51bd2534ed632a..89d0d2a3b1bb62289a6c9a862abc19f98ad30097 100644 (file)
@@ -305,11 +305,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
 
 static int lnw_gpio_runtime_idle(struct device *dev)
 {
-       int err = pm_schedule_suspend(dev, 500);
-
-       if (!err)
-               return 0;
-
+       pm_schedule_suspend(dev, 500);
        return -EBUSY;
 }
 
index de64b994cb9463e1d9c53b1ce3c455b331a525bf..8ab40ff62b998343920799fb0e56ed65bae156e1 100755 (executable)
@@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index 13f7866de46eb21a4cdf0363f0386d315f8171dd..3598b0ecf8c74c3c9a3377379bb20a4b9f70fa36 100644 (file)
@@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
        return ret;
 }
 
-static int ab8500_gpadc_runtime_idle(struct device *dev)
-{
-       pm_runtime_suspend(dev);
-       return 0;
-}
-
 static int ab8500_gpadc_suspend(struct device *dev)
 {
        struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
@@ -1039,7 +1033,7 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
        SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
                           ab8500_gpadc_runtime_resume,
-                          ab8500_gpadc_runtime_idle)
+                          NULL)
        SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
                                ab8500_gpadc_resume)
 
index d9e8c2b7f4c5b3e192eb9cbf2fa6e3936c2fcd41..2a5e7356ffa3fc7adaf046c6e1aff7654a5bc64f 100644 (file)
@@ -174,7 +174,7 @@ static int mmc_runtime_resume(struct device *dev)
 
 static int mmc_runtime_idle(struct device *dev)
 {
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 #endif /* !CONFIG_PM_RUNTIME */
index c012cf59b7d6acb564314137f79ed4e2842cd8a7..0da35ad4456a374e45c68b8b6398eace640b714a 100644 (file)
@@ -215,7 +215,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index 66aabde827277dd533b47b7ba9bfd5ddf5ff1888..6f9b44b541e47f25f2b80404a643c4ab06c50529 100644 (file)
@@ -1056,26 +1056,22 @@ static int pci_pm_runtime_idle(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 ret = 0;
 
        /*
         * If pci_dev->driver is not set (unbound), the device should
         * always remain in D0 regardless of the runtime PM status
         */
        if (!pci_dev->driver)
-               goto out;
+               return 0;
 
        if (!pm)
                return -ENOSYS;
 
-       if (pm->runtime_idle) {
-               int ret = pm->runtime_idle(dev);
-               if (ret)
-                       return ret;
-       }
+       if (pm->runtime_idle)
+               ret = pm->runtime_idle(dev);
 
-out:
-       pm_runtime_suspend(dev);
-       return 0;
+       return ret;
 }
 
 #else /* !CONFIG_PM_RUNTIME */
index 42539ee2cb111f0e10a6b152d9a0d60cbb2d895b..4c5aabe21755cb82450876666145f1f2add7ad1f 100644 (file)
@@ -229,8 +229,6 @@ static int scsi_runtime_resume(struct device *dev)
 
 static int scsi_runtime_idle(struct device *dev)
 {
-       int err;
-
        dev_dbg(dev, "scsi_runtime_idle\n");
 
        /* Insert hooks here for targets, hosts, and transport classes */
@@ -240,14 +238,11 @@ static int scsi_runtime_idle(struct device *dev)
 
                if (sdev->request_queue->dev) {
                        pm_runtime_mark_last_busy(dev);
-                       err = pm_runtime_autosuspend(dev);
-               } else {
-                       err = pm_runtime_suspend(dev);
+                       pm_runtime_autosuspend(dev);
+                       return -EBUSY;
                }
-       } else {
-               err = pm_runtime_suspend(dev);
        }
-       return err;
+       return 0;
 }
 
 int scsi_autopm_get_device(struct scsi_device *sdev)
index afe9282629b900262da4e8ea178f3f6816b771bd..8afa5a4589f2dd03771acaac8be585447e8033c0 100644 (file)
@@ -25,7 +25,7 @@
 static int default_platform_runtime_idle(struct device *dev)
 {
        /* suspend synchronously to disable clocks immediately */
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 static struct dev_pm_domain default_pm_domain = {
index 32b7bb111eb6b53d9e96808f7bd5fd0982cffd9d..095cfaded1c0dd084111af40d0e0a2c70ebe32d7 100644 (file)
@@ -223,7 +223,7 @@ static const struct dev_pm_ops spi_pm = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index 5f4765a7a5c54d6d3b845c9e9f7df402978afbff..5dfcf3bae23aa62ddb3d90dc8b72f06eac81e99c 100644 (file)
@@ -1248,13 +1248,8 @@ static int serial_hsu_resume(struct pci_dev *pdev)
 #ifdef CONFIG_PM_RUNTIME
 static int serial_hsu_runtime_idle(struct device *dev)
 {
-       int err;
-
-       err = pm_schedule_suspend(dev, 500);
-       if (err)
-               return -EBUSY;
-
-       return 0;
+       pm_schedule_suspend(dev, 500);
+       return -EBUSY;
 }
 
 static int serial_hsu_runtime_suspend(struct device *dev)
index 6eab440e1542e450f7733fb4cbbf35b1b1044313..7609ac4aed1cdc29493b3924c76b254cfdd09cae 100644 (file)
@@ -1765,7 +1765,8 @@ int usb_runtime_idle(struct device *dev)
         */
        if (autosuspend_check(udev) == 0)
                pm_runtime_autosuspend(dev);
-       return 0;
+       /* Tell the core not to suspend it, though. */
+       return -EBUSY;
 }
 
 int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
index ef07b3596d06c7cf434f4d0e6ecb9227e59852d1..84c052f1aaec67b2bc2b53215a4e5feebfbe9c79 100644 (file)
@@ -138,7 +138,6 @@ static const struct dev_pm_ops usb_port_pm_ops = {
 #ifdef CONFIG_PM_RUNTIME
        .runtime_suspend =      usb_port_runtime_suspend,
        .runtime_resume =       usb_port_runtime_resume,
-       .runtime_idle =         pm_generic_runtime_idle,
 #endif
 };
 
index 7d7e09efff9b9eea0f29ce8fc37cbcdf0268e6f8..6fa7cea25da9afde1ffac4668c30f85d711a0fc0 100644 (file)
@@ -37,7 +37,6 @@ extern void pm_runtime_enable(struct device *dev);
 extern void __pm_runtime_disable(struct device *dev, bool check_resume);
 extern void pm_runtime_allow(struct device *dev);
 extern void pm_runtime_forbid(struct device *dev);
-extern int pm_generic_runtime_idle(struct device *dev);
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
 extern void pm_runtime_no_callbacks(struct device *dev);
@@ -143,7 +142,6 @@ static inline bool pm_runtime_active(struct device *dev) { return true; }
 static inline bool pm_runtime_status_suspended(struct device *dev) { return false; }
 static inline bool pm_runtime_enabled(struct device *dev) { return false; }
 
-static inline int pm_generic_runtime_idle(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
 static inline void pm_runtime_no_callbacks(struct device *dev) {}