aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */