Skip to content

Commit c0356db

Browse files
storulfrafaeljw
authored andcommitted
PM / Domains: Eliminate the mutex for the generic_pm_domain_data
While adding devices to their PM domains, dev_pm_qos_add_notifier() was invoked while allocating the generic_pm_domain_data for the device. Since the generic_pm_domain_data's device pointer will be assigned after allocation, the ->genpd_dev_pm_qos_notifier() callback could be called prior having a valid pointer to the device. Similar scenario existed while removing a device from a genpd. To cope with these scenarios a mutex was used to protect the pointer to the device. By re-order the sequence for when dev_pm_qos_add|remove_notifier() are invoked, we make sure the ->genpd_dev_pm_qos_notifier() callback are always called with a valid device pointer available. In this way, we eliminate the need for protecting the pointer and thus we can remove the mutex from the struct generic_pm_domain_data. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent e07b45c commit c0356db

File tree

2 files changed

+14
-24
lines changed

2 files changed

+14
-24
lines changed

drivers/base/power/domain.c

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
344344
struct device *dev;
345345

346346
gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
347-
348-
mutex_lock(&gpd_data->lock);
349347
dev = gpd_data->base.dev;
350-
if (!dev) {
351-
mutex_unlock(&gpd_data->lock);
352-
return NOTIFY_DONE;
353-
}
354-
mutex_unlock(&gpd_data->lock);
355348

356349
for (;;) {
357350
struct generic_pm_domain *genpd;
@@ -1392,16 +1385,12 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
13921385
if (!gpd_data)
13931386
return NULL;
13941387

1395-
mutex_init(&gpd_data->lock);
1396-
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
1397-
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
13981388
return gpd_data;
13991389
}
14001390

14011391
static void genpd_free_dev_data(struct device *dev,
14021392
struct generic_pm_domain_data *gpd_data)
14031393
{
1404-
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
14051394
kfree(gpd_data);
14061395
}
14071396

@@ -1414,16 +1403,16 @@ static void genpd_free_dev_data(struct device *dev,
14141403
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
14151404
struct gpd_timing_data *td)
14161405
{
1417-
struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
1406+
struct generic_pm_domain_data *gpd_data;
14181407
int ret = 0;
14191408

14201409
dev_dbg(dev, "%s()\n", __func__);
14211410

14221411
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
14231412
return -EINVAL;
14241413

1425-
gpd_data_new = genpd_alloc_dev_data(dev);
1426-
if (!gpd_data_new)
1414+
gpd_data = genpd_alloc_dev_data(dev);
1415+
if (!gpd_data)
14271416
return -ENOMEM;
14281417

14291418
genpd_acquire_lock(genpd);
@@ -1445,7 +1434,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
14451434
goto out;
14461435
}
14471436

1448-
gpd_data = gpd_data_new;
14491437
dev->power.subsys_data->domain_data = &gpd_data->base;
14501438

14511439
if (td)
@@ -1461,19 +1449,20 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
14611449
genpd->device_count++;
14621450
genpd->max_off_time_changed = true;
14631451

1464-
mutex_lock(&gpd_data->lock);
14651452
gpd_data->base.dev = dev;
14661453
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
14671454
gpd_data->need_restore = -1;
14681455
gpd_data->td.constraint_changed = true;
14691456
gpd_data->td.effective_constraint_ns = -1;
1470-
mutex_unlock(&gpd_data->lock);
1457+
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
14711458

14721459
out:
14731460
genpd_release_lock(genpd);
14741461

1475-
if (gpd_data != gpd_data_new)
1476-
genpd_free_dev_data(dev, gpd_data_new);
1462+
if (ret)
1463+
genpd_free_dev_data(dev, gpd_data);
1464+
else
1465+
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
14771466

14781467
return ret;
14791468
}
@@ -1509,6 +1498,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
15091498
|| pd_to_genpd(dev->pm_domain) != genpd)
15101499
return -EINVAL;
15111500

1501+
/* The above validation also means we have existing domain_data. */
1502+
pdd = dev->power.subsys_data->domain_data;
1503+
gpd_data = to_gpd_data(pdd);
1504+
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
1505+
15121506
genpd_acquire_lock(genpd);
15131507

15141508
if (genpd->prepared_count > 0) {
@@ -1525,16 +1519,12 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
15251519
spin_lock_irq(&dev->power.lock);
15261520

15271521
dev->pm_domain = NULL;
1528-
pdd = dev->power.subsys_data->domain_data;
15291522
list_del_init(&pdd->list_node);
1530-
gpd_data = to_gpd_data(pdd);
15311523
dev->power.subsys_data->domain_data = NULL;
15321524

15331525
spin_unlock_irq(&dev->power.lock);
15341526

1535-
mutex_lock(&gpd_data->lock);
15361527
pdd->dev = NULL;
1537-
mutex_unlock(&gpd_data->lock);
15381528

15391529
genpd_release_lock(genpd);
15401530

@@ -1545,6 +1535,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
15451535

15461536
out:
15471537
genpd_release_lock(genpd);
1538+
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
15481539

15491540
return ret;
15501541
}

include/linux/pm_domain.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ struct generic_pm_domain_data {
113113
struct pm_domain_data base;
114114
struct gpd_timing_data td;
115115
struct notifier_block nb;
116-
struct mutex lock;
117116
int need_restore;
118117
};
119118

0 commit comments

Comments
 (0)