Skip to content

Commit 2071ac9

Browse files
jiada-wangrafaeljw
authored andcommitted
PM / Domains: Avoid a potential deadlock
Lockdep warns that prepare_lock and genpd->mlock can cause a deadlock the deadlock scenario is like following: First thread is probing cs2000 cs2000_probe() clk_register() __clk_core_init() clk_prepare_lock() ----> acquires prepare_lock cs2000_recalc_rate() i2c_smbus_read_byte_data() rcar_i2c_master_xfer() dma_request_chan() rcar_dmac_of_xlate() rcar_dmac_alloc_chan_resources() pm_runtime_get_sync() __pm_runtime_resume() rpm_resume() rpm_callback() genpd_runtime_resume() ----> acquires genpd->mlock Second thread is attaching any device to the same PM domain genpd_add_device() genpd_lock() ----> acquires genpd->mlock cpg_mssr_attach_dev() of_clk_get_from_provider() __of_clk_get_from_provider() __clk_create_clk() clk_prepare_lock() ----> acquires prepare_lock Since currently no PM provider access genpd's critical section in .attach_dev, and .detach_dev callbacks, so there is no need to protect these two callbacks with genpd->mlock. This patch avoids a potential deadlock by moving out .attach_dev and .detach_dev from genpd->mlock, so that genpd->mlock won't be held when prepare_lock is acquired in .attach_dev and .detach_dev Signed-off-by: Jiada Wang <jiada_wang@mentor.com> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 9e98c67 commit 2071ac9

File tree

1 file changed

+6
-7
lines changed

1 file changed

+6
-7
lines changed

drivers/base/power/domain.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,22 +1469,21 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
14691469
if (IS_ERR(gpd_data))
14701470
return PTR_ERR(gpd_data);
14711471

1472-
genpd_lock(genpd);
1473-
14741472
ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
14751473
if (ret)
14761474
goto out;
14771475

1476+
genpd_lock(genpd);
1477+
14781478
dev_pm_domain_set(dev, &genpd->domain);
14791479

14801480
genpd->device_count++;
14811481
genpd->max_off_time_changed = true;
14821482

14831483
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
14841484

1485-
out:
14861485
genpd_unlock(genpd);
1487-
1486+
out:
14881487
if (ret)
14891488
genpd_free_dev_data(dev, gpd_data);
14901489
else
@@ -1533,15 +1532,15 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
15331532
genpd->device_count--;
15341533
genpd->max_off_time_changed = true;
15351534

1536-
if (genpd->detach_dev)
1537-
genpd->detach_dev(genpd, dev);
1538-
15391535
dev_pm_domain_set(dev, NULL);
15401536

15411537
list_del_init(&pdd->list_node);
15421538

15431539
genpd_unlock(genpd);
15441540

1541+
if (genpd->detach_dev)
1542+
genpd->detach_dev(genpd, dev);
1543+
15451544
genpd_free_dev_data(dev, gpd_data);
15461545

15471546
return 0;

0 commit comments

Comments
 (0)