Commit 72a4a179 authored by Patrick Mochel's avatar Patrick Mochel

[power] Further swsusp cleanups.

- Remove drivers_resume() and call from do_magic_resume2(). Handled by core.
- When bringing devices back to life, call device_pm_resume()
- Make sure we report the error from write_suspend_image()
- Remove suspend_power_down() and call to it. Handled by PM core.
- Move swap file resetting and freeing of pagedir to swsusp_free()
- Remove extraneous in_atomic() checks. 
- Mark all resume functions __init.
- Move resume_suspend_image() inside swsusp_read() and cleanup. 
- Make do_magic() report error.
parent f2a93dbd
......@@ -38,7 +38,7 @@ struct saved_context {
extern void save_processor_state(void);
extern void restore_processor_state(void);
extern void do_magic(int resume);
extern int do_magic(int resume);
#ifdef CONFIG_ACPI_SLEEP
extern unsigned long saved_eip;
......
......@@ -48,13 +48,6 @@ extern void drain_local_pages(void);
extern unsigned int nr_copy_pages __nosavedata;
extern suspend_pagedir_t *pagedir_nosave __nosavedata;
/* Communication between kernel/suspend.c and arch/i386/suspend.c */
extern void do_magic_resume_1(void);
extern void do_magic_resume_2(void);
extern void do_magic_suspend_1(void);
extern void do_magic_suspend_2(void);
/* Communication between acpi and arch/i386/suspend.c */
extern void do_suspend_lowlevel(int resume);
......
......@@ -41,6 +41,11 @@ void pm_restore_console(void)
console_loglevel = orig_loglevel;
#ifdef SUSPEND_CONSOLE
set_console(orig_fgconsole);
/* FIXME:
* This following part is left over from swsusp. Is it really needed?
*/
update_screen(fg_console);
#endif
return;
}
......@@ -88,8 +88,6 @@ static dev_t resume_device;
/* Local variables that should not be affected by save */
unsigned int nr_copy_pages __nosavedata = 0;
static int pm_suspend_state;
/* Suspend pagedir is allocated before final copy, therefore it
must be freed after resume
......@@ -438,36 +436,6 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
}
/* Make disk drivers accept operations, again */
static void drivers_unsuspend(void)
{
device_resume(RESUME_RESTORE_STATE);
device_resume(RESUME_ENABLE);
}
#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(RESUME_RESTORE_STATE);
device_resume(RESUME_ENABLE);
}
if (flags & RESUME_PHASE2) {
if (pm_suspend_state) {
if(pm_send_all(PM_RESUME,(void *)0))
printk(KERN_WARNING "Problem while sending resume event\n");
pm_suspend_state=0;
} else
printk(KERN_WARNING "PM suspend state wasn't raised\n");
#ifdef SUSPEND_CONSOLE
update_screen(fg_console); /* Hmm, is this the problem? */
#endif
}
}
static int suspend_prepare_image(void)
{
struct sysinfo i;
......@@ -520,12 +488,14 @@ static int suspend_prepare_image(void)
return 0;
}
static void suspend_save_image(void)
static int suspend_save_image(void)
{
drivers_unsuspend();
int error;
device_pm_resume();
lock_swapdevices();
write_suspend_image();
error = write_suspend_image();
lock_swapdevices(); /* This will unlock ignored swap devices since writing is finished */
/* It is important _NOT_ to umount filesystems at this point. We want
......@@ -533,29 +503,7 @@ static void suspend_save_image(void)
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/
}
static void suspend_power_down(void)
{
extern int C_A_D;
C_A_D = 0;
printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
#ifdef CONFIG_VT
PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state);
mdelay(1000);
if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL))))
machine_restart(NULL);
else
#endif
{
device_shutdown();
machine_power_off();
}
printk(KERN_EMERG "%sProbably not capable for powerdown. System halted.\n", name_suspend);
machine_halt();
while (1);
/* NOTREACHED */
return error;
}
/*
......@@ -567,32 +515,21 @@ void do_magic_resume_1(void)
barrier();
mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
PRINTK( "Waiting for DMAs to settle down...\n");
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
driver scheduled DMA, we have good chance for DMA to finish ;-). */
/* 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
driver scheduled DMA, we have good chance for DMA to finish ;-). */
mdelay(1000);
}
void do_magic_resume_2(void)
{
BUG_ON (nr_copy_pages_check != nr_copy_pages);
BUG_ON (pagedir_order_check != pagedir_order);
__flush_tlb_global(); /* Even mappings of "global" things (vmalloc) need to be fixed */
PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save);
/* Even mappings of "global" things (vmalloc) need to be fixed */
__flush_tlb_global();
spin_unlock_irq(&suspend_pagedir_lock);
drivers_resume(RESUME_ALL_PHASES);
PRINTK( "Fixing swap signatures... " );
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
PRINTK( "ok\n" );
#ifdef SUSPEND_CONSOLE
update_screen(fg_console); /* Hmm, is this the problem? */
#endif
}
/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically does:
......@@ -617,40 +554,28 @@ void do_magic_suspend_1(void)
{
mb();
barrier();
BUG_ON(in_atomic());
spin_lock_irq(&suspend_pagedir_lock);
}
void do_magic_suspend_2(void)
int do_magic_suspend_2(void)
{
int is_problem;
read_swapfiles();
is_problem = suspend_prepare_image();
spin_unlock_irq(&suspend_pagedir_lock);
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 */
BUG_ON(in_atomic());
suspend_save_image();
suspend_power_down(); /* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */
}
if (!is_problem)
return suspend_save_image();
printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend);
MDELAY(1000); /* So user can wait and report us messages if armageddon comes :-) */
barrier();
mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
mdelay(1000);
free_pages((unsigned long) pagedir_nosave, pagedir_order);
spin_unlock_irq(&suspend_pagedir_lock);
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
return -EFAULT;
}
/* More restore stuff */
/* FIXME: Why not memcpy(to, from, 1<<pagedir_order*PAGE_SIZE)? */
static void copy_pagedir(suspend_pagedir_t *to, suspend_pagedir_t *from)
static void __init copy_pagedir(suspend_pagedir_t *to, suspend_pagedir_t *from)
{
int i;
char *topointer=(char *)to, *frompointer=(char *)from;
......@@ -667,8 +592,8 @@ static void copy_pagedir(suspend_pagedir_t *to, suspend_pagedir_t *from)
/*
* Returns true if given address/order collides with any orig_address
*/
static int does_collide_order(suspend_pagedir_t *pagedir, unsigned long addr,
int order)
static int __init does_collide_order(suspend_pagedir_t *pagedir,
unsigned long addr, int order)
{
int i;
unsigned long addre = addr + (PAGE_SIZE<<order);
......@@ -685,7 +610,7 @@ static int does_collide_order(suspend_pagedir_t *pagedir, unsigned long addr,
* We check here that pagedir & pages it points to won't collide with pages
* where we're going to restore from the loaded pages later
*/
static int check_pagedir(void)
static int __init check_pagedir(void)
{
int i;
......@@ -703,7 +628,7 @@ static int check_pagedir(void)
return 0;
}
static int relocate_pagedir(void)
static int __init relocate_pagedir(void)
{
/*
* We have to avoid recursion (not to overflow kernel stack),
......@@ -753,13 +678,13 @@ static int relocate_pagedir(void)
* I really don't think that it's foolproof but more than nothing..
*/
static int sanity_check_failed(char *reason)
static int __init sanity_check_failed(char *reason)
{
printk(KERN_ERR "%s%s\n",name_resume,reason);
return -EPERM;
}
static int sanity_check(struct suspend_header *sh)
static int __init sanity_check(struct suspend_header *sh)
{
if(sh->version_code != LINUX_VERSION_CODE)
return sanity_check_failed("Incorrect kernel version");
......@@ -776,7 +701,8 @@ static int sanity_check(struct suspend_header *sh)
return 0;
}
static int bdev_read_page(struct block_device *bdev, long pos, void *buf)
static int __init bdev_read_page(struct block_device *bdev,
long pos, void *buf)
{
struct buffer_head *bh;
BUG_ON (pos%PAGE_SIZE);
......@@ -792,7 +718,8 @@ static int bdev_read_page(struct block_device *bdev, long pos, void *buf)
extern dev_t __init name_to_dev_t(const char *line);
static int __read_suspend_image(struct block_device *bdev, union diskpage *cur)
static int __init read_suspend_image(struct block_device *bdev,
union diskpage *cur)
{
swp_entry_t next;
int i, nr_pgdir_pages;
......@@ -869,54 +796,6 @@ static int __read_suspend_image(struct block_device *bdev, union diskpage *cur)
return 0;
}
static int read_suspend_image(const char * specialfile)
{
union diskpage *cur;
unsigned long scratch_page = 0;
int error;
char b[BDEVNAME_SIZE];
resume_device = name_to_dev_t(specialfile);
scratch_page = get_zeroed_page(GFP_ATOMIC);
cur = (void *) scratch_page;
if (cur) {
struct block_device *bdev;
printk("Resuming from device %s\n",
__bdevname(resume_device, b));
bdev = open_by_devnum(resume_device, FMODE_READ, BDEV_RAW);
if (IS_ERR(bdev)) {
error = PTR_ERR(bdev);
} else {
set_blocksize(bdev, PAGE_SIZE);
error = __read_suspend_image(bdev, cur);
blkdev_put(bdev, BDEV_RAW);
}
} else error = -ENOMEM;
if (scratch_page)
free_page(scratch_page);
switch (error) {
case 0:
PRINTK("Reading resume file was successful\n");
break;
case -EINVAL:
break;
case -EIO:
printk( "%sI/O error\n", name_resume);
break;
case -ENOENT:
printk( "%s%s: No such file or directory\n", name_resume, specialfile);
break;
case -ENOMEM:
printk( "%sNot enough memory\n", name_resume);
break;
default:
printk( "%sError %d resuming\n", name_resume, error );
}
MDELAY(1000);
return error;
}
/**
* swsusp_save - Snapshot memory
*/
......@@ -944,9 +823,7 @@ int swsusp_save(void)
int swsusp_write(void)
{
arch_prepare_suspend();
do_magic(0);
MDELAY(1000);
return 0;
return do_magic(0);
}
......@@ -954,13 +831,39 @@ int swsusp_write(void)
* swsusp_read - Read saved image from swap.
*/
int swsusp_read(void)
int __init swsusp_read(void)
{
union diskpage *cur;
int error;
char b[BDEVNAME_SIZE];
if (!strlen(resume_file))
return -ENOENT;
printk("swsusp: %s\n", name_resume );
resume_device = name_to_dev_t(resume_file);
printk("swsusp: Resume From Partition: %s, Device: %s\n",
resume_file, __bdevname(resume_device, b));
cur = (union diskpage *)get_zeroed_page(GFP_ATOMIC);
if (cur) {
struct block_device *bdev;
bdev = open_by_devnum(resume_device, FMODE_READ, BDEV_RAW);
if (!IS_ERR(bdev)) {
set_blocksize(bdev, PAGE_SIZE);
error = read_suspend_image(bdev, cur);
blkdev_put(bdev, BDEV_RAW);
} else
error = PTR_ERR(bdev);
free_page((unsigned long)cur);
} else
error = -ENOMEM;
if (!error)
PRINTK("Reading resume file was successful\n");
else
printk( "%sError %d resuming\n", name_resume, error );
MDELAY(1000);
return read_suspend_image(resume_file);
return error;
}
......@@ -968,10 +871,9 @@ int swsusp_read(void)
* swsusp_restore - Replace running kernel with saved image.
*/
int swsusp_restore(void)
int __init swsusp_restore(void)
{
do_magic(1);
return 0;
return do_magic(1);
}
......@@ -981,6 +883,12 @@ int swsusp_restore(void)
int swsusp_free(void)
{
PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save);
PRINTK( "Fixing swap signatures... " );
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
PRINTK( "ok\n" );
return 0;
}
......
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