Commit 44ea4dc0 authored by Patrick Mochel's avatar Patrick Mochel

[Power Mgmt] Consolidate pmdisk and swsusp low-level handling.

- Split do_magic into swsusp_arch_suspend() and swsusp_arch_resume().
- Clean up based on pmdisk implementation
  - Only save registers we need to.
  - Use rep;movsl for copying, rather than doing each byte.
- Create swsusp_suspend and swsusp_resume wrappers for calling the assmebly
  routines that:
  - Call {save,restore}_processor_state() in each. 
  - Disable/enable interrupts in each. 
- Call swsusp_{suspend,restore} in software_{suspend,resume}
- Kill all the do_magic_* functions.
- Remove prototypes from linux/suspend.h
- Remove similar pmdisk functions.
- Update calls in kernel/power/disk.c to use swsusp versions.
parent 2e633f4f
obj-$(CONFIG_PM) += cpu.o
obj-$(CONFIG_PM_DISK) += pmdisk.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
......@@ -15,83 +15,47 @@
.text
ENTRY(do_magic)
pushl %ebx
cmpl $0,8(%esp)
jne resume
call do_magic_suspend_1
call save_processor_state
ENTRY(swsusp_arch_suspend)
movl %esp, saved_context_esp
movl %eax, saved_context_eax
movl %ebx, saved_context_ebx
movl %ecx, saved_context_ecx
movl %edx, saved_context_edx
movl %ebp, saved_context_ebp
movl %esi, saved_context_esi
movl %edi, saved_context_edi
pushfl ; popl saved_context_eflags
call do_magic_suspend_2
popl %ebx
call swsusp_save
ret
resume:
ENTRY(swsusp_arch_resume)
movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
movl %ecx,%cr3
call do_magic_resume_1
movl $0,loop
cmpl $0,nr_copy_pages
je copy_done
copy_loop:
movl $0,loop2
movl pagedir_nosave,%ebx
xorl %eax, %eax
xorl %edx, %edx
.p2align 4,,7
copy_one_page:
movl pagedir_nosave,%ecx
movl loop,%eax
movl loop2,%edx
sall $4,%eax
movl 4(%ecx,%eax),%ebx
movl (%ecx,%eax),%eax
movb (%edx,%eax),%al
movb %al,(%edx,%ebx)
movl loop2,%eax
leal 1(%eax),%edx
movl %edx,loop2
movl %edx,%eax
cmpl $4095,%eax
jbe copy_one_page
movl loop,%eax
leal 1(%eax),%edx
movl %edx,loop
movl %edx,%eax
cmpl nr_copy_pages,%eax
jb copy_loop
copy_loop:
movl 4(%ebx,%edx),%edi
movl (%ebx,%edx),%esi
movl $1024, %ecx
rep
movsl
copy_done:
movl $__USER_DS,%eax
incl %eax
addl $16, %edx
cmpl nr_copy_pages,%eax
jb copy_loop
.p2align 4,,7
movw %ax, %ds
movw %ax, %es
movl saved_context_esp, %esp
movl saved_context_ebp, %ebp
movl saved_context_eax, %eax
movl saved_context_ebx, %ebx
movl saved_context_ecx, %ecx
movl saved_context_edx, %edx
movl saved_context_esi, %esi
movl saved_context_edi, %edi
call restore_processor_state
pushl saved_context_eflags ; popfl
call do_magic_resume_2
popl %ebx
call swsusp_restore
ret
.section .data.nosave
loop:
.quad 0
loop2:
.quad 0
.previous
......@@ -75,12 +75,6 @@ static inline void disable_nonboot_cpus(void) {}
static inline void enable_nonboot_cpus(void) {}
#endif
asmlinkage void do_magic(int is_resume);
asmlinkage void do_magic_resume_1(void);
asmlinkage void do_magic_resume_2(void);
asmlinkage void do_magic_suspend_1(void);
asmlinkage void do_magic_suspend_2(void);
void save_processor_state(void);
void restore_processor_state(void);
struct saved_context;
......
......@@ -23,10 +23,10 @@
extern u32 pm_disk_mode;
extern struct pm_ops * pm_ops;
extern int pmdisk_save(void);
extern int swsusp_suspend(void);
extern int pmdisk_write(void);
extern int pmdisk_read(void);
extern int pmdisk_restore(void);
extern int swsusp_resume(void);
extern int pmdisk_free(void);
......@@ -161,7 +161,7 @@ int pm_suspend_disk(void)
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
if ((error = pmdisk_save()))
if ((error = swsusp_save()))
goto Done;
if (in_suspend) {
......@@ -227,7 +227,7 @@ static int pm_resume(void)
mdelay(1000);
pr_debug("PM: Restoring saved image.\n");
pmdisk_restore();
swsusp_resume();
pr_debug("PM: Restore failed, recovering.n");
finish();
Free:
......
......@@ -249,28 +249,7 @@ static int write_suspend_image(void)
extern void free_suspend_pagedir(unsigned long);
extern int suspend_prepare_image(void);
/**
* pmdisk_suspend - Atomically snapshot the system.
*
* This must be called with interrupts disabled, to prevent the
* system changing at all from underneath us.
*
* To do this, we count the number of pages in the system that we
* need to save; make sure we have enough memory and swap to clone
* the pages and save them in swap, allocate the space to hold them,
* and then snapshot them all.
*/
int pmdisk_suspend(void)
{
int error = 0;
if ((error = swsusp_swap_check()))
return error;
return suspend_prepare_image();
}
/**
......@@ -297,36 +276,6 @@ static int suspend_save_image(void)
return error;
}
/*
* Magic happens here
*/
int pmdisk_resume(void)
{
BUG_ON (nr_copy_pages_check != nr_copy_pages);
BUG_ON (pagedir_order_check != pagedir_order);
/* Even mappings of "global" things (vmalloc) need to be fixed */
__flush_tlb_global();
return 0;
}
/* pmdisk_arch_suspend() is implemented in arch/?/power/pmdisk.S,
and basically does:
if (!resume) {
save_processor_state();
SAVE_REGISTERS
return pmdisk_suspend();
}
GO_TO_SWAPPER_PAGE_TABLES
COPY_PAGES_BACK
RESTORE_REGISTERS
restore_processor_state();
return pmdisk_resume();
*/
/* More restore stuff */
......@@ -563,28 +512,6 @@ static int __init read_suspend_image(void)
goto Done;
}
/**
* pmdisk_save - Snapshot memory
*/
int pmdisk_save(void)
{
int error;
#if defined (CONFIG_HIGHMEM) || defined (CONFIG_DISCONTIGMEM)
pr_debug("pmdisk: not supported with high- or discontig-mem.\n");
return -EPERM;
#endif
if ((error = arch_prepare_suspend()))
return error;
local_irq_disable();
save_processor_state();
error = pmdisk_arch_suspend(0);
restore_processor_state();
local_irq_enable();
return error;
}
/**
* pmdisk_write - Write saved memory image to swap.
......@@ -632,22 +559,6 @@ int __init pmdisk_read(void)
}
/**
* pmdisk_restore - Replace running kernel with saved image.
*/
int __init pmdisk_restore(void)
{
int error;
local_irq_disable();
save_processor_state();
error = pmdisk_arch_suspend(1);
restore_processor_state();
local_irq_enable();
return error;
}
/**
* pmdisk_free - Free memory allocated to hold snapshot.
*/
......
......@@ -893,80 +893,58 @@ static void suspend_finish(void)
#endif
}
/*
* Magic happens here
*/
asmlinkage void do_magic_resume_1(void)
{
barrier();
mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
extern asmlinkage int swsusp_arch_suspend(void);
extern asmlinkage int swsusp_arch_resume(void);
device_power_down(3);
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 ;-). */
}
asmlinkage void do_magic_resume_2(void)
asmlinkage int swsusp_save(void)
{
BUG_ON (nr_copy_pages_check != nr_copy_pages);
BUG_ON (pagedir_order_check != pagedir_order);
int error = 0;
__flush_tlb_global(); /* Even mappings of "global" things (vmalloc) need to be fixed */
device_power_up();
spin_unlock_irq(&suspend_pagedir_lock);
if ((error = swsusp_swap_check()))
return error;
return suspend_prepare_image();
}
/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically does:
if (!resume) {
do_magic_suspend_1();
save_processor_state();
SAVE_REGISTERS
do_magic_suspend_2();
return;
}
GO_TO_SWAPPER_PAGE_TABLES
do_magic_resume_1();
COPY_PAGES_BACK
RESTORE_REGISTERS
int swsusp_suspend(void)
{
int error;
if ((error = arch_prepare_suspend()))
return error;
local_irq_disable();
save_processor_state();
error = swsusp_arch_suspend();
restore_processor_state();
do_magic_resume_2();
local_irq_enable();
return error;
}
*/
asmlinkage void do_magic_suspend_1(void)
asmlinkage int swsusp_restore(void)
{
mb();
barrier();
BUG_ON(in_atomic());
spin_lock_irq(&suspend_pagedir_lock);
BUG_ON (nr_copy_pages_check != nr_copy_pages);
BUG_ON (pagedir_order_check != pagedir_order);
/* Even mappings of "global" things (vmalloc) need to be fixed */
__flush_tlb_global();
return 0;
}
asmlinkage void do_magic_suspend_2(void)
int swsusp_resume(void)
{
int is_problem;
swsusp_swap_check();
device_power_down(3);
is_problem = suspend_prepare_image();
device_power_up();
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 ?! */
}
int error;
local_irq_disable();
save_processor_state();
error = swsusp_arch_resume();
restore_processor_state();
local_irq_enable();
return error;
}
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();
}
static int in_suspend __nosavedata = 0;
/*
* This is main interface to the outside world. It needs to be
......@@ -998,16 +976,15 @@ int software_suspend(void)
/* Save state of all device drivers, and stop them. */
printk("Suspending devices... ");
if ((res = device_suspend(3))==0) {
/* If stopping device drivers worked, we proceed basically into
* suspend_save_image.
*
* do_magic(0) returns after system is resumed.
*
* do_magic() copies all "used" memory to "free" memory, then
* unsuspends all device drivers, and writes memory to disk
* using normal kernel mechanism.
*/
do_magic(0);
in_suspend = 1;
res = swsusp_save();
if (!res && in_suspend) {
suspend_save_image();
suspend_power_down();
}
in_suspend = 0;
suspend_finish();
}
thaw_processes();
......@@ -1352,7 +1329,7 @@ static int __init software_resume(void)
/* FIXME: Should we stop processes here, just to be safer? */
disable_nonboot_cpus();
device_suspend(3);
do_magic(1);
swsusp_resume();
panic("This never returns");
read_failure:
......
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