diff options
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 339eb2d9bdd..c2468a7e5b2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -309,7 +309,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) not_suspended = 0; list_for_each_entry(pdd, &genpd->dev_list, list_node) - if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev)) + if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) + || pdd->dev->power.irq_safe)) not_suspended++; if (not_suspended > genpd->in_progress) @@ -417,12 +418,21 @@ static int pm_genpd_runtime_suspend(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; + might_sleep_if(!genpd->dev_irq_safe); + if (genpd->stop_device) { int ret = genpd->stop_device(dev); if (ret) return ret; } + /* + * If power.irq_safe is set, this routine will be run with interrupts + * off, so it can't use mutexes. + */ + if (dev->power.irq_safe) + return 0; + mutex_lock(&genpd->lock); genpd->in_progress++; pm_genpd_poweroff(genpd); @@ -452,6 +462,12 @@ static int pm_genpd_runtime_resume(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; + might_sleep_if(!genpd->dev_irq_safe); + + /* If power.irq_safe, the PM domain is never powered off. */ + if (dev->power.irq_safe) + goto out; + mutex_lock(&genpd->lock); ret = __pm_genpd_poweron(genpd); if (ret) { @@ -483,6 +499,7 @@ static int pm_genpd_runtime_resume(struct device *dev) wake_up_all(&genpd->status_wait_queue); mutex_unlock(&genpd->lock); + out: if (genpd->start_device) genpd->start_device(dev); |