aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Hunter <jonathanh@nvidia.com>2016-09-12 07:01:12 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-09-12 20:49:34 -0400
commitde0aa06d8b1c39df1071bfe169b3b97ca6bc01ac (patch)
tree01e47886fde0823831895c8d1a56d1c985b89d2a
parent19efa5ff63dc5ed41ac85f5a8518aa77cece3776 (diff)
PM / Domains: Store the provider in the PM domain structure
It is possible that a device has more than one provider of PM domains and to support the removal of a PM domain by provider, it is necessary to store a reference to the provider in the PM domain structure. Therefore, store a reference to the firmware node handle in the PM domain structure and populate it when providers (only device-tree based providers are currently supported by PM domains) are registered. Please note that when removing PM domains, it is necessary to verify that the PM domain provider has been removed from the list of providers before the PM domain can be removed. To do this add another member to the PM domain structure that indicates if the provider is present and set this member accordingly when providers are added and removed. Initialise the 'provider' and 'has_provider' members of the generic_pm_domain structure when a PM domains is added by calling pm_genpd_init(). Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/domain.c42
-rw-r--r--include/linux/pm_domain.h2
2 files changed, 39 insertions, 5 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 1bd8d412db06..d5135caa84db 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1306,6 +1306,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
1306 genpd->device_count = 0; 1306 genpd->device_count = 0;
1307 genpd->max_off_time_ns = -1; 1307 genpd->max_off_time_ns = -1;
1308 genpd->max_off_time_changed = true; 1308 genpd->max_off_time_changed = true;
1309 genpd->provider = NULL;
1310 genpd->has_provider = false;
1309 genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; 1311 genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
1310 genpd->domain.ops.runtime_resume = genpd_runtime_resume; 1312 genpd->domain.ops.runtime_resume = genpd_runtime_resume;
1311 genpd->domain.ops.prepare = pm_genpd_prepare; 1313 genpd->domain.ops.prepare = pm_genpd_prepare;
@@ -1491,6 +1493,11 @@ int of_genpd_add_provider_simple(struct device_node *np,
1491 if (pm_genpd_present(genpd)) 1493 if (pm_genpd_present(genpd))
1492 ret = genpd_add_provider(np, genpd_xlate_simple, genpd); 1494 ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
1493 1495
1496 if (!ret) {
1497 genpd->provider = &np->fwnode;
1498 genpd->has_provider = true;
1499 }
1500
1494 mutex_unlock(&gpd_list_lock); 1501 mutex_unlock(&gpd_list_lock);
1495 1502
1496 return ret; 1503 return ret;
@@ -1506,7 +1513,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
1506 struct genpd_onecell_data *data) 1513 struct genpd_onecell_data *data)
1507{ 1514{
1508 unsigned int i; 1515 unsigned int i;
1509 int ret; 1516 int ret = -EINVAL;
1510 1517
1511 if (!np || !data) 1518 if (!np || !data)
1512 return -EINVAL; 1519 return -EINVAL;
@@ -1514,13 +1521,26 @@ int of_genpd_add_provider_onecell(struct device_node *np,
1514 mutex_lock(&gpd_list_lock); 1521 mutex_lock(&gpd_list_lock);
1515 1522
1516 for (i = 0; i < data->num_domains; i++) { 1523 for (i = 0; i < data->num_domains; i++) {
1517 if (!pm_genpd_present(data->domains[i])) { 1524 if (!pm_genpd_present(data->domains[i]))
1518 mutex_unlock(&gpd_list_lock); 1525 goto error;
1519 return -EINVAL; 1526
1520 } 1527 data->domains[i]->provider = &np->fwnode;
1528 data->domains[i]->has_provider = true;
1521 } 1529 }
1522 1530
1523 ret = genpd_add_provider(np, genpd_xlate_onecell, data); 1531 ret = genpd_add_provider(np, genpd_xlate_onecell, data);
1532 if (ret < 0)
1533 goto error;
1534
1535 mutex_unlock(&gpd_list_lock);
1536
1537 return 0;
1538
1539error:
1540 while (i--) {
1541 data->domains[i]->provider = NULL;
1542 data->domains[i]->has_provider = false;
1543 }
1524 1544
1525 mutex_unlock(&gpd_list_lock); 1545 mutex_unlock(&gpd_list_lock);
1526 1546
@@ -1535,10 +1555,21 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);
1535void of_genpd_del_provider(struct device_node *np) 1555void of_genpd_del_provider(struct device_node *np)
1536{ 1556{
1537 struct of_genpd_provider *cp; 1557 struct of_genpd_provider *cp;
1558 struct generic_pm_domain *gpd;
1538 1559
1560 mutex_lock(&gpd_list_lock);
1539 mutex_lock(&of_genpd_mutex); 1561 mutex_lock(&of_genpd_mutex);
1540 list_for_each_entry(cp, &of_genpd_providers, link) { 1562 list_for_each_entry(cp, &of_genpd_providers, link) {
1541 if (cp->node == np) { 1563 if (cp->node == np) {
1564 /*
1565 * For each PM domain associated with the
1566 * provider, set the 'has_provider' to false
1567 * so that the PM domain can be safely removed.
1568 */
1569 list_for_each_entry(gpd, &gpd_list, gpd_list_node)
1570 if (gpd->provider == &np->fwnode)
1571 gpd->has_provider = false;
1572
1542 list_del(&cp->link); 1573 list_del(&cp->link);
1543 of_node_put(cp->node); 1574 of_node_put(cp->node);
1544 kfree(cp); 1575 kfree(cp);
@@ -1546,6 +1577,7 @@ void of_genpd_del_provider(struct device_node *np)
1546 } 1577 }
1547 } 1578 }
1548 mutex_unlock(&of_genpd_mutex); 1579 mutex_unlock(&of_genpd_mutex);
1580 mutex_unlock(&gpd_list_lock);
1549} 1581}
1550EXPORT_SYMBOL_GPL(of_genpd_del_provider); 1582EXPORT_SYMBOL_GPL(of_genpd_del_provider);
1551 1583
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index f103869db443..554f8915c691 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -51,6 +51,8 @@ struct generic_pm_domain {
51 struct mutex lock; 51 struct mutex lock;
52 struct dev_power_governor *gov; 52 struct dev_power_governor *gov;
53 struct work_struct power_off_work; 53 struct work_struct power_off_work;
54 struct fwnode_handle *provider; /* Identity of the domain provider */
55 bool has_provider;
54 const char *name; 56 const char *name;
55 atomic_t sd_count; /* Number of subdomains with power "on" */ 57 atomic_t sd_count; /* Number of subdomains with power "on" */
56 enum gpd_status status; /* Current state of the domain */ 58 enum gpd_status status; /* Current state of the domain */