diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-09-19 15:59:02 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-09-19 15:59:02 -0400 |
commit | 88d26136a256576e444db312179e17af6dd0ea87 (patch) | |
tree | 21bd82f6880a91708549512fdb42bc4c79b4ea98 | |
parent | 997a031107ec962967ce36db9bc500f1fad491c1 (diff) |
PM: Prevent runtime suspend during system resume
This patch (as1591) moves the pm_runtime_get_noresume() and
pm_runtime_put_sync() calls from __device_suspend() and
device_resume() to device_prepare() and device_complete() in the PM
core.
The reason for doing this is to make sure that parent devices remain
at full power (i.e., don't go into runtime suspend) while their
children are being resumed from a system sleep.
The PCI core already contained equivalent code to serve the same
purpose. The patch removes the duplicated code, since it is no longer
needed. One of the comments from the PCI core gets moved into the PM
core, and a second comment is added to explain whe the _get_noresume
and _put_sync calls are present.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | drivers/base/power/main.c | 29 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 17 |
2 files changed, 18 insertions, 28 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2700f2e4066f..077b9756fd8f 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -565,7 +565,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
565 | pm_callback_t callback = NULL; | 565 | pm_callback_t callback = NULL; |
566 | char *info = NULL; | 566 | char *info = NULL; |
567 | int error = 0; | 567 | int error = 0; |
568 | bool put = false; | ||
569 | 568 | ||
570 | TRACE_DEVICE(dev); | 569 | TRACE_DEVICE(dev); |
571 | TRACE_RESUME(0); | 570 | TRACE_RESUME(0); |
@@ -583,7 +582,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
583 | goto Unlock; | 582 | goto Unlock; |
584 | 583 | ||
585 | pm_runtime_enable(dev); | 584 | pm_runtime_enable(dev); |
586 | put = true; | ||
587 | 585 | ||
588 | if (dev->pm_domain) { | 586 | if (dev->pm_domain) { |
589 | info = "power domain "; | 587 | info = "power domain "; |
@@ -636,9 +634,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
636 | 634 | ||
637 | TRACE_RESUME(error); | 635 | TRACE_RESUME(error); |
638 | 636 | ||
639 | if (put) | ||
640 | pm_runtime_put_sync(dev); | ||
641 | |||
642 | return error; | 637 | return error; |
643 | } | 638 | } |
644 | 639 | ||
@@ -749,6 +744,8 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
749 | } | 744 | } |
750 | 745 | ||
751 | device_unlock(dev); | 746 | device_unlock(dev); |
747 | |||
748 | pm_runtime_put_sync(dev); | ||
752 | } | 749 | } |
753 | 750 | ||
754 | /** | 751 | /** |
@@ -1043,12 +1040,16 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1043 | if (async_error) | 1040 | if (async_error) |
1044 | goto Complete; | 1041 | goto Complete; |
1045 | 1042 | ||
1046 | pm_runtime_get_noresume(dev); | 1043 | /* |
1044 | * If a device configured to wake up the system from sleep states | ||
1045 | * has been suspended at run time and there's a resume request pending | ||
1046 | * for it, this is equivalent to the device signaling wakeup, so the | ||
1047 | * system suspend operation should be aborted. | ||
1048 | */ | ||
1047 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | 1049 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) |
1048 | pm_wakeup_event(dev, 0); | 1050 | pm_wakeup_event(dev, 0); |
1049 | 1051 | ||
1050 | if (pm_wakeup_pending()) { | 1052 | if (pm_wakeup_pending()) { |
1051 | pm_runtime_put_sync(dev); | ||
1052 | async_error = -EBUSY; | 1053 | async_error = -EBUSY; |
1053 | goto Complete; | 1054 | goto Complete; |
1054 | } | 1055 | } |
@@ -1111,12 +1112,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1111 | Complete: | 1112 | Complete: |
1112 | complete_all(&dev->power.completion); | 1113 | complete_all(&dev->power.completion); |
1113 | 1114 | ||
1114 | if (error) { | 1115 | if (error) |
1115 | pm_runtime_put_sync(dev); | ||
1116 | async_error = error; | 1116 | async_error = error; |
1117 | } else if (dev->power.is_suspended) { | 1117 | else if (dev->power.is_suspended) |
1118 | __pm_runtime_disable(dev, false); | 1118 | __pm_runtime_disable(dev, false); |
1119 | } | ||
1120 | 1119 | ||
1121 | return error; | 1120 | return error; |
1122 | } | 1121 | } |
@@ -1209,6 +1208,14 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1209 | char *info = NULL; | 1208 | char *info = NULL; |
1210 | int error = 0; | 1209 | int error = 0; |
1211 | 1210 | ||
1211 | /* | ||
1212 | * If a device's parent goes into runtime suspend at the wrong time, | ||
1213 | * it won't be possible to resume the device. To prevent this we | ||
1214 | * block runtime suspend here, during the prepare phase, and allow | ||
1215 | * it again during the complete phase. | ||
1216 | */ | ||
1217 | pm_runtime_get_noresume(dev); | ||
1218 | |||
1212 | device_lock(dev); | 1219 | device_lock(dev); |
1213 | 1220 | ||
1214 | dev->power.wakeup_path = device_may_wakeup(dev); | 1221 | dev->power.wakeup_path = device_may_wakeup(dev); |
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 185be3703343..51cd90bcdd4c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -624,21 +624,6 @@ static int pci_pm_prepare(struct device *dev) | |||
624 | int error = 0; | 624 | int error = 0; |
625 | 625 | ||
626 | /* | 626 | /* |
627 | * If a PCI device configured to wake up the system from sleep states | ||
628 | * has been suspended at run time and there's a resume request pending | ||
629 | * for it, this is equivalent to the device signaling wakeup, so the | ||
630 | * system suspend operation should be aborted. | ||
631 | */ | ||
632 | pm_runtime_get_noresume(dev); | ||
633 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | ||
634 | pm_wakeup_event(dev, 0); | ||
635 | |||
636 | if (pm_wakeup_pending()) { | ||
637 | pm_runtime_put_sync(dev); | ||
638 | return -EBUSY; | ||
639 | } | ||
640 | |||
641 | /* | ||
642 | * PCI devices suspended at run time need to be resumed at this | 627 | * PCI devices suspended at run time need to be resumed at this |
643 | * point, because in general it is necessary to reconfigure them for | 628 | * point, because in general it is necessary to reconfigure them for |
644 | * system suspend. Namely, if the device is supposed to wake up the | 629 | * system suspend. Namely, if the device is supposed to wake up the |
@@ -661,8 +646,6 @@ static void pci_pm_complete(struct device *dev) | |||
661 | 646 | ||
662 | if (drv && drv->pm && drv->pm->complete) | 647 | if (drv && drv->pm && drv->pm->complete) |
663 | drv->pm->complete(dev); | 648 | drv->pm->complete(dev); |
664 | |||
665 | pm_runtime_put_sync(dev); | ||
666 | } | 649 | } |
667 | 650 | ||
668 | #else /* !CONFIG_PM_SLEEP */ | 651 | #else /* !CONFIG_PM_SLEEP */ |