Skip to content

Commit 19efa5f

Browse files
jonhunterrafaeljw
authored andcommitted
PM / Domains: Prepare for adding support to remove PM domains
In order to remove PM domains safely from the list of PM domains, it is necessary to adding locking for the PM domain list around any places where devices or subdomains are added to a PM domain. There are places where a reference to a PM domain is obtained via calling of_genpd_get_from_provider() before adding the device or the subdomain. In these cases a lock for the PM domain list needs to be held around the call to of_genpd_get_from_provider() and the call to add the device/subdomain. To avoid deadlocks by multiple attempts to obtain the PM domain list lock, add functions genpd_add_device() and genpd_add_subdomain() which require the user to hold the PM domain list lock when calling. Signed-off-by: Jon Hunter <[email protected]> Acked-by: Ulf Hansson <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 0159ec6 commit 19efa5f

File tree

1 file changed

+73
-24
lines changed

1 file changed

+73
-24
lines changed

drivers/base/power/domain.c

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,14 +1060,8 @@ static void genpd_free_dev_data(struct device *dev,
10601060
dev_pm_put_subsys_data(dev);
10611061
}
10621062

1063-
/**
1064-
* __pm_genpd_add_device - Add a device to an I/O PM domain.
1065-
* @genpd: PM domain to add the device to.
1066-
* @dev: Device to be added.
1067-
* @td: Set of PM QoS timing parameters to attach to the device.
1068-
*/
1069-
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1070-
struct gpd_timing_data *td)
1063+
static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1064+
struct gpd_timing_data *td)
10711065
{
10721066
struct generic_pm_domain_data *gpd_data;
10731067
int ret = 0;
@@ -1107,6 +1101,24 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
11071101

11081102
return ret;
11091103
}
1104+
1105+
/**
1106+
* __pm_genpd_add_device - Add a device to an I/O PM domain.
1107+
* @genpd: PM domain to add the device to.
1108+
* @dev: Device to be added.
1109+
* @td: Set of PM QoS timing parameters to attach to the device.
1110+
*/
1111+
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1112+
struct gpd_timing_data *td)
1113+
{
1114+
int ret;
1115+
1116+
mutex_lock(&gpd_list_lock);
1117+
ret = genpd_add_device(genpd, dev, td);
1118+
mutex_unlock(&gpd_list_lock);
1119+
1120+
return ret;
1121+
}
11101122
EXPORT_SYMBOL_GPL(__pm_genpd_add_device);
11111123

11121124
/**
@@ -1160,13 +1172,8 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
11601172
}
11611173
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);
11621174

1163-
/**
1164-
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
1165-
* @genpd: Master PM domain to add the subdomain to.
1166-
* @subdomain: Subdomain to be added.
1167-
*/
1168-
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
1169-
struct generic_pm_domain *subdomain)
1175+
static int genpd_add_subdomain(struct generic_pm_domain *genpd,
1176+
struct generic_pm_domain *subdomain)
11701177
{
11711178
struct gpd_link *link, *itr;
11721179
int ret = 0;
@@ -1209,6 +1216,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
12091216
kfree(link);
12101217
return ret;
12111218
}
1219+
1220+
/**
1221+
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
1222+
* @genpd: Master PM domain to add the subdomain to.
1223+
* @subdomain: Subdomain to be added.
1224+
*/
1225+
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
1226+
struct generic_pm_domain *subdomain)
1227+
{
1228+
int ret;
1229+
1230+
mutex_lock(&gpd_list_lock);
1231+
ret = genpd_add_subdomain(genpd, subdomain);
1232+
mutex_unlock(&gpd_list_lock);
1233+
1234+
return ret;
1235+
}
12121236
EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);
12131237

12141238
/**
@@ -1571,12 +1595,22 @@ static struct generic_pm_domain *genpd_get_from_provider(
15711595
int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev)
15721596
{
15731597
struct generic_pm_domain *genpd;
1598+
int ret;
1599+
1600+
mutex_lock(&gpd_list_lock);
15741601

15751602
genpd = genpd_get_from_provider(genpdspec);
1576-
if (IS_ERR(genpd))
1577-
return PTR_ERR(genpd);
1603+
if (IS_ERR(genpd)) {
1604+
ret = PTR_ERR(genpd);
1605+
goto out;
1606+
}
1607+
1608+
ret = genpd_add_device(genpd, dev, NULL);
15781609

1579-
return pm_genpd_add_device(genpd, dev);
1610+
out:
1611+
mutex_unlock(&gpd_list_lock);
1612+
1613+
return ret;
15801614
}
15811615
EXPORT_SYMBOL_GPL(of_genpd_add_device);
15821616

@@ -1593,16 +1627,28 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
15931627
struct of_phandle_args *subdomain_spec)
15941628
{
15951629
struct generic_pm_domain *parent, *subdomain;
1630+
int ret;
1631+
1632+
mutex_lock(&gpd_list_lock);
15961633

15971634
parent = genpd_get_from_provider(parent_spec);
1598-
if (IS_ERR(parent))
1599-
return PTR_ERR(parent);
1635+
if (IS_ERR(parent)) {
1636+
ret = PTR_ERR(parent);
1637+
goto out;
1638+
}
16001639

16011640
subdomain = genpd_get_from_provider(subdomain_spec);
1602-
if (IS_ERR(subdomain))
1603-
return PTR_ERR(subdomain);
1641+
if (IS_ERR(subdomain)) {
1642+
ret = PTR_ERR(subdomain);
1643+
goto out;
1644+
}
1645+
1646+
ret = genpd_add_subdomain(parent, subdomain);
16041647

1605-
return pm_genpd_add_subdomain(parent, subdomain);
1648+
out:
1649+
mutex_unlock(&gpd_list_lock);
1650+
1651+
return ret;
16061652
}
16071653
EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
16081654

@@ -1701,9 +1747,11 @@ int genpd_dev_pm_attach(struct device *dev)
17011747
return -ENOENT;
17021748
}
17031749

1750+
mutex_lock(&gpd_list_lock);
17041751
pd = genpd_get_from_provider(&pd_args);
17051752
of_node_put(pd_args.np);
17061753
if (IS_ERR(pd)) {
1754+
mutex_unlock(&gpd_list_lock);
17071755
dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
17081756
__func__, PTR_ERR(pd));
17091757
return -EPROBE_DEFER;
@@ -1712,13 +1760,14 @@ int genpd_dev_pm_attach(struct device *dev)
17121760
dev_dbg(dev, "adding to PM domain %s\n", pd->name);
17131761

17141762
for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
1715-
ret = pm_genpd_add_device(pd, dev);
1763+
ret = genpd_add_device(pd, dev, NULL);
17161764
if (ret != -EAGAIN)
17171765
break;
17181766

17191767
mdelay(i);
17201768
cond_resched();
17211769
}
1770+
mutex_unlock(&gpd_list_lock);
17221771

17231772
if (ret < 0) {
17241773
dev_err(dev, "failed to add to PM domain %s: %d",

0 commit comments

Comments
 (0)