Commit e7c215c1 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] swsusp does not stop DMA properly during resume

From: Pavel Machek <pavel@ucw.cz>

To correctly stop all DMA activity, make the boot kernel put all devices
into suspend state before entering the resume kernel image.
parent e100952f
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/swapops.h> #include <linux/swapops.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/console.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -488,33 +489,6 @@ static void free_some_memory(void) ...@@ -488,33 +489,6 @@ static void free_some_memory(void)
printk("|\n"); printk("|\n");
} }
/* Make disk drivers accept operations, again */
static void drivers_unsuspend(void)
{
device_resume();
}
/* Called from process context */
static int drivers_suspend(void)
{
return device_suspend(4);
}
#define RESUME_PHASE1 1 /* Called from interrupts disabled */
#define RESUME_PHASE2 2 /* Called with interrupts enabled */
#define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2)
static void drivers_resume(int flags)
{
if (flags & RESUME_PHASE1) {
device_resume();
}
if (flags & RESUME_PHASE2) {
#ifdef SUSPEND_CONSOLE
update_screen(fg_console); /* Hmm, is this the problem? */
#endif
}
}
static int suspend_prepare_image(void) static int suspend_prepare_image(void)
{ {
struct sysinfo i; struct sysinfo i;
...@@ -569,7 +543,7 @@ static int suspend_prepare_image(void) ...@@ -569,7 +543,7 @@ static int suspend_prepare_image(void)
static void suspend_save_image(void) static void suspend_save_image(void)
{ {
drivers_unsuspend(); device_resume();
lock_swapdevices(); lock_swapdevices();
write_suspend_image(); write_suspend_image();
...@@ -615,6 +589,7 @@ void do_magic_resume_1(void) ...@@ -615,6 +589,7 @@ void do_magic_resume_1(void)
mb(); mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */ spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
device_power_down(4);
PRINTK( "Waiting for DMAs to settle down...\n"); PRINTK( "Waiting for DMAs to settle down...\n");
mdelay(1000); /* We do not want some readahead with DMA to corrupt our memory, right? mdelay(1000); /* We do not want some readahead with DMA to corrupt our memory, right?
Do it with disabled interrupts for best effect. That way, if some Do it with disabled interrupts for best effect. That way, if some
...@@ -630,8 +605,13 @@ void do_magic_resume_2(void) ...@@ -630,8 +605,13 @@ void do_magic_resume_2(void)
PRINTK( "Freeing prev allocated pagedir\n" ); PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save); free_suspend_pagedir((unsigned long) pagedir_save);
device_power_up();
spin_unlock_irq(&suspend_pagedir_lock); spin_unlock_irq(&suspend_pagedir_lock);
drivers_resume(RESUME_ALL_PHASES); device_resume();
acquire_console_sem();
update_screen(fg_console); /* Hmm, is this the problem? */
release_console_sem();
PRINTK( "Fixing swap signatures... " ); PRINTK( "Fixing swap signatures... " );
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
...@@ -672,7 +652,9 @@ void do_magic_suspend_2(void) ...@@ -672,7 +652,9 @@ void do_magic_suspend_2(void)
{ {
int is_problem; int is_problem;
read_swapfiles(); read_swapfiles();
device_power_down(4);
is_problem = suspend_prepare_image(); is_problem = suspend_prepare_image();
device_power_up();
spin_unlock_irq(&suspend_pagedir_lock); spin_unlock_irq(&suspend_pagedir_lock);
if (!is_problem) { if (!is_problem) {
kernel_fpu_end(); /* save_processor_state() does kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks */ kernel_fpu_end(); /* save_processor_state() does kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks */
...@@ -716,7 +698,7 @@ static void do_software_suspend(void) ...@@ -716,7 +698,7 @@ static void do_software_suspend(void)
blk_run_queues(); blk_run_queues();
/* Save state of all device drivers, and stop them. */ /* Save state of all device drivers, and stop them. */
if(drivers_suspend()==0) if ((res = device_suspend(4))==0)
/* If stopping device drivers worked, we proceed basically into /* If stopping device drivers worked, we proceed basically into
* suspend_save_image. * suspend_save_image.
* *
...@@ -1091,6 +1073,7 @@ static int __init software_resume(void) ...@@ -1091,6 +1073,7 @@ static int __init software_resume(void)
printk( "resuming from %s\n", resume_file); printk( "resuming from %s\n", resume_file);
if (read_suspend_image(resume_file, 0)) if (read_suspend_image(resume_file, 0))
goto read_failure; goto read_failure;
device_suspend(4);
do_magic(1); do_magic(1);
panic("This never returns"); panic("This never returns");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment