aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-10 10:09:44 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-10 10:09:44 -0500
commitf7cc61f0667a26a2a02ba0a2b5f977070378e324 (patch)
treeb48a9e64e047e2cd2a819604200793e6f404adee /drivers/base
parent740b68ea3ab7a55907e06b8b5b9a67082e345932 (diff)
parent1e95e3b2da424db68d0a465273f1901a990c6277 (diff)
Merge branch 'pm-domains'
* pm-domains: PM: Convert dev_pm_put_subsys_data() into a void function PM: Update function header for dev_pm_get_subsys_data() PM / Domains: Handle errors from genpd's ->attach_dev() callback PM / Domains: Re-order initialization of generic_pm_domain_data PM / Domains: Free pm_subsys_data in error path in __pm_genpd_add_device() PM / Domains: Eliminate the mutex for the generic_pm_domain_data PM / Domains: Don't check for an existing device when adding a new PM / Domains: Don't allow an existing generic_pm_domain_data PM / Domains: Remove reference counting for the generic_pm_domain_data PM / Domains: Rename __pm_genpd_alloc|free_dev_data() PM / Domains: Remove pm_genpd_dev_need_restore() API
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/common.c18
-rw-r--r--drivers/base/power/domain.c157
2 files changed, 71 insertions, 104 deletions
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index b0f138806bbc..f32b802b98f4 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -19,8 +19,8 @@
19 * @dev: Device to handle. 19 * @dev: Device to handle.
20 * 20 *
21 * If power.subsys_data is NULL, point it to a new object, otherwise increment 21 * If power.subsys_data is NULL, point it to a new object, otherwise increment
22 * its reference counter. Return 1 if a new object has been created, otherwise 22 * its reference counter. Return 0 if new object has been created or refcount
23 * return 0 or error code. 23 * increased, otherwise negative error code.
24 */ 24 */
25int dev_pm_get_subsys_data(struct device *dev) 25int dev_pm_get_subsys_data(struct device *dev)
26{ 26{
@@ -56,13 +56,11 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
56 * @dev: Device to handle. 56 * @dev: Device to handle.
57 * 57 *
58 * If the reference counter of power.subsys_data is zero after dropping the 58 * If the reference counter of power.subsys_data is zero after dropping the
59 * reference, power.subsys_data is removed. Return 1 if that happens or 0 59 * reference, power.subsys_data is removed.
60 * otherwise.
61 */ 60 */
62int dev_pm_put_subsys_data(struct device *dev) 61void dev_pm_put_subsys_data(struct device *dev)
63{ 62{
64 struct pm_subsys_data *psd; 63 struct pm_subsys_data *psd;
65 int ret = 1;
66 64
67 spin_lock_irq(&dev->power.lock); 65 spin_lock_irq(&dev->power.lock);
68 66
@@ -70,18 +68,14 @@ int dev_pm_put_subsys_data(struct device *dev)
70 if (!psd) 68 if (!psd)
71 goto out; 69 goto out;
72 70
73 if (--psd->refcount == 0) { 71 if (--psd->refcount == 0)
74 dev->power.subsys_data = NULL; 72 dev->power.subsys_data = NULL;
75 } else { 73 else
76 psd = NULL; 74 psd = NULL;
77 ret = 0;
78 }
79 75
80 out: 76 out:
81 spin_unlock_irq(&dev->power.lock); 77 spin_unlock_irq(&dev->power.lock);
82 kfree(psd); 78 kfree(psd);
83
84 return ret;
85} 79}
86EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); 80EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
87 81
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 0d8780c04a5e..ba4abbe4693c 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;
@@ -1384,25 +1377,66 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
1384 1377
1385#endif /* CONFIG_PM_SLEEP */ 1378#endif /* CONFIG_PM_SLEEP */
1386 1379
1387static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev) 1380static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
1381 struct generic_pm_domain *genpd,
1382 struct gpd_timing_data *td)
1388{ 1383{
1389 struct generic_pm_domain_data *gpd_data; 1384 struct generic_pm_domain_data *gpd_data;
1385 int ret;
1386
1387 ret = dev_pm_get_subsys_data(dev);
1388 if (ret)
1389 return ERR_PTR(ret);
1390 1390
1391 gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); 1391 gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
1392 if (!gpd_data) 1392 if (!gpd_data) {
1393 return NULL; 1393 ret = -ENOMEM;
1394 goto err_put;
1395 }
1396
1397 if (td)
1398 gpd_data->td = *td;
1394 1399
1395 mutex_init(&gpd_data->lock); 1400 gpd_data->base.dev = dev;
1401 gpd_data->need_restore = -1;
1402 gpd_data->td.constraint_changed = true;
1403 gpd_data->td.effective_constraint_ns = -1;
1396 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; 1404 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
1397 dev_pm_qos_add_notifier(dev, &gpd_data->nb); 1405
1406 spin_lock_irq(&dev->power.lock);
1407
1408 if (dev->power.subsys_data->domain_data) {
1409 ret = -EINVAL;
1410 goto err_free;
1411 }
1412
1413 dev->power.subsys_data->domain_data = &gpd_data->base;
1414 dev->pm_domain = &genpd->domain;
1415
1416 spin_unlock_irq(&dev->power.lock);
1417
1398 return gpd_data; 1418 return gpd_data;
1419
1420 err_free:
1421 spin_unlock_irq(&dev->power.lock);
1422 kfree(gpd_data);
1423 err_put:
1424 dev_pm_put_subsys_data(dev);
1425 return ERR_PTR(ret);
1399} 1426}
1400 1427
1401static void __pm_genpd_free_dev_data(struct device *dev, 1428static void genpd_free_dev_data(struct device *dev,
1402 struct generic_pm_domain_data *gpd_data) 1429 struct generic_pm_domain_data *gpd_data)
1403{ 1430{
1404 dev_pm_qos_remove_notifier(dev, &gpd_data->nb); 1431 spin_lock_irq(&dev->power.lock);
1432
1433 dev->pm_domain = NULL;
1434 dev->power.subsys_data->domain_data = NULL;
1435
1436 spin_unlock_irq(&dev->power.lock);
1437
1405 kfree(gpd_data); 1438 kfree(gpd_data);
1439 dev_pm_put_subsys_data(dev);
1406} 1440}
1407 1441
1408/** 1442/**
@@ -1414,8 +1448,7 @@ static void __pm_genpd_free_dev_data(struct device *dev,
1414int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, 1448int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1415 struct gpd_timing_data *td) 1449 struct gpd_timing_data *td)
1416{ 1450{
1417 struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; 1451 struct generic_pm_domain_data *gpd_data;
1418 struct pm_domain_data *pdd;
1419 int ret = 0; 1452 int ret = 0;
1420 1453
1421 dev_dbg(dev, "%s()\n", __func__); 1454 dev_dbg(dev, "%s()\n", __func__);
@@ -1423,9 +1456,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1423 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) 1456 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
1424 return -EINVAL; 1457 return -EINVAL;
1425 1458
1426 gpd_data_new = __pm_genpd_alloc_dev_data(dev); 1459 gpd_data = genpd_alloc_dev_data(dev, genpd, td);
1427 if (!gpd_data_new) 1460 if (IS_ERR(gpd_data))
1428 return -ENOMEM; 1461 return PTR_ERR(gpd_data);
1429 1462
1430 genpd_acquire_lock(genpd); 1463 genpd_acquire_lock(genpd);
1431 1464
@@ -1434,50 +1467,22 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1434 goto out; 1467 goto out;
1435 } 1468 }
1436 1469
1437 list_for_each_entry(pdd, &genpd->dev_list, list_node) 1470 ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
1438 if (pdd->dev == dev) {
1439 ret = -EINVAL;
1440 goto out;
1441 }
1442
1443 ret = dev_pm_get_subsys_data(dev);
1444 if (ret) 1471 if (ret)
1445 goto out; 1472 goto out;
1446 1473
1447 genpd->device_count++; 1474 genpd->device_count++;
1448 genpd->max_off_time_changed = true; 1475 genpd->max_off_time_changed = true;
1449 1476
1450 spin_lock_irq(&dev->power.lock);
1451
1452 dev->pm_domain = &genpd->domain;
1453 if (dev->power.subsys_data->domain_data) {
1454 gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
1455 } else {
1456 gpd_data = gpd_data_new;
1457 dev->power.subsys_data->domain_data = &gpd_data->base;
1458 }
1459 gpd_data->refcount++;
1460 if (td)
1461 gpd_data->td = *td;
1462
1463 spin_unlock_irq(&dev->power.lock);
1464
1465 if (genpd->attach_dev)
1466 genpd->attach_dev(genpd, dev);
1467
1468 mutex_lock(&gpd_data->lock);
1469 gpd_data->base.dev = dev;
1470 list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); 1477 list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
1471 gpd_data->need_restore = -1;
1472 gpd_data->td.constraint_changed = true;
1473 gpd_data->td.effective_constraint_ns = -1;
1474 mutex_unlock(&gpd_data->lock);
1475 1478
1476 out: 1479 out:
1477 genpd_release_lock(genpd); 1480 genpd_release_lock(genpd);
1478 1481
1479 if (gpd_data != gpd_data_new) 1482 if (ret)
1480 __pm_genpd_free_dev_data(dev, gpd_data_new); 1483 genpd_free_dev_data(dev, gpd_data);
1484 else
1485 dev_pm_qos_add_notifier(dev, &gpd_data->nb);
1481 1486
1482 return ret; 1487 return ret;
1483} 1488}
@@ -1504,7 +1509,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1504{ 1509{
1505 struct generic_pm_domain_data *gpd_data; 1510 struct generic_pm_domain_data *gpd_data;
1506 struct pm_domain_data *pdd; 1511 struct pm_domain_data *pdd;
1507 bool remove = false;
1508 int ret = 0; 1512 int ret = 0;
1509 1513
1510 dev_dbg(dev, "%s()\n", __func__); 1514 dev_dbg(dev, "%s()\n", __func__);
@@ -1514,6 +1518,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1514 || pd_to_genpd(dev->pm_domain) != genpd) 1518 || pd_to_genpd(dev->pm_domain) != genpd)
1515 return -EINVAL; 1519 return -EINVAL;
1516 1520
1521 /* The above validation also means we have existing domain_data. */
1522 pdd = dev->power.subsys_data->domain_data;
1523 gpd_data = to_gpd_data(pdd);
1524 dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
1525
1517 genpd_acquire_lock(genpd); 1526 genpd_acquire_lock(genpd);
1518 1527
1519 if (genpd->prepared_count > 0) { 1528 if (genpd->prepared_count > 0) {
@@ -1527,58 +1536,22 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1527 if (genpd->detach_dev) 1536 if (genpd->detach_dev)
1528 genpd->detach_dev(genpd, dev); 1537 genpd->detach_dev(genpd, dev);
1529 1538
1530 spin_lock_irq(&dev->power.lock);
1531
1532 dev->pm_domain = NULL;
1533 pdd = dev->power.subsys_data->domain_data;
1534 list_del_init(&pdd->list_node); 1539 list_del_init(&pdd->list_node);
1535 gpd_data = to_gpd_data(pdd);
1536 if (--gpd_data->refcount == 0) {
1537 dev->power.subsys_data->domain_data = NULL;
1538 remove = true;
1539 }
1540
1541 spin_unlock_irq(&dev->power.lock);
1542
1543 mutex_lock(&gpd_data->lock);
1544 pdd->dev = NULL;
1545 mutex_unlock(&gpd_data->lock);
1546 1540
1547 genpd_release_lock(genpd); 1541 genpd_release_lock(genpd);
1548 1542
1549 dev_pm_put_subsys_data(dev); 1543 genpd_free_dev_data(dev, gpd_data);
1550 if (remove)
1551 __pm_genpd_free_dev_data(dev, gpd_data);
1552 1544
1553 return 0; 1545 return 0;
1554 1546
1555 out: 1547 out:
1556 genpd_release_lock(genpd); 1548 genpd_release_lock(genpd);
1549 dev_pm_qos_add_notifier(dev, &gpd_data->nb);
1557 1550
1558 return ret; 1551 return ret;
1559} 1552}
1560 1553
1561/** 1554/**
1562 * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
1563 * @dev: Device to set/unset the flag for.
1564 * @val: The new value of the device's "need restore" flag.
1565 */
1566void pm_genpd_dev_need_restore(struct device *dev, bool val)
1567{
1568 struct pm_subsys_data *psd;
1569 unsigned long flags;
1570
1571 spin_lock_irqsave(&dev->power.lock, flags);
1572
1573 psd = dev_to_psd(dev);
1574 if (psd && psd->domain_data)
1575 to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0;
1576
1577 spin_unlock_irqrestore(&dev->power.lock, flags);
1578}
1579EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
1580
1581/**
1582 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. 1555 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
1583 * @genpd: Master PM domain to add the subdomain to. 1556 * @genpd: Master PM domain to add the subdomain to.
1584 * @subdomain: Subdomain to be added. 1557 * @subdomain: Subdomain to be added.