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:
Rafael J. Wysocki 2013-06-03 21:49:52 +02:00
parent cd38ca854d
commit 45f0a85c82
23 changed files with 28 additions and 92 deletions

View 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 management callbacks provided by the PM core, defined in
driver/base/power/generic_ops.c: 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); int pm_generic_runtime_suspend(struct device *dev);
- invoke the ->runtime_suspend() callback provided by the driver of this - invoke the ->runtime_suspend() callback provided by the driver of this
device and return its result, or return -EINVAL if not defined device and return its result, or return -EINVAL if not defined

View File

@ -591,11 +591,6 @@ static int _od_runtime_suspend(struct device *dev)
return ret; return ret;
} }
static int _od_runtime_idle(struct device *dev)
{
return pm_generic_runtime_idle(dev);
}
static int _od_runtime_resume(struct device *dev) static int _od_runtime_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_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 = { struct dev_pm_domain omap_device_pm_domain = {
.ops = { .ops = {
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
_od_runtime_idle) NULL)
USE_PLATFORM_PM_SLEEP_OPS USE_PLATFORM_PM_SLEEP_OPS
.suspend_noirq = _od_suspend_noirq, .suspend_noirq = _od_suspend_noirq,
.resume_noirq = _od_resume_noirq, .resume_noirq = _od_resume_noirq,

View File

@ -886,7 +886,6 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_subsys_runtime_suspend, .runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume, .runtime_resume = acpi_subsys_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
#endif #endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare, .prepare = acpi_subsys_prepare,

View File

@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = {
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
amba_pm_runtime_suspend, amba_pm_runtime_suspend,
amba_pm_runtime_resume, amba_pm_runtime_resume,
pm_generic_runtime_idle NULL
) )
}; };

View File

@ -5430,7 +5430,7 @@ static int ata_port_runtime_idle(struct device *dev)
return -EBUSY; return -EBUSY;
} }
return pm_runtime_suspend(dev); return 0;
} }
static int ata_port_runtime_suspend(struct device *dev) static int ata_port_runtime_suspend(struct device *dev)

View File

@ -888,7 +888,6 @@ int platform_pm_restore(struct device *dev)
static const struct dev_pm_ops platform_dev_pm_ops = { static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend, .runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume, .runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS USE_PLATFORM_PM_SLEEP_OPS
}; };

View File

@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->max_off_time_changed = true; genpd->max_off_time_changed = true;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; 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.prepare = pm_genpd_prepare;
genpd->domain.ops.suspend = pm_genpd_suspend; genpd->domain.ops.suspend = pm_genpd_suspend;
genpd->domain.ops.suspend_late = pm_genpd_suspend_late; genpd->domain.ops.suspend_late = pm_genpd_suspend_late;

View File

@ -11,29 +11,6 @@
#include <linux/export.h> #include <linux/export.h>
#ifdef CONFIG_PM_RUNTIME #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. * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
* @dev: Device to suspend. * @dev: Device to suspend.

View File

@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
/* Pending requests need to be canceled. */ /* Pending requests need to be canceled. */
dev->power.request = RPM_REQ_NONE; dev->power.request = RPM_REQ_NONE;
if (dev->power.no_callbacks) { if (dev->power.no_callbacks)
/* Assume ->runtime_idle() callback would have suspended. */
retval = rpm_suspend(dev, rpmflags);
goto out; goto out;
}
/* Carry out an asynchronous or a synchronous idle notification. */ /* Carry out an asynchronous or a synchronous idle notification. */
if (rpmflags & RPM_ASYNC) { if (rpmflags & RPM_ASYNC) {
@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.request_pending = true; dev->power.request_pending = true;
queue_work(pm_wq, &dev->power.work); queue_work(pm_wq, &dev->power.work);
} }
goto out; trace_rpm_return_int(dev, _THIS_IP_, 0);
return 0;
} }
dev->power.idle_notification = true; dev->power.idle_notification = true;
@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
callback = dev->driver->pm->runtime_idle; callback = dev->driver->pm->runtime_idle;
if (callback) if (callback)
__rpm_callback(callback, dev); retval = __rpm_callback(callback, dev);
dev->power.idle_notification = false; dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue); wake_up_all(&dev->power.wait_queue);
out: out:
trace_rpm_return_int(dev, _THIS_IP_, retval); trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval; return retval ? retval : rpm_suspend(dev, rpmflags);
} }
/** /**

View File

@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
return -EAGAIN; return -EAGAIN;
} }
return pm_schedule_suspend(dev, 0); return 0;
} }
/****************************************************************************** /******************************************************************************

View File

@ -305,11 +305,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
static int lnw_gpio_runtime_idle(struct device *dev) static int lnw_gpio_runtime_idle(struct device *dev)
{ {
int err = pm_schedule_suspend(dev, 500); pm_schedule_suspend(dev, 500);
if (!err)
return 0;
return -EBUSY; return -EBUSY;
} }

View File

@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = {
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,
pm_generic_runtime_idle NULL
) )
}; };

View File

@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
return ret; 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) static int ab8500_gpadc_suspend(struct device *dev)
{ {
struct ab8500_gpadc *gpadc = dev_get_drvdata(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 = { static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
ab8500_gpadc_runtime_resume, ab8500_gpadc_runtime_resume,
ab8500_gpadc_runtime_idle) NULL)
SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend, SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
ab8500_gpadc_resume) ab8500_gpadc_resume)

View File

@ -164,7 +164,7 @@ static int mmc_runtime_resume(struct device *dev)
static int mmc_runtime_idle(struct device *dev) static int mmc_runtime_idle(struct device *dev)
{ {
return pm_runtime_suspend(dev); return 0;
} }
#endif /* !CONFIG_PM_RUNTIME */ #endif /* !CONFIG_PM_RUNTIME */

