diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-10 10:09:44 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-10 10:09:44 -0500 |
commit | f7cc61f0667a26a2a02ba0a2b5f977070378e324 (patch) | |
tree | b48a9e64e047e2cd2a819604200793e6f404adee /drivers/base | |
parent | 740b68ea3ab7a55907e06b8b5b9a67082e345932 (diff) | |
parent | 1e95e3b2da424db68d0a465273f1901a990c6277 (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.c | 18 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 157 |
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 | */ |
25 | int dev_pm_get_subsys_data(struct device *dev) | 25 | int 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 | */ |
62 | int dev_pm_put_subsys_data(struct device *dev) | 61 | void 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 | } |
86 | EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); | 80 | EXPORT_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 | ||
1387 | static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev) | 1380 | static 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 | ||
1401 | static void __pm_genpd_free_dev_data(struct device *dev, | 1428 | static 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, | |||
1414 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | 1448 | int __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 | */ | ||
1566 | void 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 | } | ||
1579 | EXPORT_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. |