aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-20 07:22:15 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-20 07:22:15 -0400
commit55cc33ceb75643d190ed215f423972e0b7ae7aeb (patch)
treee9573d995bfae0f81ce800433b424bb998f90eca /drivers/base
parent1f0b63866fc1be700260547be8edf8e6f0af37f2 (diff)
parentf71495f3f0c5f0801823d1235b271a4a415d3df8 (diff)
Merge branch 'pm-sleep' into acpi-pm
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/main.c66
1 files changed, 51 insertions, 15 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 86d5e4fb5b98..343ffad59377 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -479,7 +479,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
479 TRACE_DEVICE(dev); 479 TRACE_DEVICE(dev);
480 TRACE_RESUME(0); 480 TRACE_RESUME(0);
481 481
482 if (dev->power.syscore) 482 if (dev->power.syscore || dev->power.direct_complete)
483 goto Out; 483 goto Out;
484 484
485 if (!dev->power.is_noirq_suspended) 485 if (!dev->power.is_noirq_suspended)
@@ -605,7 +605,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
605 TRACE_DEVICE(dev); 605 TRACE_DEVICE(dev);
606 TRACE_RESUME(0); 606 TRACE_RESUME(0);
607 607
608 if (dev->power.syscore) 608 if (dev->power.syscore || dev->power.direct_complete)
609 goto Out; 609 goto Out;
610 610
611 if (!dev->power.is_late_suspended) 611 if (!dev->power.is_late_suspended)
@@ -735,6 +735,12 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
735 if (dev->power.syscore) 735 if (dev->power.syscore)
736 goto Complete; 736 goto Complete;
737 737
738 if (dev->power.direct_complete) {
739 /* Match the pm_runtime_disable() in __device_suspend(). */
740 pm_runtime_enable(dev);
741 goto Complete;
742 }
743
738 dpm_wait(dev->parent, async); 744 dpm_wait(dev->parent, async);
739 dpm_watchdog_set(&wd, dev); 745 dpm_watchdog_set(&wd, dev);
740 device_lock(dev); 746 device_lock(dev);
@@ -1007,7 +1013,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1007 goto Complete; 1013 goto Complete;
1008 } 1014 }
1009 1015
1010 if (dev->power.syscore) 1016 if (dev->power.syscore || dev->power.direct_complete)
1011 goto Complete; 1017 goto Complete;
1012 1018
1013 dpm_wait_for_children(dev, async); 1019 dpm_wait_for_children(dev, async);
@@ -1146,7 +1152,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
1146 goto Complete; 1152 goto Complete;
1147 } 1153 }
1148 1154
1149 if (dev->power.syscore) 1155 if (dev->power.syscore || dev->power.direct_complete)
1150 goto Complete; 1156 goto Complete;
1151 1157
1152 dpm_wait_for_children(dev, async); 1158 dpm_wait_for_children(dev, async);
@@ -1332,6 +1338,17 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1332 if (dev->power.syscore) 1338 if (dev->power.syscore)
1333 goto Complete; 1339 goto Complete;
1334 1340
1341 if (dev->power.direct_complete) {
1342 if (pm_runtime_status_suspended(dev)) {
1343 pm_runtime_disable(dev);
1344 if (pm_runtime_suspended_if_enabled(dev))
1345 goto Complete;
1346
1347 pm_runtime_enable(dev);
1348 }
1349 dev->power.direct_complete = false;
1350 }
1351
1335 dpm_watchdog_set(&wd, dev); 1352 dpm_watchdog_set(&wd, dev);
1336 device_lock(dev); 1353 device_lock(dev);
1337 1354
@@ -1382,10 +1399,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1382 1399
1383 End: 1400 End:
1384 if (!error) { 1401 if (!error) {
1402 struct device *parent = dev->parent;
1403
1385 dev->power.is_suspended = true; 1404 dev->power.is_suspended = true;
1386 if (dev->power.wakeup_path 1405 if (parent) {
1387 && dev->parent && !dev->parent->power.ignore_children) 1406 spin_lock_irq(&parent->power.lock);
1388 dev->parent->power.wakeup_path = true; 1407
1408 dev->parent->power.direct_complete = false;
1409 if (dev->power.wakeup_path
1410 && !dev->parent->power.ignore_children)
1411 dev->parent->power.wakeup_path = true;
1412
1413 spin_unlock_irq(&parent->power.lock);
1414 }
1389 } 1415 }
1390 1416
1391 device_unlock(dev); 1417 device_unlock(dev);
@@ -1487,7 +1513,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
1487{ 1513{
1488 int (*callback)(struct device *) = NULL; 1514 int (*callback)(struct device *) = NULL;
1489 char *info = NULL; 1515 char *info = NULL;
1490 int error = 0; 1516 int ret = 0;
1491 1517
1492 if (dev->power.syscore) 1518 if (dev->power.syscore)
1493 return 0; 1519 return 0;
@@ -1523,17 +1549,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
1523 callback = dev->driver->pm->prepare; 1549 callback = dev->driver->pm->prepare;
1524 } 1550 }
1525 1551
1526 if (callback) { 1552 if (callback)
1527 error = callback(dev); 1553 ret = callback(dev);
1528 suspend_report_result(callback, error);
1529 }
1530 1554
1531 device_unlock(dev); 1555 device_unlock(dev);
1532 1556
1533 if (error) 1557 if (ret < 0) {
1558 suspend_report_result(callback, ret);
1534 pm_runtime_put(dev); 1559 pm_runtime_put(dev);
1535 1560 return ret;
1536 return error; 1561 }
1562 /*
1563 * A positive return value from ->prepare() means "this device appears
1564 * to be runtime-suspended and its state is fine, so if it really is
1565 * runtime-suspended, you can leave it in that state provided that you
1566 * will do the same thing with all of its descendants". This only
1567 * applies to suspend transitions, however.
1568 */
1569 spin_lock_irq(&dev->power.lock);
1570 dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;
1571 spin_unlock_irq(&dev->power.lock);
1572 return 0;
1537} 1573}
1538 1574
1539/** 1575/**