Commit 45f0a85c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

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: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: default avatarKevin Hilman <khilman@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: default avatarKevin Hilman <khilman@linaro.org>
Reviewed-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
parent cd38ca85
...@@ -660,11 +660,6 @@ Subsystems may wish to conserve code space by using the set of generic power ...@@ -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
......
...@@ -591,11 +591,6 @@ static int _od_runtime_suspend(struct device *dev) ...@@ -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) ...@@ -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,
......
...@@ -886,7 +886,6 @@ static struct dev_pm_domain acpi_general_pm_domain = { ...@@ -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,
......
...@@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = { ...@@ -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
) )
}; };
......
...@@ -5430,7 +5430,7 @@ static int ata_port_runtime_idle(struct device *dev) ...@@ -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)
......
...@@ -888,7 +888,6 @@ int platform_pm_restore(struct device *dev) ...@@ -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
}; };
......
...@@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, ...@@ -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;
......
...@@ -11,29 +11,6 @@ ...@@ -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.
......
...@@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags) ...@@ -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) ...@@ -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) ...@@ -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);
} }
/** /**
......
...@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev) ...@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
return -EAGAIN; return -EAGAIN;
} }
return pm_schedule_suspend(dev, 0); return 0;
} }
/****************************************************************************** /******************************************************************************
......
...@@ -305,11 +305,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = { ...@@ -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;
} }
......
...@@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = { ...@@ -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
) )
}; };
......
...@@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) ...@@ -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) ...@@ -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)
......
...@@ -164,7 +164,7 @@ static int mmc_runtime_resume(struct device *dev) ...@@ -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 */
......
...@@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { ...@@ -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
) )
}; };
......
...@@ -1050,26 +1050,22 @@ static int pci_pm_runtime_idle(struct device *dev) ...@@ -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 */
......
...@@ -229,8 +229,6 @@ static int scsi_runtime_resume(struct device *dev) ...@@ -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) ...@@ -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)
......
...@@ -25,7 +25,7 @@ ...@@ -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 = {
......
...@@ -223,7 +223,7 @@ static const struct dev_pm_ops spi_pm = { ...@@ -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
) )
}; };
......
...@@ -1248,13 +1248,8 @@ static int serial_hsu_resume(struct pci_dev *pdev) ...@@ -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)
......
...@@ -1765,7 +1765,8 @@ int usb_runtime_idle(struct device *dev) ...@@ -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)
......
...@@ -141,7 +141,6 @@ static const struct dev_pm_ops usb_port_pm_ops = { ...@@ -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
}; };
......
...@@ -37,7 +37,6 @@ extern void pm_runtime_enable(struct device *dev); ...@@ -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; } ...@@ -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) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment