forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									cd38ca854d
								
							
						
					
					
						commit
						45f0a85c82
					
				
					 23 changed files with 28 additions and 92 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -886,7 +886,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, | ||||
|  |  | |||
|  | @ -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 | ||||
| 	) | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5430,7 +5430,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) | ||||
|  |  | |||
|  | @ -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 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -11,29 +11,6 @@ | |||
| #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. | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev) | |||
| 			return -EAGAIN; | ||||
| 	} | ||||
| 
 | ||||
| 	return pm_schedule_suspend(dev, 0); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
| 	) | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
| 
 | ||||
|  |  | |||
|  | @ -164,7 +164,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 */ | ||||
|  |  | |||
|  | @ -211,7 +211,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 | ||||
| 	) | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1050,26 +1050,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 */ | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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 | ||||
| 	) | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
| 	pm_schedule_suspend(dev, 500); | ||||
| 	return -EBUSY; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int serial_hsu_runtime_suspend(struct device *dev) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -141,7 +141,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 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) {} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Rafael J. Wysocki
						Rafael J. Wysocki