[PATCH] swsusp: properly suspend and resume *all* devices

Barry K. Nathan
2005-01-03T15:04:37Z

swsusp does not suspend and resume *all* devices, including system
devices. This has been the case since at least 2.6.9, if not earlier.

One effect of this 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).

On at least one of my systems, without this patch I also have to "ifdown
eth0;ifup eth0" to get networking to function after resuming, even after
working around the interrupt routing problem mentioned above. With this
patch, networking simply works after a resume, and the ifdown/ifup is
no longer needed.

This patch is against 2.6.10-mm1, although it applies with an offset to
2.6.10-bk4 as well. I have tested it against 2.6.10-mm1 and 2.6.10-bk4,
with and without "noapic", with and without "acpi=off". However, I have
not tested it on a highmem system.

I believe this patch fixes a severe problem in swsusp; I would like to
see this patch (or at least *some* kind of fix for this problem) tested
more widely and committed to mainline before the 2.6.11 release.

Signed-off-by: Barry K. Nathan <barryn@pobox.com>

--- linux-2.6.10-mm1/kernel/power/swsusp.c 2005-01-03 02:16:15.175265255 -0800
+++ linux-2.6.10-mm1-bkn3/kernel/power/swsusp.c 2005-01-03 06:27:07.753344731 -0800
@@ -843,11 +843,22 @@
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;
}