aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:37:04 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:37:04 -0400
commit0aa2a221696cc8ea20a4cdca01315d3b6b4ecc4d (patch)
treee2af809c44ff7ec93299170fc7ee6871be25108e /drivers/base/power
parentb5e8d269d814763d597ccc0108d1fa6639ad35a1 (diff)
PM / Domains: Preliminary support for devices with power.irq_safe set
The generic PM domains framework currently doesn't work with devices whose power.irq_safe flag is set, because runtime PM callbacks for such devices are run with interrupts disabled and the callbacks provided by the generic PM domains framework use domain mutexes and may sleep. However, such devices very well may belong to power domains on some systems, so the generic PM domains framework should take them into account. For this reason, modify the generic PM domains framework so that the domain .power_off() and .power_on() callbacks are never executed for a domain containing devices with power.irq_safe set, although the .stop_device() and .start_device() callbacks are still run for them. Additionally, introduce a flag allowing the creator of a struct generic_pm_domain object to indicate that its .stop_device() and .start_device() callbacks may be run in interrupt context (might_sleep_if() triggers if that flag is not set and one of those callbacks is run in interrupt context). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c19
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)
309 309
310 not_suspended = 0; 310 not_suspended = 0;
311 list_for_each_entry(pdd, &genpd->dev_list, list_node) 311 list_for_each_entry(pdd, &genpd->dev_list, list_node)
312 if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev)) 312 if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
313 || pdd->dev->power.irq_safe))
313 not_suspended++; 314 not_suspended++;
314 315
315 if (not_suspended > genpd->in_progress) 316 if (not_suspended > genpd->in_progress)
@@ -417,12 +418,21 @@ static int pm_genpd_runtime_suspend(struct device *dev)
417 if (IS_ERR(genpd)) 418 if (IS_ERR(genpd))
418 return -EINVAL; 419 return -EINVAL;
419 420
421 might_sleep_if(!genpd->dev_irq_safe);
422
420 if (genpd->stop_device) { 423 if (genpd->stop_device) {
421 int ret = genpd->stop_device(dev); 424 int ret = genpd->stop_device(dev);
422 if (ret) 425 if (ret)
423 return ret; 426 return ret;
424 } 427 }
425 428
429 /*
430 * If power.irq_safe is set, this routine will be run with interrupts
431 * off, so it can't use mutexes.
432 */
433 if (dev->power.irq_safe)
434 return 0;
435
426 mutex_lock(&genpd->lock); 436 mutex_lock(&genpd->lock);
427 genpd->in_progress++; 437 genpd->in_progress++;
428 pm_genpd_poweroff(genpd); 438 pm_genpd_poweroff(genpd);
@@ -452,6 +462,12 @@ static int pm_genpd_runtime_resume(struct device *dev)
452 if (IS_ERR(genpd)) 462 if (IS_ERR(genpd))
453 return -EINVAL; 463 return -EINVAL;
454 464
465 might_sleep_if(!genpd->dev_irq_safe);
466
467 /* If power.irq_safe, the PM domain is never powered off. */
468 if (dev->power.irq_safe)
469 goto out;
470
455 mutex_lock(&genpd->lock); 471 mutex_lock(&genpd->lock);
456 ret = __pm_genpd_poweron(genpd); 472 ret = __pm_genpd_poweron(genpd);
457 if (ret) { 473 if (ret) {
@@ -483,6 +499,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
483 wake_up_all(&genpd->status_wait_queue); 499 wake_up_all(&genpd->status_wait_queue);
484 mutex_unlock(&genpd->lock); 500 mutex_unlock(&genpd->lock);
485 501
502 out:
486 if (genpd->start_device) 503 if (genpd->start_device)
487 genpd->start_device(dev); 504 genpd->start_device(dev);
488 505