Skip to content

Commit 3fe5771

Browse files
jonhunterrafaeljw
authored andcommitted
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 <[email protected]> Acked-by: Ulf Hansson <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent de0aa06 commit 3fe5771

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

drivers/base/power/domain.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,66 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
13581358
}
13591359
EXPORT_SYMBOL_GPL(pm_genpd_init);
13601360

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+
13611421
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
13621422

13631423
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,

include/linux/pm_domain.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
130130
struct generic_pm_domain *target);
131131
extern int pm_genpd_init(struct generic_pm_domain *genpd,
132132
struct dev_power_governor *gov, bool is_off);
133+
extern int pm_genpd_remove(struct generic_pm_domain *genpd);
133134

134135
extern struct dev_power_governor simple_qos_governor;
135136
extern struct dev_power_governor pm_domain_always_on_gov;
@@ -165,6 +166,10 @@ static inline int pm_genpd_init(struct generic_pm_domain *genpd,
165166
{
166167
return -ENOSYS;
167168
}
169+
static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
170+
{
171+
return -ENOTSUPP;
172+
}
168173
#endif
169174

170175
static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,

0 commit comments

Comments
 (0)