Skip to content

Commit ebb486b

Browse files
Shawn Guorafaeljw
authored andcommitted
PM: domains: Power off[on] domain in hibernate .freeze[thaw]_noirq hook
On platforms which use SHUTDOWN as hibernation mode, the genpd noirq hooks will be called like below. genpd_freeze_noirq() genpd_restore_noirq() ↓ ↑ Create snapshot image Restore target kernel ↓ ↑ genpd_thaw_noirq() genpd_freeze_noirq() ↓ ↑ Write snapshot image Read snapshot image ↓ ↑ power_down() Kernel boot As of today suspend hooks genpd_suspend[resume]_noirq() manages domain on/off state, but hibernate hooks genpd_freeze[thaw]_noirq() doesn't. This results in a different behavior of domain power state between suspend and hibernate freeze, i.e. domain is powered off for the former while on for the later. It causes a problem on platforms like i.MX where the domain needs to be powered on/off by calling clock and regulator interface. When the platform restores from hibernation, the domain is off in hardware and genpd_restore_noirq() tries to power it on, but will never succeed because software state of domain (clock and regulator) is left on from the last hibernate freeze, so kernel thinks that clock and regulator are enabled while they are actually not turned on in hardware. The consequence would be that devices in the power domain will access registers without clock or power, and cause hardware lockup. Power off[on] domain in hibernate .freeze[thaw]_noirq hook for reasons: - Align the behavior between suspend and hibernate freeze. - Have power state of domains stay in sync between hardware and software for hibernate freeze, and thus fix the lockup issue seen on i.MX platform. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent d9cc34f commit ebb486b

1 file changed

Lines changed: 4 additions & 31 deletions

File tree

drivers/base/power/domain.c

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,24 +1307,11 @@ static int genpd_resume_noirq(struct device *dev)
13071307
*/
13081308
static int genpd_freeze_noirq(struct device *dev)
13091309
{
1310-
const struct generic_pm_domain *genpd;
1311-
int ret = 0;
1312-
13131310
dev_dbg(dev, "%s()\n", __func__);
13141311

1315-
genpd = dev_to_genpd(dev);
1316-
if (IS_ERR(genpd))
1317-
return -EINVAL;
1318-
1319-
ret = pm_generic_freeze_noirq(dev);
1320-
if (ret)
1321-
return ret;
1322-
1323-
if (genpd->dev_ops.stop && genpd->dev_ops.start &&
1324-
!pm_runtime_status_suspended(dev))
1325-
ret = genpd_stop_dev(genpd, dev);
1326-
1327-
return ret;
1312+
return genpd_finish_suspend(dev,
1313+
pm_generic_freeze_noirq,
1314+
pm_generic_thaw_noirq);
13281315
}
13291316

13301317
/**
@@ -1336,23 +1323,9 @@ static int genpd_freeze_noirq(struct device *dev)
13361323
*/
13371324
static int genpd_thaw_noirq(struct device *dev)
13381325
{
1339-
const struct generic_pm_domain *genpd;
1340-
int ret = 0;
1341-
13421326
dev_dbg(dev, "%s()\n", __func__);
13431327

1344-
genpd = dev_to_genpd(dev);
1345-
if (IS_ERR(genpd))
1346-
return -EINVAL;
1347-
1348-
if (genpd->dev_ops.stop && genpd->dev_ops.start &&
1349-
!pm_runtime_status_suspended(dev)) {
1350-
ret = genpd_start_dev(genpd, dev);
1351-
if (ret)
1352-
return ret;
1353-
}
1354-
1355-
return pm_generic_thaw_noirq(dev);
1328+
return genpd_finish_resume(dev, pm_generic_thaw_noirq);
13561329
}
13571330

13581331
/**

0 commit comments

Comments
 (0)