View File

@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,
pm_generic_runtime_idle NULL
) )
}; };

View File

@ -1050,26 +1050,22 @@ static int pci_pm_runtime_idle(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 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 * If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status * always remain in D0 regardless of the runtime PM status
*/ */
if (!pci_dev->driver) if (!pci_dev->driver)
goto out; return 0;
if (!pm) if (!pm)
return -ENOSYS; return -ENOSYS;
if (pm->runtime_idle) { if (pm->runtime_idle)
int ret = pm->runtime_idle(dev); ret = pm->runtime_idle(dev);
if (ret)
return ret;
}
out: return ret;
pm_runtime_suspend(dev);
return 0;
} }
#else /* !CONFIG_PM_RUNTIME */ #else /* !CONFIG_PM_RUNTIME */

View File

@ -229,8 +229,6 @@ static int scsi_runtime_resume(struct device *dev)
static int scsi_runtime_idle(struct device *dev) static int scsi_runtime_idle(struct device *dev)
{ {
int err;
dev_dbg(dev, "scsi_runtime_idle\n"); dev_dbg(dev, "scsi_runtime_idle\n");
/* Insert hooks here for targets, hosts, and transport classes */ /* 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) { if (sdev->request_queue->dev) {
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
err = pm_runtime_autosuspend(dev); pm_runtime_autosuspend(dev);
} else { return -EBUSY;
err = pm_runtime_suspend(dev);
} }
} else {
err = pm_runtime_suspend(dev);
} }
return err; return 0;
} }
int scsi_autopm_get_device(struct scsi_device *sdev) int scsi_autopm_get_device(struct scsi_device *sdev)

View File

@ -25,7 +25,7 @@
static int default_platform_runtime_idle(struct device *dev) static int default_platform_runtime_idle(struct device *dev)
{ {
/* suspend synchronously to disable clocks immediately */ /* suspend synchronously to disable clocks immediately */
return pm_runtime_suspend(dev); return 0;
} }
static struct dev_pm_domain default_pm_domain = { static struct dev_pm_domain default_pm_domain = {

View File

@ -223,7 +223,7 @@ static const struct dev_pm_ops spi_pm = {
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,
pm_generic_runtime_idle NULL
) )
}; };

View File

@ -1248,13 +1248,8 @@ static int serial_hsu_resume(struct pci_dev *pdev)
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
static int serial_hsu_runtime_idle(struct device *dev) static int serial_hsu_runtime_idle(struct device *dev)
{ {
int err; pm_schedule_suspend(dev, 500);
return -EBUSY;
err = pm_schedule_suspend(dev, 500);
if (err)
return -EBUSY;
return 0;
} }
static int serial_hsu_runtime_suspend(struct device *dev) static int serial_hsu_runtime_suspend(struct device *dev)

View File

@ -1765,7 +1765,8 @@ int usb_runtime_idle(struct device *dev)
*/ */
if (autosuspend_check(udev) == 0) if (autosuspend_check(udev) == 0)
pm_runtime_autosuspend(dev); 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) int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)

View File

@ -141,7 +141,6 @@ static const struct dev_pm_ops usb_port_pm_ops = {
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_port_runtime_suspend, .runtime_suspend = usb_port_runtime_suspend,
.runtime_resume = usb_port_runtime_resume, .runtime_resume = usb_port_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
#endif #endif
}; };

View 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_disable(struct device *dev, bool check_resume);
extern void pm_runtime_allow(struct device *dev); extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(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_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev); extern int pm_generic_runtime_resume(struct device *dev);
extern void pm_runtime_no_callbacks(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_status_suspended(struct device *dev) { return false; }
static inline bool pm_runtime_enabled(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_suspend(struct device *dev) { return 0; }
static inline int pm_generic_runtime_resume(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) {} static inline void pm_runtime_no_callbacks(struct device *dev) {}