aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Hunter <jonathanh@nvidia.com>2016-09-12 07:01:13 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-09-12 20:49:34 -0400
commit3fe577107ccf1974958701df710e0b07ef16db75 (patch)
tree3dd76befaccad67978dd0db1e9ba898705067c00
parentde0aa06d8b1c39df1071bfe169b3b97ca6bc01ac (diff)
PM / Domains: Add support for removing PM domains
The genpd framework allows users to add PM domains via the pm_genpd_init() function, however, there is no corresponding function to remove a PM domain. For most devices this may be fine as the PM domains are never removed, however, for devices that wish to populate the PM domains from within a driver, having the ability to remove a PM domain if the probing of the device fails or the driver is unloaded is necessary. Add the function pm_genpd_remove() to remove a PM domain by referencing it's generic_pm_domain structure. Note that the bulk of the code that removes the PM domain is placed in a separate local function genpd_remove() (which is called by pm_genpd_remove()). The code is structured in this way to prepare for adding another function to remove a PM domain by provider that will also call genpd_remove(). Note that users of genpd_remove() must call this function with the mutex, gpd_list_lock, held. PM domains can only be removed if the associated provider has been removed, they are not a parent domain to another PM domain and have no devices associated with them. 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.c60
-rw-r--r--include/linux/pm_domain.h5
2 files changed, 65 insertions, 0 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index d5135caa84db..7481e3e316a2 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1358,6 +1358,66 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
1358} 1358}
1359EXPORT_SYMBOL_GPL(pm_genpd_init); 1359EXPORT_SYMBOL_GPL(pm_genpd_init);
1360 1360
1361static int genpd_remove(struct generic_pm_domain *genpd)
1362{
1363 struct gpd_link *l, *link;
1364
1365 if (IS_ERR_OR_NULL(genpd))
1366 return -EINVAL;
1367
1368 mutex_lock(&genpd->lock);
1369
1370 if (genpd->has_provider) {
1371 mutex_unlock(&genpd->lock);
1372 pr_err("Provider present, unable to remove %s\n", genpd->name);
1373 return -EBUSY;
1374 }
1375
1376 if (!list_empty(&genpd->master_links) || genpd->device_count) {
1377 mutex_unlock(&genpd->lock);
1378 pr_err("%s: unable to remove %s\n", __func__, genpd->name);
1379 return -EBUSY;
1380 }
1381
1382 list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) {
1383 list_del(&link->master_node);
1384 list_del(&link->slave_node);
1385 kfree(link);
1386 }
1387
1388 list_del(&genpd->gpd_list_node);
1389 mutex_unlock(&genpd->lock);
1390 cancel_work_sync(&genpd->power_off_work);
1391 pr_debug("%s: removed %s\n", __func__, genpd->name);
1392
1393 return 0;
1394}
1395
1396/**
1397 * pm_genpd_remove - Remove a generic I/O PM domain
1398 * @genpd: Pointer to PM domain that is to be removed.
1399 *
1400 * To remove the PM domain, this function:
1401 * - Removes the PM domain as a subdomain to any parent domains,
1402 * if it was added.
1403 * - Removes the PM domain from the list of registered PM domains.
1404 *
1405 * The PM domain will only be removed, if the associated provider has
1406 * been removed, it is not a parent to any other PM domain and has no
1407 * devices associated with it.
1408 */
1409int pm_genpd_remove(struct generic_pm_domain *genpd)
1410{
1411 int ret;
1412
1413 mutex_lock(&gpd_list_lock);
1414 ret = genpd_remove(genpd);
1415 mutex_unlock(&gpd_list_lock);
1416
1417 return ret;
1418}
1419EXPORT_SYMBOL_GPL(pm_genpd_remove);
1420
1361#ifdef CONFIG_PM_GENERIC_DOMAINS_OF 1421#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
1362 1422
1363typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, 1423typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 554f8915c691..85f7d53a9827 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -130,6 +130,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
130 struct generic_pm_domain *target); 130 struct generic_pm_domain *target);
131extern int pm_genpd_init(struct generic_pm_domain *genpd, 131extern int pm_genpd_init(struct generic_pm_domain *genpd,
132 struct dev_power_governor *gov, bool is_off); 132 struct dev_power_governor *gov, bool is_off);
133extern int pm_genpd_remove(struct generic_pm_domain *genpd);
133 134
134extern struct dev_power_governor simple_qos_governor; 135extern struct dev_power_governor simple_qos_governor;
135extern struct dev_power_governor pm_domain_always_on_gov; 136extern struct dev_power_governor pm_domain_always_on_gov;
@@ -165,6 +166,10 @@ static inline int pm_genpd_init(struct generic_pm_domain *genpd,
165{ 166{
166 return -ENOSYS; 167 return -ENOSYS;
167} 168}
169static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
170{
171 return -ENOTSUPP;
172}
168#endif 173#endif
169 174
170static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, 175static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,