diff options
Diffstat (limited to 'drivers/base/power/domain.c')
-rw-r--r-- | drivers/base/power/domain.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 40bc2f4072cc..fb83d4acd400 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -361,9 +361,19 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
361 | struct device *dev = pdd->dev; | 361 | struct device *dev = pdd->dev; |
362 | int ret = 0; | 362 | int ret = 0; |
363 | 363 | ||
364 | if (gpd_data->need_restore) | 364 | if (gpd_data->need_restore > 0) |
365 | return 0; | 365 | return 0; |
366 | 366 | ||
367 | /* | ||
368 | * If the value of the need_restore flag is still unknown at this point, | ||
369 | * we trust that pm_genpd_poweroff() has verified that the device is | ||
370 | * already runtime PM suspended. | ||
371 | */ | ||
372 | if (gpd_data->need_restore < 0) { | ||
373 | gpd_data->need_restore = 1; | ||
374 | return 0; | ||
375 | } | ||
376 | |||
367 | mutex_unlock(&genpd->lock); | 377 | mutex_unlock(&genpd->lock); |
368 | 378 | ||
369 | genpd_start_dev(genpd, dev); | 379 | genpd_start_dev(genpd, dev); |
@@ -373,7 +383,7 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
373 | mutex_lock(&genpd->lock); | 383 | mutex_lock(&genpd->lock); |
374 | 384 | ||
375 | if (!ret) | 385 | if (!ret) |
376 | gpd_data->need_restore = true; | 386 | gpd_data->need_restore = 1; |
377 | 387 | ||
378 | return ret; | 388 | return ret; |
379 | } | 389 | } |
@@ -389,12 +399,17 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd, | |||
389 | { | 399 | { |
390 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | 400 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); |
391 | struct device *dev = pdd->dev; | 401 | struct device *dev = pdd->dev; |
392 | bool need_restore = gpd_data->need_restore; | 402 | int need_restore = gpd_data->need_restore; |
393 | 403 | ||
394 | gpd_data->need_restore = false; | 404 | gpd_data->need_restore = 0; |
395 | mutex_unlock(&genpd->lock); | 405 | mutex_unlock(&genpd->lock); |
396 | 406 | ||
397 | genpd_start_dev(genpd, dev); | 407 | genpd_start_dev(genpd, dev); |
408 | |||
409 | /* | ||
410 | * Call genpd_restore_dev() for recently added devices too (need_restore | ||
411 | * is negative then). | ||
412 | */ | ||
398 | if (need_restore) | 413 | if (need_restore) |
399 | genpd_restore_dev(genpd, dev); | 414 | genpd_restore_dev(genpd, dev); |
400 | 415 | ||
@@ -603,6 +618,7 @@ static void genpd_power_off_work_fn(struct work_struct *work) | |||
603 | static int pm_genpd_runtime_suspend(struct device *dev) | 618 | static int pm_genpd_runtime_suspend(struct device *dev) |
604 | { | 619 | { |
605 | struct generic_pm_domain *genpd; | 620 | struct generic_pm_domain *genpd; |
621 | struct generic_pm_domain_data *gpd_data; | ||
606 | bool (*stop_ok)(struct device *__dev); | 622 | bool (*stop_ok)(struct device *__dev); |
607 | int ret; | 623 | int ret; |
608 | 624 | ||
@@ -628,6 +644,16 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
628 | return 0; | 644 | return 0; |
629 | 645 | ||
630 | mutex_lock(&genpd->lock); | 646 | mutex_lock(&genpd->lock); |
647 | |||
648 | /* | ||
649 | * If we have an unknown state of the need_restore flag, it means none | ||
650 | * of the runtime PM callbacks has been invoked yet. Let's update the | ||
651 | * flag to reflect that the current state is active. | ||
652 | */ | ||
653 | gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); | ||
654 | if (gpd_data->need_restore < 0) | ||
655 | gpd_data->need_restore = 0; | ||
656 | |||
631 | genpd->in_progress++; | 657 | genpd->in_progress++; |
632 | pm_genpd_poweroff(genpd); | 658 | pm_genpd_poweroff(genpd); |
633 | genpd->in_progress--; | 659 | genpd->in_progress--; |
@@ -1437,12 +1463,12 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1437 | spin_unlock_irq(&dev->power.lock); | 1463 | spin_unlock_irq(&dev->power.lock); |
1438 | 1464 | ||
1439 | if (genpd->attach_dev) | 1465 | if (genpd->attach_dev) |
1440 | genpd->attach_dev(dev); | 1466 | genpd->attach_dev(genpd, dev); |
1441 | 1467 | ||
1442 | mutex_lock(&gpd_data->lock); | 1468 | mutex_lock(&gpd_data->lock); |
1443 | gpd_data->base.dev = dev; | 1469 | gpd_data->base.dev = dev; |
1444 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); | 1470 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); |
1445 | gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF; | 1471 | gpd_data->need_restore = -1; |
1446 | gpd_data->td.constraint_changed = true; | 1472 | gpd_data->td.constraint_changed = true; |
1447 | gpd_data->td.effective_constraint_ns = -1; | 1473 | gpd_data->td.effective_constraint_ns = -1; |
1448 | mutex_unlock(&gpd_data->lock); | 1474 | mutex_unlock(&gpd_data->lock); |
@@ -1499,7 +1525,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1499 | genpd->max_off_time_changed = true; | 1525 | genpd->max_off_time_changed = true; |
1500 | 1526 | ||
1501 | if (genpd->detach_dev) | 1527 | if (genpd->detach_dev) |
1502 | genpd->detach_dev(dev); | 1528 | genpd->detach_dev(genpd, dev); |
1503 | 1529 | ||
1504 | spin_lock_irq(&dev->power.lock); | 1530 | spin_lock_irq(&dev->power.lock); |
1505 | 1531 | ||
@@ -1546,7 +1572,7 @@ void pm_genpd_dev_need_restore(struct device *dev, bool val) | |||
1546 | 1572 | ||
1547 | psd = dev_to_psd(dev); | 1573 | psd = dev_to_psd(dev); |
1548 | if (psd && psd->domain_data) | 1574 | if (psd && psd->domain_data) |
1549 | to_gpd_data(psd->domain_data)->need_restore = val; | 1575 | to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0; |
1550 | 1576 | ||
1551 | spin_unlock_irqrestore(&dev->power.lock, flags); | 1577 | spin_unlock_irqrestore(&dev->power.lock, flags); |
1552 | } | 1578 | } |