| From a6fd82b4d0598a3e72e5803f44de38ddfe6a0151 Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| Date: Sun, 29 Jan 2012 20:39:02 +0100 |
| Subject: PM / Domains: Run late/early device suspend callbacks at the right |
| time |
| |
| After the introduction of the late/early phases of device |
| suspend/resume during system-wide power transitions it is possible |
| to make the generic PM domains code execute its default late/early |
| device suspend/resume callbacks during those phases instead of the |
| corresponding _noirq phases. The _noirq device suspend/resume |
| phases were only used for executing those callbacks, because this |
| was the only way it could be done, but now we can do better. |
| |
| Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> |
| (cherry picked from commit 0496c8ae366724a0a2136cec09a2e277e782c126) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| drivers/base/power/domain.c | 157 ++++++++++++++++++++++++++++++------------- |
| 1 file changed, 111 insertions(+), 46 deletions(-) |
| |
| diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c |
| index 939109b..d2c0323 100644 |
| --- a/drivers/base/power/domain.c |
| +++ b/drivers/base/power/domain.c |
| @@ -820,17 +820,16 @@ static int pm_genpd_suspend(struct device *dev) |
| } |
| |
| /** |
| - * pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain. |
| + * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain. |
| * @dev: Device to suspend. |
| * |
| * Carry out a late suspend of a device under the assumption that its |
| * pm_domain field points to the domain member of an object of type |
| * struct generic_pm_domain representing a PM domain consisting of I/O devices. |
| */ |
| -static int pm_genpd_suspend_noirq(struct device *dev) |
| +static int pm_genpd_suspend_late(struct device *dev) |
| { |
| struct generic_pm_domain *genpd; |
| - int ret; |
| |
| dev_dbg(dev, "%s()\n", __func__); |
| |
| @@ -838,14 +837,28 @@ static int pm_genpd_suspend_noirq(struct device *dev) |
| if (IS_ERR(genpd)) |
| return -EINVAL; |
| |
| - if (genpd->suspend_power_off) |
| - return 0; |
| + return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); |
| +} |
| |
| - ret = genpd_suspend_late(genpd, dev); |
| - if (ret) |
| - return ret; |
| +/** |
| + * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain. |
| + * @dev: Device to suspend. |
| + * |
| + * Stop the device and remove power from the domain if all devices in it have |
| + * been stopped. |
| + */ |
| +static int pm_genpd_suspend_noirq(struct device *dev) |
| +{ |
| + struct generic_pm_domain *genpd; |
| + |
| + dev_dbg(dev, "%s()\n", __func__); |
| + |
| + genpd = dev_to_genpd(dev); |
| + if (IS_ERR(genpd)) |
| + return -EINVAL; |
| |
| - if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) |
| + if (genpd->suspend_power_off |
| + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
| return 0; |
| |
| genpd_stop_dev(genpd, dev); |
| @@ -862,13 +875,10 @@ static int pm_genpd_suspend_noirq(struct device *dev) |
| } |
| |
| /** |
| - * pm_genpd_resume_noirq - Early resume of a device from an I/O power domain. |
| + * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain. |
| * @dev: Device to resume. |
| * |
| - * Carry out an early resume of a device under the assumption that its |
| - * pm_domain field points to the domain member of an object of type |
| - * struct generic_pm_domain representing a power domain consisting of I/O |
| - * devices. |
| + * Restore power to the device's PM domain, if necessary, and start the device. |
| */ |
| static int pm_genpd_resume_noirq(struct device *dev) |
| { |
| @@ -890,13 +900,34 @@ static int pm_genpd_resume_noirq(struct device *dev) |
| */ |
| pm_genpd_poweron(genpd); |
| genpd->suspended_count--; |
| - genpd_start_dev(genpd, dev); |
| |
| - return genpd_resume_early(genpd, dev); |
| + return genpd_start_dev(genpd, dev); |
| } |
| |
| /** |
| - * pm_genpd_resume - Resume a device belonging to an I/O power domain. |
| + * pm_genpd_resume_early - Early resume of a device in an I/O PM domain. |
| + * @dev: Device to resume. |
| + * |
| + * Carry out an early resume of a device under the assumption that its |
| + * pm_domain field points to the domain member of an object of type |
| + * struct generic_pm_domain representing a power domain consisting of I/O |
| + * devices. |
| + */ |
| +static int pm_genpd_resume_early(struct device *dev) |
| +{ |
| + struct generic_pm_domain *genpd; |
| + |
| + dev_dbg(dev, "%s()\n", __func__); |
| + |
| + genpd = dev_to_genpd(dev); |
| + if (IS_ERR(genpd)) |
| + return -EINVAL; |
| + |
| + return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); |
| +} |
| + |
| +/** |
| + * pm_genpd_resume - Resume of device in an I/O PM domain. |
| * @dev: Device to resume. |
| * |
| * Resume a device under the assumption that its pm_domain field points to the |
| @@ -917,7 +948,7 @@ static int pm_genpd_resume(struct device *dev) |
| } |
| |
| /** |
| - * pm_genpd_freeze - Freeze a device belonging to an I/O power domain. |
| + * pm_genpd_freeze - Freezing a device in an I/O PM domain. |
| * @dev: Device to freeze. |
| * |
| * Freeze a device under the assumption that its pm_domain field points to the |
| @@ -938,7 +969,29 @@ static int pm_genpd_freeze(struct device *dev) |
| } |
| |
| /** |
| - * pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain. |
| + * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain. |
| + * @dev: Device to freeze. |
| + * |
| + * Carry out a late freeze of a device under the assumption that its |
| + * pm_domain field points to the domain member of an object of type |
| + * struct generic_pm_domain representing a power domain consisting of I/O |
| + * devices. |
| + */ |
| +static int pm_genpd_freeze_late(struct device *dev) |
| +{ |
| + struct generic_pm_domain *genpd; |
| + |
| + dev_dbg(dev, "%s()\n", __func__); |
| + |
| + genpd = dev_to_genpd(dev); |
| + if (IS_ERR(genpd)) |
| + return -EINVAL; |
| + |
| + return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); |
| +} |
| + |
| +/** |
| + * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. |
| * @dev: Device to freeze. |
| * |
| * Carry out a late freeze of a device under the assumption that its |
| @@ -949,7 +1002,6 @@ static int pm_genpd_freeze(struct device *dev) |
| static int pm_genpd_freeze_noirq(struct device *dev) |
| { |
| struct generic_pm_domain *genpd; |
| - int ret; |
| |
| dev_dbg(dev, "%s()\n", __func__); |
| |
| @@ -957,20 +1009,31 @@ static int pm_genpd_freeze_noirq(struct device *dev) |
| if (IS_ERR(genpd)) |
| return -EINVAL; |
| |
| - if (genpd->suspend_power_off) |
| - return 0; |
| + return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
| +} |
| |
| - ret = genpd_freeze_late(genpd, dev); |
| - if (ret) |
| - return ret; |
| +/** |
| + * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain. |
| + * @dev: Device to thaw. |
| + * |
| + * Start the device, unless power has been removed from the domain already |
| + * before the system transition. |
| + */ |
| +static int pm_genpd_thaw_noirq(struct device *dev) |
| +{ |
| + struct generic_pm_domain *genpd; |
| |
| - genpd_stop_dev(genpd, dev); |
| + dev_dbg(dev, "%s()\n", __func__); |
| |
| - return 0; |
| + genpd = dev_to_genpd(dev); |
| + if (IS_ERR(genpd)) |
| + return -EINVAL; |
| + |
| + return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); |
| } |
| |
| /** |
| - * pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain. |
| + * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain. |
| * @dev: Device to thaw. |
| * |
| * Carry out an early thaw of a device under the assumption that its |
| @@ -978,7 +1041,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) |
| * struct generic_pm_domain representing a power domain consisting of I/O |
| * devices. |
| */ |
| -static int pm_genpd_thaw_noirq(struct device *dev) |
| +static int pm_genpd_thaw_early(struct device *dev) |
| { |
| struct generic_pm_domain *genpd; |
| |
| @@ -988,12 +1051,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) |
| if (IS_ERR(genpd)) |
| return -EINVAL; |
| |
| - if (genpd->suspend_power_off) |
| - return 0; |
| - |
| - genpd_start_dev(genpd, dev); |
| - |
| - return genpd_thaw_early(genpd, dev); |
| + return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); |
| } |
| |
| /** |
| @@ -1018,13 +1076,11 @@ static int pm_genpd_thaw(struct device *dev) |
| } |
| |
| /** |
| - * pm_genpd_restore_noirq - Early restore of a device from an I/O power domain. |
| + * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain. |
| * @dev: Device to resume. |
| * |
| - * Carry out an early restore of a device under the assumption that its |
| - * pm_domain field points to the domain member of an object of type |
| - * struct generic_pm_domain representing a power domain consisting of I/O |
| - * devices. |
| + * Make sure the domain will be in the same power state as before the |
| + * hibernation the system is resuming from and start the device if necessary. |
| */ |
| static int pm_genpd_restore_noirq(struct device *dev) |
| { |
| @@ -1054,9 +1110,8 @@ static int pm_genpd_restore_noirq(struct device *dev) |
| |
| pm_genpd_poweron(genpd); |
| genpd->suspended_count--; |
| - genpd_start_dev(genpd, dev); |
| |
| - return genpd_resume_early(genpd, dev); |
| + return genpd_start_dev(genpd, dev); |
| } |
| |
| /** |
| @@ -1099,11 +1154,15 @@ static void pm_genpd_complete(struct device *dev) |
| |
| #define pm_genpd_prepare NULL |
| #define pm_genpd_suspend NULL |
| +#define pm_genpd_suspend_late NULL |
| #define pm_genpd_suspend_noirq NULL |
| +#define pm_genpd_resume_early NULL |
| #define pm_genpd_resume_noirq NULL |
| #define pm_genpd_resume NULL |
| #define pm_genpd_freeze NULL |
| +#define pm_genpd_freeze_late NULL |
| #define pm_genpd_freeze_noirq NULL |
| +#define pm_genpd_thaw_early NULL |
| #define pm_genpd_thaw_noirq NULL |
| #define pm_genpd_thaw NULL |
| #define pm_genpd_restore_noirq NULL |
| @@ -1482,7 +1541,7 @@ static int pm_genpd_default_suspend_late(struct device *dev) |
| { |
| int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; |
| |
| - return cb ? cb(dev) : pm_generic_suspend_noirq(dev); |
| + return cb ? cb(dev) : pm_generic_suspend_late(dev); |
| } |
| |
| /** |
| @@ -1493,7 +1552,7 @@ static int pm_genpd_default_resume_early(struct device *dev) |
| { |
| int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; |
| |
| - return cb ? cb(dev) : pm_generic_resume_noirq(dev); |
| + return cb ? cb(dev) : pm_generic_resume_early(dev); |
| } |
| |
| /** |
| @@ -1526,7 +1585,7 @@ static int pm_genpd_default_freeze_late(struct device *dev) |
| { |
| int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; |
| |
| - return cb ? cb(dev) : pm_generic_freeze_noirq(dev); |
| + return cb ? cb(dev) : pm_generic_freeze_late(dev); |
| } |
| |
| /** |
| @@ -1537,7 +1596,7 @@ static int pm_genpd_default_thaw_early(struct device *dev) |
| { |
| int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; |
| |
| - return cb ? cb(dev) : pm_generic_thaw_noirq(dev); |
| + return cb ? cb(dev) : pm_generic_thaw_early(dev); |
| } |
| |
| /** |
| @@ -1596,16 +1655,22 @@ void pm_genpd_init(struct generic_pm_domain *genpd, |
| 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; |
| genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; |
| genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; |
| + genpd->domain.ops.resume_early = pm_genpd_resume_early; |
| genpd->domain.ops.resume = pm_genpd_resume; |
| genpd->domain.ops.freeze = pm_genpd_freeze; |
| + genpd->domain.ops.freeze_late = pm_genpd_freeze_late; |
| genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
| genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
| + genpd->domain.ops.thaw_early = pm_genpd_thaw_early; |
| genpd->domain.ops.thaw = pm_genpd_thaw; |
| genpd->domain.ops.poweroff = pm_genpd_suspend; |
| + genpd->domain.ops.poweroff_late = pm_genpd_suspend_late; |
| genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
| genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
| + genpd->domain.ops.restore_early = pm_genpd_resume_early; |
| genpd->domain.ops.restore = pm_genpd_resume; |
| genpd->domain.ops.complete = pm_genpd_complete; |
| genpd->dev_ops.save_state = pm_genpd_default_save_state; |
| -- |
| 1.7.10.1.362.g242cab3 |
| |