aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2015-01-27 15:13:42 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-03 16:56:53 -0500
commitc0356db7d1b66840882744cbd9d9c5960b2d88c7 (patch)
tree98f3e89374400691135194fa4cbfdc065b96e5ed /drivers/base
parente07b45cb98839aa972c099ffd5fc5eb2ff1b2e26 (diff)
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>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/domain.c37
1 files changed, 14 insertions, 23 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 88198ba919d9..1f026c18bc5c 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
344 struct device *dev; 344 struct device *dev;
345 345
346 gpd_data = container_of(nb, struct generic_pm_domain_data, nb); 346 gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
347
348 mutex_lock(&gpd_data->lock);
349 dev = gpd_data->base.dev; 347 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);
355 348
356 for (;;) { 349 for (;;) {
357 struct generic_pm_domain *genpd; 350 struct generic_pm_domain *genpd;
@@ -1392,16 +1385,12 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
1392 if (!gpd_data) 1385 if (!gpd_data)
1393 return NULL; 1386 return NULL;
1394 1387
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);
1398 return gpd_data; 1388 return gpd_data;
1399} 1389}
1400 1390
1401static void genpd_free_dev_data(struct device *dev, 1391static void genpd_free_dev_data(struct device *dev,
1402 struct generic_pm_domain_data *gpd_data) 1392 struct generic_pm_domain_data *gpd_data)
1403{ 1393{
1404 dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
1405 kfree(gpd_data); 1394 kfree(gpd_data);
1406} 1395}
1407 1396
@@ -1414,7 +1403,7 @@ static void genpd_free_dev_data(struct device *dev,
1414int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, 1403int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1415 struct gpd_timing_data *td) 1404 struct gpd_timing_data *td)
1416{ 1405{
1417 struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; 1406 struct generic_pm_domain_data *gpd_data;
1418 int ret = 0; 1407 int ret = 0;
1419 1408
1420 dev_dbg(dev, "%s()\n", __func__); 1409 dev_dbg(dev, "%s()\n", __func__);
@@ -1422,8 +1411,8 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1422 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) 1411 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
1423 return -EINVAL; 1412 return -EINVAL;
1424 1413
1425 gpd_data_new = genpd_alloc_dev_data(dev); 1414 gpd_data = genpd_alloc_dev_data(dev);
1426 if (!gpd_data_new) 1415 if (!gpd_data)
1427 return -ENOMEM; 1416 return -ENOMEM;
1428 1417
1429 genpd_acquire_lock(genpd); 1418 genpd_acquire_lock(genpd);
@@ -1445,7 +1434,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1445 goto out; 1434 goto out;
1446 } 1435 }
1447 1436
1448 gpd_data = gpd_data_new;
1449 dev->power.subsys_data->domain_data = &gpd_data->base; 1437 dev->power.subsys_data->domain_data = &gpd_data->base;
1450 1438
1451 if (td) 1439 if (td)
@@ -1461,19 +1449,20 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1461 genpd->device_count++; 1449 genpd->device_count++;
1462 genpd->max_off_time_changed = true; 1450 genpd->max_off_time_changed = true;
1463 1451
1464 mutex_lock(&gpd_data->lock);
1465 gpd_data->base.dev = dev; 1452 gpd_data->base.dev = dev;
1466 list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); 1453 list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
1467 gpd_data->need_restore = -1; 1454 gpd_data->need_restore = -1;
1468 gpd_data->td.constraint_changed = true; 1455 gpd_data->td.constraint_changed = true;
1469 gpd_data->td.effective_constraint_ns = -1; 1456 gpd_data->td.effective_constraint_ns = -1;
1470 mutex_unlock(&gpd_data->lock); 1457 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
1471 1458
1472 out: 1459 out:
1473 genpd_release_lock(genpd); 1460 genpd_release_lock(genpd);
1474 1461
1475 if (gpd_data != gpd_data_new) 1462 if (ret)
1476 genpd_free_dev_data(dev, gpd_data_new); 1463 genpd_free_dev_data(dev, gpd_data);
1464 else
1465 dev_pm_qos_add_notifier(dev, &gpd_data->nb);
1477 1466
1478 return ret; 1467 return ret;
1479} 1468}
@@ -1509,6 +1498,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1509 || pd_to_genpd(dev->pm_domain) != genpd) 1498 || pd_to_genpd(dev->pm_domain) != genpd)
1510 return -EINVAL; 1499 return -EINVAL;
1511 1500
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
1512 genpd_acquire_lock(genpd); 1506 genpd_acquire_lock(genpd);
1513 1507
1514 if (genpd->prepared_count > 0) { 1508 if (genpd->prepared_count > 0) {
@@ -1525,16 +1519,12 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1525 spin_lock_irq(&dev->power.lock); 1519 spin_lock_irq(&dev->power.lock);
1526 1520
1527 dev->pm_domain = NULL; 1521 dev->pm_domain = NULL;
1528 pdd = dev->power.subsys_data->domain_data;
1529 list_del_init(&pdd->list_node); 1522 list_del_init(&pdd->list_node);
1530 gpd_data = to_gpd_data(pdd);
1531 dev->power.subsys_data->domain_data = NULL; 1523 dev->power.subsys_data->domain_data = NULL;
1532 1524
1533 spin_unlock_irq(&dev->power.lock); 1525 spin_unlock_irq(&dev->power.lock);
1534 1526
1535 mutex_lock(&gpd_data->lock);
1536 pdd->dev = NULL; 1527 pdd->dev = NULL;
1537 mutex_unlock(&gpd_data->lock);
1538 1528
1539 genpd_release_lock(genpd); 1529 genpd_release_lock(genpd);
1540 1530
@@ -1545,6 +1535,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1545 1535
1546 out: 1536 out:
1547 genpd_release_lock(genpd); 1537 genpd_release_lock(genpd);
1538 dev_pm_qos_add_notifier(dev, &gpd_data->nb);
1548 1539
1549 return ret; 1540 return ret;
1550} 1541}