Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / Runtime: Rework the "runtime idle" helper routine

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>

+28 -92
-5
Documentation/power/runtime_pm.txt
··· 660 660 management callbacks provided by the PM core, defined in 661 661 driver/base/power/generic_ops.c: 662 662 663 - int pm_generic_runtime_idle(struct device *dev); 664 - - invoke the ->runtime_idle() callback provided by the driver of this 665 - device, if defined, and call pm_runtime_suspend() for this device if the 666 - return value is 0 or the callback is not defined 667 - 668 663 int pm_generic_runtime_suspend(struct device *dev); 669 664 - invoke the ->runtime_suspend() callback provided by the driver of this 670 665 device and return its result, or return -EINVAL if not defined
+1 -6
arch/arm/mach-omap2/omap_device.c
··· 591 591 return ret; 592 592 } 593 593 594 - static int _od_runtime_idle(struct device *dev) 595 - { 596 - return pm_generic_runtime_idle(dev); 597 - } 598 - 599 594 static int _od_runtime_resume(struct device *dev) 600 595 { 601 596 struct platform_device *pdev = to_platform_device(dev); ··· 648 653 struct dev_pm_domain omap_device_pm_domain = { 649 654 .ops = { 650 655 SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, 651 - _od_runtime_idle) 656 + NULL) 652 657 USE_PLATFORM_PM_SLEEP_OPS 653 658 .suspend_noirq = _od_suspend_noirq, 654 659 .resume_noirq = _od_resume_noirq,
-1
drivers/acpi/device_pm.c
··· 886 886 #ifdef CONFIG_PM_RUNTIME 887 887 .runtime_suspend = acpi_subsys_runtime_suspend, 888 888 .runtime_resume = acpi_subsys_runtime_resume, 889 - .runtime_idle = pm_generic_runtime_idle, 890 889 #endif 891 890 #ifdef CONFIG_PM_SLEEP 892 891 .prepare = acpi_subsys_prepare,
+1 -1
drivers/amba/bus.c
··· 284 284 SET_RUNTIME_PM_OPS( 285 285 amba_pm_runtime_suspend, 286 286 amba_pm_runtime_resume, 287 - pm_generic_runtime_idle 287 + NULL 288 288 ) 289 289 }; 290 290
+1 -1
drivers/ata/libata-core.c
··· 5430 5430 return -EBUSY; 5431 5431 } 5432 5432 5433 - return pm_runtime_suspend(dev); 5433 + return 0; 5434 5434 } 5435 5435 5436 5436 static int ata_port_runtime_suspend(struct device *dev)
-1
drivers/base/platform.c
··· 888 888 static const struct dev_pm_ops platform_dev_pm_ops = { 889 889 .runtime_suspend = pm_generic_runtime_suspend, 890 890 .runtime_resume = pm_generic_runtime_resume, 891 - .runtime_idle = pm_generic_runtime_idle, 892 891 USE_PLATFORM_PM_SLEEP_OPS 893 892 }; 894 893
-1
drivers/base/power/domain.c
··· 2143 2143 genpd->max_off_time_changed = true; 2144 2144 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; 2145 2145 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; 2146 - genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; 2147 2146 genpd->domain.ops.prepare = pm_genpd_prepare; 2148 2147 genpd->domain.ops.suspend = pm_genpd_suspend; 2149 2148 genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
-23
drivers/base/power/generic_ops.c
··· 12 12 13 13 #ifdef CONFIG_PM_RUNTIME 14 14 /** 15 - * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. 16 - * @dev: Device to handle. 17 - * 18 - * If PM operations are defined for the @dev's driver and they include 19 - * ->runtime_idle(), execute it and return its error code, if nonzero. 20 - * Otherwise, execute pm_runtime_suspend() for the device and return 0. 21 - */ 22 - int pm_generic_runtime_idle(struct device *dev) 23 - { 24 - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 25 - 26 - if (pm && pm->runtime_idle) { 27 - int ret = pm->runtime_idle(dev); 28 - if (ret) 29 - return ret; 30 - } 31 - 32 - pm_runtime_suspend(dev); 33 - return 0; 34 - } 35 - EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); 36 - 37 - /** 38 15 * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. 39 16 * @dev: Device to suspend. 40 17 *
+5 -7
drivers/base/power/runtime.c
··· 293 293 /* Pending requests need to be canceled. */ 294 294 dev->power.request = RPM_REQ_NONE; 295 295 296 - if (dev->power.no_callbacks) { 297 - /* Assume ->runtime_idle() callback would have suspended. */ 298 - retval = rpm_suspend(dev, rpmflags); 296 + if (dev->power.no_callbacks) 299 297 goto out; 300 - } 301 298 302 299 /* Carry out an asynchronous or a synchronous idle notification. */ 303 300 if (rpmflags & RPM_ASYNC) { ··· 303 306 dev->power.request_pending = true; 304 307 queue_work(pm_wq, &dev->power.work); 305 308 } 306 - goto out; 309 + trace_rpm_return_int(dev, _THIS_IP_, 0); 310 + return 0; 307 311 } 308 312 309 313 dev->power.idle_notification = true; ··· 324 326 callback = dev->driver->pm->runtime_idle; 325 327 326 328 if (callback) 327 - __rpm_callback(callback, dev); 329 + retval = __rpm_callback(callback, dev); 328 330 329 331 dev->power.idle_notification = false; 330 332 wake_up_all(&dev->power.wait_queue); 331 333 332 334 out: 333 335 trace_rpm_return_int(dev, _THIS_IP_, retval); 334 - return retval; 336 + return retval ? retval : rpm_suspend(dev, rpmflags); 335 337 } 336 338 337 339 /**
+1 -1
drivers/dma/intel_mid_dma.c
··· 1405 1405 return -EAGAIN; 1406 1406 } 1407 1407 1408 - return pm_schedule_suspend(dev, 0); 1408 + return 0; 1409 1409 } 1410 1410 1411 1411 /******************************************************************************
+1 -5
drivers/gpio/gpio-langwell.c
··· 305 305 306 306 static int lnw_gpio_runtime_idle(struct device *dev) 307 307 { 308 - int err = pm_schedule_suspend(dev, 500); 309 - 310 - if (!err) 311 - return 0; 312 - 308 + pm_schedule_suspend(dev, 500); 313 309 return -EBUSY; 314 310 } 315 311
+1 -1
drivers/i2c/i2c-core.c
··· 435 435 SET_RUNTIME_PM_OPS( 436 436 pm_generic_runtime_suspend, 437 437 pm_generic_runtime_resume, 438 - pm_generic_runtime_idle 438 + NULL 439 439 ) 440 440 }; 441 441
+1 -7
drivers/mfd/ab8500-gpadc.c
··· 886 886 return ret; 887 887 } 888 888 889 - static int ab8500_gpadc_runtime_idle(struct device *dev) 890 - { 891 - pm_runtime_suspend(dev); 892 - return 0; 893 - } 894 - 895 889 static int ab8500_gpadc_suspend(struct device *dev) 896 890 { 897 891 struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); ··· 1033 1039 static const struct dev_pm_ops ab8500_gpadc_pm_ops = { 1034 1040 SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, 1035 1041 ab8500_gpadc_runtime_resume, 1036 - ab8500_gpadc_runtime_idle) 1042 + NULL) 1037 1043 SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend, 1038 1044 ab8500_gpadc_resume) 1039 1045
+1 -1
drivers/mmc/core/bus.c
··· 164 164 165 165 static int mmc_runtime_idle(struct device *dev) 166 166 { 167 - return pm_runtime_suspend(dev); 167 + return 0; 168 168 } 169 169 170 170 #endif /* !CONFIG_PM_RUNTIME */
+1 -1
drivers/mmc/core/sdio_bus.c
··· 211 211 SET_RUNTIME_PM_OPS( 212 212 pm_generic_runtime_suspend, 213 213 pm_generic_runtime_resume, 214 - pm_generic_runtime_idle 214 + NULL 215 215 ) 216 216 }; 217 217
+5 -9
drivers/pci/pci-driver.c
··· 1050 1050 { 1051 1051 struct pci_dev *pci_dev = to_pci_dev(dev); 1052 1052 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 1053 + int ret = 0; 1053 1054 1054 1055 /* 1055 1056 * If pci_dev->driver is not set (unbound), the device should 1056 1057 * always remain in D0 regardless of the runtime PM status 1057 1058 */ 1058 1059 if (!pci_dev->driver) 1059 - goto out; 1060 + return 0; 1060 1061 1061 1062 if (!pm) 1062 1063 return -ENOSYS; 1063 1064 1064 - if (pm->runtime_idle) { 1065 - int ret = pm->runtime_idle(dev); 1066 - if (ret) 1067 - return ret; 1068 - } 1065 + if (pm->runtime_idle) 1066 + ret = pm->runtime_idle(dev); 1069 1067 1070 - out: 1071 - pm_runtime_suspend(dev); 1072 - return 0; 1068 + return ret; 1073 1069 } 1074 1070 1075 1071 #else /* !CONFIG_PM_RUNTIME */
+3 -8
drivers/scsi/scsi_pm.c
··· 229 229 230 230 static int scsi_runtime_idle(struct device *dev) 231 231 { 232 - int err; 233 - 234 232 dev_dbg(dev, "scsi_runtime_idle\n"); 235 233 236 234 /* Insert hooks here for targets, hosts, and transport classes */ ··· 238 240 239 241 if (sdev->request_queue->dev) { 240 242 pm_runtime_mark_last_busy(dev); 241 - err = pm_runtime_autosuspend(dev); 242 - } else { 243 - err = pm_runtime_suspend(dev); 243 + pm_runtime_autosuspend(dev); 244 + return -EBUSY; 244 245 } 245 - } else { 246 - err = pm_runtime_suspend(dev); 247 246 } 248 - return err; 247 + return 0; 249 248 } 250 249 251 250 int scsi_autopm_get_device(struct scsi_device *sdev)
+1 -1
drivers/sh/pm_runtime.c
··· 25 25 static int default_platform_runtime_idle(struct device *dev) 26 26 { 27 27 /* suspend synchronously to disable clocks immediately */ 28 - return pm_runtime_suspend(dev); 28 + return 0; 29 29 } 30 30 31 31 static struct dev_pm_domain default_pm_domain = {
+1 -1
drivers/spi/spi.c
··· 223 223 SET_RUNTIME_PM_OPS( 224 224 pm_generic_runtime_suspend, 225 225 pm_generic_runtime_resume, 226 - pm_generic_runtime_idle 226 + NULL 227 227 ) 228 228 }; 229 229
+2 -7
drivers/tty/serial/mfd.c
··· 1248 1248 #ifdef CONFIG_PM_RUNTIME 1249 1249 static int serial_hsu_runtime_idle(struct device *dev) 1250 1250 { 1251 - int err; 1252 - 1253 - err = pm_schedule_suspend(dev, 500); 1254 - if (err) 1255 - return -EBUSY; 1256 - 1257 - return 0; 1251 + pm_schedule_suspend(dev, 500); 1252 + return -EBUSY; 1258 1253 } 1259 1254 1260 1255 static int serial_hsu_runtime_suspend(struct device *dev)
+2 -1
drivers/usb/core/driver.c
··· 1765 1765 */ 1766 1766 if (autosuspend_check(udev) == 0) 1767 1767 pm_runtime_autosuspend(dev); 1768 - return 0; 1768 + /* Tell the core not to suspend it, though. */ 1769 + return -EBUSY; 1769 1770 } 1770 1771 1771 1772 int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
-1
drivers/usb/core/port.c
··· 141 141 #ifdef CONFIG_PM_RUNTIME 142 142 .runtime_suspend = usb_port_runtime_suspend, 143 143 .runtime_resume = usb_port_runtime_resume, 144 - .runtime_idle = pm_generic_runtime_idle, 145 144 #endif 146 145 }; 147 146
-2
include/linux/pm_runtime.h
··· 37 37 extern void __pm_runtime_disable(struct device *dev, bool check_resume); 38 38 extern void pm_runtime_allow(struct device *dev); 39 39 extern void pm_runtime_forbid(struct device *dev); 40 - extern int pm_generic_runtime_idle(struct device *dev); 41 40 extern int pm_generic_runtime_suspend(struct device *dev); 42 41 extern int pm_generic_runtime_resume(struct device *dev); 43 42 extern void pm_runtime_no_callbacks(struct device *dev); ··· 142 143 static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } 143 144 static inline bool pm_runtime_enabled(struct device *dev) { return false; } 144 145 145 - static inline int pm_generic_runtime_idle(struct device *dev) { return 0; } 146 146 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } 147 147 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } 148 148 static inline void pm_runtime_no_callbacks(struct device *dev) {}