diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/domain.c | 67 |
1 files changed, 35 insertions, 32 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 3bd342f22519..0fd5ee127c30 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1377,7 +1377,9 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #endif /* CONFIG_PM_SLEEP */ -static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) +static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, + struct generic_pm_domain *genpd, + struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data; int ret; @@ -1392,8 +1394,32 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) goto err_put; } + if (td) + gpd_data->td = *td; + + gpd_data->base.dev = dev; + gpd_data->need_restore = -1; + gpd_data->td.constraint_changed = true; + gpd_data->td.effective_constraint_ns = -1; + gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; + + spin_lock_irq(&dev->power.lock); + + if (dev->power.subsys_data->domain_data) { + ret = -EINVAL; + goto err_free; + } + + dev->power.subsys_data->domain_data = &gpd_data->base; + dev->pm_domain = &genpd->domain; + + spin_unlock_irq(&dev->power.lock); + return gpd_data; + err_free: + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); err_put: dev_pm_put_subsys_data(dev); return ERR_PTR(ret); @@ -1402,6 +1428,13 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { + spin_lock_irq(&dev->power.lock); + + dev->pm_domain = NULL; + dev->power.subsys_data->domain_data = NULL; + + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); dev_pm_put_subsys_data(dev); } @@ -1423,7 +1456,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data = genpd_alloc_dev_data(dev); + gpd_data = genpd_alloc_dev_data(dev, genpd, td); if (IS_ERR(gpd_data)) return PTR_ERR(gpd_data); @@ -1434,35 +1467,13 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - spin_lock_irq(&dev->power.lock); - - if (dev->power.subsys_data->domain_data) { - spin_unlock_irq(&dev->power.lock); - ret = -EINVAL; - goto out; - } - - dev->power.subsys_data->domain_data = &gpd_data->base; - - if (td) - gpd_data->td = *td; - - dev->pm_domain = &genpd->domain; - - spin_unlock_irq(&dev->power.lock); - if (genpd->attach_dev) genpd->attach_dev(genpd, dev); genpd->device_count++; genpd->max_off_time_changed = true; - gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); - gpd_data->need_restore = -1; - gpd_data->td.constraint_changed = true; - gpd_data->td.effective_constraint_ns = -1; - gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; out: genpd_release_lock(genpd); @@ -1524,15 +1535,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, if (genpd->detach_dev) genpd->detach_dev(genpd, dev); - spin_lock_irq(&dev->power.lock); - - dev->pm_domain = NULL; list_del_init(&pdd->list_node); - dev->power.subsys_data->domain_data = NULL; - - spin_unlock_irq(&dev->power.lock); - - pdd->dev = NULL; genpd_release_lock(genpd); |