diff options
| author | Jon Hunter <jonathanh@nvidia.com> | 2016-09-12 07:01:13 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-09-12 20:49:34 -0400 |
| commit | 3fe577107ccf1974958701df710e0b07ef16db75 (patch) | |
| tree | 3dd76befaccad67978dd0db1e9ba898705067c00 /drivers/base/power | |
| parent | de0aa06d8b1c39df1071bfe169b3b97ca6bc01ac (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>
Diffstat (limited to 'drivers/base/power')
| -rw-r--r-- | drivers/base/power/domain.c | 60 |
1 files changed, 60 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 | } |
| 1359 | EXPORT_SYMBOL_GPL(pm_genpd_init); | 1359 | EXPORT_SYMBOL_GPL(pm_genpd_init); |
| 1360 | 1360 | ||
| 1361 | static 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 | */ | ||
| 1409 | int 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 | } | ||
| 1419 | EXPORT_SYMBOL_GPL(pm_genpd_remove); | ||
| 1420 | |||
| 1361 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | 1421 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF |
| 1362 | 1422 | ||
| 1363 | typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, | 1423 | typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, |
