diff options
| -rw-r--r-- | drivers/base/power/domain.c | 42 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 2 |
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 | |||
| 1539 | error: | ||
| 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); | |||
| 1535 | void of_genpd_del_provider(struct device_node *np) | 1555 | void 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 | } |
| 1550 | EXPORT_SYMBOL_GPL(of_genpd_del_provider); | 1582 | EXPORT_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 */ |
