time.)  Unlike the other suspend-related phases, during the prepare
        phase the device tree is traversed top-down.
 
-       The prepare phase uses only a bus callback.  After the callback method
-       returns, no new children may be registered below the device.  The method
-       may also prepare the device or driver in some way for the upcoming
-       system power transition, but it should not put the device into a
-       low-power state.
+       In addition to that, if device drivers need to allocate additional
+       memory to be able to hadle device suspend correctly, that should be
+       done in the prepare phase.
+
+       After the prepare callback method returns, no new children may be
+       registered below the device.  The method may also prepare the device or
+       driver in some way for the upcoming system power transition (for
+       example, by allocating additional memory required for this purpose), but
+       it should not put the device into a low-power state.
 
     2. The suspend methods should quiesce the device to stop it from performing
        I/O.  They also may save the device registers and put it into the
 
 Suspend notifiers
-       (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
-
-There are some operations that device drivers may want to carry out in their
-.suspend() routines, but shouldn't, because they can cause the hibernation or
-suspend to fail. For example, a driver may want to allocate a substantial amount
-of memory (like 50 MB) in .suspend(), but that shouldn't be done after the
-swsusp's memory shrinker has run.
-
-Also, there may be some operations, that subsystems want to carry out before a
-hibernation/suspend or after a restore/resume, requiring the system to be fully
-functional, so the drivers' .suspend() and .resume() routines are not suitable
-for this purpose.  For example, device drivers may want to upload firmware to
-their devices after a restore from a hibernation image, but they cannot do it by
-calling request_firmware() from their .resume() routines (user land processes
-are frozen at this point).  The solution may be to load the firmware into
-memory before processes are frozen and upload it from there in the .resume()
-routine.  Of course, a hibernation notifier may be used for this purpose.
-
-The subsystems that have such needs can register suspend notifiers that will be
-called upon the following events by the suspend core:
+       (C) 2007-2011 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+There are some operations that subsystems or drivers may want to carry out
+before hibernation/suspend or after restore/resume, but they require the system
+to be fully functional, so the drivers' and subsystems' .suspend() and .resume()
+or even .prepare() and .complete() callbacks are not suitable for this purpose.
+For example, device drivers may want to upload firmware to their devices after
+resume/restore, but they cannot do it by calling request_firmware() from their
+.resume() or .complete() routines (user land processes are frozen at these
+points).  The solution may be to load the firmware into memory before processes
+are frozen and upload it from there in the .resume() routine.
+A suspend/hibernation notifier may be used for this purpose.
+
+The subsystems or drivers having such needs can register suspend notifiers that
+will be called upon the following events by the PM core:
 
 PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
                        be frozen immediately.
 
 PM_POST_HIBERNATION    The system memory state has been restored from a
-                       hibernation image or an error occurred during the
-                       hibernation.  Device drivers' .resume() callbacks have
+                       hibernation image or an error occurred during
+                       hibernation.  Device drivers' restore callbacks have
                        been executed and tasks have been thawed.
 
 PM_RESTORE_PREPARE     The system is going to restore a hibernation image.
-                       If all goes well the restored kernel will issue a
+                       If all goes well, the restored kernel will issue a
                        PM_POST_HIBERNATION notification.
 
-PM_POST_RESTORE                An error occurred during the hibernation restore.
-                       Device drivers' .resume() callbacks have been executed
+PM_POST_RESTORE                An error occurred during restore from hibernation.
+                       Device drivers' restore callbacks have been executed
                        and tasks have been thawed.
 
-PM_SUSPEND_PREPARE     The system is preparing for a suspend.
+PM_SUSPEND_PREPARE     The system is preparing for suspend.
 
 PM_POST_SUSPEND                The system has just resumed or an error occurred during
-                       the suspend.    Device drivers' .resume() callbacks have
-                       been executed and tasks have been thawed.
+                       suspend.  Device drivers' resume callbacks have been
+                       executed and tasks have been thawed.
 
 It is generally assumed that whatever the notifiers do for
 PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION.  Analogously,
 
  * Execute the appropriate "resume" callback for all devices whose status
  * indicates that they are suspended.
  */
-static void dpm_resume(pm_message_t state)
+void dpm_resume(pm_message_t state)
 {
        struct device *dev;
        ktime_t starttime = ktime_get();
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
  * Execute the ->complete() callbacks for all devices whose PM status is not
  * DPM_ON (this allows new devices to be registered).
  */
-static void dpm_complete(pm_message_t state)
+void dpm_complete(pm_message_t state)
 {
        struct list_head list;
 
+       might_sleep();
+
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_prepared_list)) {
  */
 void dpm_resume_end(pm_message_t state)
 {
-       might_sleep();
        dpm_resume(state);
        dpm_complete(state);
 }
  * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
  * @state: PM transition of the system being carried out.
  */
-static int dpm_suspend(pm_message_t state)
+int dpm_suspend(pm_message_t state)
 {
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
  *
  * Execute the ->prepare() callback(s) for all devices.
  */
-static int dpm_prepare(pm_message_t state)
+int dpm_prepare(pm_message_t state)
 {
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
 {
        int error;
 
-       might_sleep();
        error = dpm_prepare(state);
        if (!error)
                error = dpm_suspend(state);
 
 extern void device_pm_lock(void);
 extern void dpm_resume_noirq(pm_message_t state);
 extern void dpm_resume_end(pm_message_t state);
+extern void dpm_resume(pm_message_t state);
+extern void dpm_complete(pm_message_t state);
 
 extern void device_pm_unlock(void);
 extern int dpm_suspend_noirq(pm_message_t state);
 extern int dpm_suspend_start(pm_message_t state);
+extern int dpm_suspend(pm_message_t state);
+extern int dpm_prepare(pm_message_t state);
 
 extern void __suspend_report_result(const char *function, void *fn, int ret);
 
 
 
 int hibernation_snapshot(int platform_mode)
 {
+       pm_message_t msg = PMSG_RECOVER;
        int error;
 
        error = platform_begin(platform_mode);
        if (error)
                goto Close;
 
+       error = dpm_prepare(PMSG_FREEZE);
+       if (error)
+               goto Complete_devices;
+
        /* Preallocate image memory before shutting down devices. */
        error = hibernate_preallocate_memory();
        if (error)
-               goto Close;
+               goto Complete_devices;
 
        suspend_console();
        pm_restrict_gfp_mask();
-       error = dpm_suspend_start(PMSG_FREEZE);
+       error = dpm_suspend(PMSG_FREEZE);
        if (error)
                goto Recover_platform;
 
        if (error || !in_suspend)
                swsusp_free();
 
-       dpm_resume_end(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+       msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
+       dpm_resume(msg);
 
        if (error || !in_suspend)
                pm_restore_gfp_mask();
 
        resume_console();
+
+ Complete_devices:
+       dpm_complete(msg);
+
  Close:
        platform_end(platform_mode);
        return error;