/* 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
}
-/* 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;
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
* 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;
}
/*
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:
{
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;
/*
* 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);
* 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;
return 0;
}
-static int relocate_pagedir(void)
+static int __init relocate_pagedir(void)
{
/*
* We have to avoid recursion (not to overflow kernel stack),
* 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");
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);
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;
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
*/
int swsusp_write(void)
{
arch_prepare_suspend();
- do_magic(0);
- MDELAY(1000);
- return 0;
+ return do_magic(0);
}
* 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;
}
* 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);
}
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;
}