From a20a26f360e95684260c4f0036779aed77f9327b Mon Sep 17 00:00:00 2001
From: "Barry K. Nathan" <barryn@pobox.com>
Date: Mon, 10 Jan 2005 17:12:33 -0800
Subject: [PATCH] [PATCH] swsusp: device power management fix

Since at least kernel 2.6.9, if not earlier, swsusp fails to properly
suspend and resume all devices.

The most notable effect is that resuming fails to properly reconfigure
interrupt routers.  In 2.6.9 this was obscured by other kernel code, but in
2.6.10 this often causes post-resume APIC errors and near-total failure of
some PCI devices (e.g.  network, sound and USB controllers).

Even in cases where interrupt routing is unaffected, this bug causes other
problems.  For instance, on one of my systems I have to run "ifdown
eth0;ifup eth0" after resume in order to have functional networking, if I
do not apply this patch.

By itself, this patch is not theoretically complete; my next patch fixes
that.  However, this patch is the critical one for fixing swsusp's behavior
in the real world.

Signed-off-by: Barry K. Nathan <barryn@pobox.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 kernel/power/swsusp.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index dfac617c4f39..210d102a7dc4 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -843,11 +843,22 @@ int swsusp_suspend(void)
 	if ((error = arch_prepare_suspend()))
 		return error;
 	local_irq_disable();
+	/* At this point, device_suspend() has been called, but *not*
+	 * device_power_down(). We *must* device_power_down() now.
+	 * Otherwise, drivers for some devices (e.g. interrupt controllers)
+	 * become desynchronized with the actual state of the hardware
+	 * at resume time, and evil weirdness ensues.
+	 */
+	if ((error = device_power_down(PM_SUSPEND_DISK))) {
+		local_irq_enable();
+		return error;
+	}
 	save_processor_state();
 	error = swsusp_arch_suspend();
 	/* Restore control flow magically appears here */
 	restore_processor_state();
 	restore_highmem();
+	device_power_up();
 	local_irq_enable();
 	return error;
 }
-- 
2.30.9