Commit 1a8e07b6 authored by Patrick Mochel's avatar Patrick Mochel

Merge digitalimplant.org:/home/mochel/src/linux-2.6-virgin

into digitalimplant.org:/home/mochel/src/linux-2.6-power
parents a6c13231 9556b782
obj-$(CONFIG_PM) += cpu.o
obj-$(CONFIG_PM_DISK) += pmdisk.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
/* Originally gcc generated, modified by hand */
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
.text
ENTRY(pmdisk_arch_suspend)
cmpl $0,4(%esp)
jne .L1450
movl %esp, saved_context_esp
movl %ebx, saved_context_ebx
movl %ebp, saved_context_ebp
movl %esi, saved_context_esi
movl %edi, saved_context_edi
pushfl ; popl saved_context_eflags
call pmdisk_suspend
jmp .L1449
.p2align 4,,7
.L1450:
movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
movl %ecx,%cr3
movl pm_pagedir_nosave,%ebx
xorl %eax, %eax
xorl %edx, %edx
.p2align 4,,7
.L1455:
movl 4(%ebx,%edx),%edi
movl (%ebx,%edx),%esi
movl $1024, %ecx
rep
movsl
movl %cr3, %ecx;
movl %ecx, %cr3; # flush TLB
incl %eax
addl $16, %edx
cmpl pmdisk_pages,%eax
jb .L1455
.p2align 4,,7
.L1453:
movl saved_context_esp, %esp
movl saved_context_ebp, %ebp
movl saved_context_ebx, %ebx
movl saved_context_esi, %esi
movl saved_context_edi, %edi
pushl saved_context_eflags ; popfl
call pmdisk_resume
.L1449:
ret
......@@ -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
......@@ -23,16 +23,6 @@ typedef struct pbe {
#define SWAP_FILENAME_MAXLENGTH 32
struct suspend_header {
u32 version_code;
unsigned long num_physpages;
char machine[8];
char version[20];
int num_cpus;
int page_size;
suspend_pagedir_t *suspend_pagedir;
unsigned int num_pbes;
};
#define SUSPEND_PD_PAGES(x) (((x)*sizeof(struct pbe))/PAGE_SIZE+1)
......@@ -45,16 +35,12 @@ extern void drain_local_pages(void);
/* kernel/power/swsusp.c */
extern int software_suspend(void);
extern unsigned int nr_copy_pages __nosavedata;
extern suspend_pagedir_t *pagedir_nosave __nosavedata;
#else /* CONFIG_SOFTWARE_SUSPEND */
static inline int software_suspend(void)
{
printk("Warning: fake suspend called\n");
return -EPERM;
}
#define software_resume() do { } while(0)
#endif /* CONFIG_SOFTWARE_SUSPEND */
......@@ -78,12 +64,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;
......
......@@ -42,33 +42,12 @@ config SOFTWARE_SUSPEND
For more information take a look at Documentation/power/swsusp.txt.
config PM_DISK
bool "Suspend-to-Disk Support"
depends on PM && SWAP && X86 && !X86_64
---help---
Suspend-to-disk is a power management state in which the contents
of memory are stored on disk and the entire system is shut down or
put into a low-power state (e.g. ACPI S4). When the computer is
turned back on, the stored image is loaded from disk and execution
resumes from where it left off before suspending.
This config option enables the core infrastructure necessary to
perform the suspend and resume transition.
Currently, this suspend-to-disk implementation is based on a forked
version of the swsusp code base. As such, it's still experimental,
and still relies on CONFIG_SWAP.
More information can be found in Documentation/power/.
If unsure, Say N.
config PM_DISK_PARTITION
config PM_STD_PARTITION
string "Default resume partition"
depends on PM_DISK
depends on SOFTWARE_SUSPEND
default ""
---help---
The default resume partition is the partition that the pmdisk suspend-
The default resume partition is the partition that the suspend-
to-disk implementation will look for a suspended disk image.
The partition specified here will be different for almost every user.
......@@ -77,16 +56,10 @@ config PM_DISK_PARTITION
The partition specified can be overridden by specifying:
pmdisk=/dev/<other device>
resume=/dev/<other device>
which will set the resume partition to the device specified.
One may also do:
pmdisk=off
to inform the kernel not to perform a resume transition.
Note there is currently not a way to specify which device to save the
suspended image to. It will simply pick the first available swap
device.
......
......@@ -2,7 +2,6 @@
swsusp-smp-$(CONFIG_SMP) += smp.o
obj-y := main.o process.o console.o pm.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y)
obj-$(CONFIG_PM_DISK) += disk.o pmdisk.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
......@@ -23,13 +23,16 @@
extern u32 pm_disk_mode;
extern struct pm_ops * pm_ops;
extern int pmdisk_save(void);
extern int pmdisk_write(void);
extern int pmdisk_read(void);
extern int pmdisk_restore(void);
extern int pmdisk_free(void);
extern int swsusp_suspend(void);
extern int swsusp_write(void);
extern int swsusp_read(void);
extern int swsusp_resume(void);
extern int swsusp_free(void);
static int noresume = 0;
char resume_file[256] = CONFIG_PM_STD_PARTITION;
/**
* power_down - Shut machine down for hibernate.
* @mode: Suspend-to-disk mode
......@@ -99,6 +102,7 @@ static void finish(void)
{
device_resume();
platform_finish();
enable_nonboot_cpus();
thaw_processes();
pm_restore_console();
}
......@@ -126,6 +130,7 @@ static int prepare(void)
/* Free memory before shutting down devices. */
free_some_memory();
disable_nonboot_cpus();
if ((error = device_suspend(PM_SUSPEND_DISK)))
goto Finish;
......@@ -133,6 +138,7 @@ static int prepare(void)
Finish:
platform_finish();
Thaw:
enable_nonboot_cpus();
thaw_processes();
pm_restore_console();
return error;
......@@ -161,7 +167,7 @@ int pm_suspend_disk(void)
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
if ((error = pmdisk_save()))
if ((error = swsusp_suspend()))
goto Done;
if (in_suspend) {
......@@ -173,14 +179,14 @@ int pm_suspend_disk(void)
mb();
barrier();
error = pmdisk_write();
error = swsusp_write();
if (!error) {
error = power_down(pm_disk_mode);
pr_debug("PM: Power down failed.\n");
}
} else
pr_debug("PM: Image restored successfully.\n");
pmdisk_free();
swsusp_free();
Done:
finish();
return error;
......@@ -188,7 +194,7 @@ int pm_suspend_disk(void)
/**
* pm_resume - Resume from a saved image.
* software_resume - Resume from a saved image.
*
* Called as a late_initcall (so all devices are discovered and
* initialized), we call pmdisk to see if we have a saved image or not.
......@@ -199,13 +205,21 @@ int pm_suspend_disk(void)
*
*/
static int pm_resume(void)
static int software_resume(void)
{
int error;
if (noresume) {
/**
* FIXME: If noresume is specified, we need to find the partition
* and reset it back to normal swap space.
*/
return 0;
}
pr_debug("PM: Reading pmdisk image.\n");
if ((error = pmdisk_read()))
if ((error = swsusp_read()))
goto Done;
pr_debug("PM: Preparing system for restore.\n");
......@@ -216,28 +230,18 @@ static int pm_resume(void)
barrier();
mb();
/* FIXME: The following (comment and mdelay()) are from swsusp.
* Are they really necessary?
*
* 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 ;-).
*/
pr_debug("PM: Waiting for DMAs to settle down.\n");
mdelay(1000);
pr_debug("PM: Restoring saved image.\n");
pmdisk_restore();
swsusp_resume();
pr_debug("PM: Restore failed, recovering.n");
finish();
Free:
pmdisk_free();
swsusp_free();
Done:
pr_debug("PM: Resume from disk failed.\n");
return 0;
}
late_initcall(pm_resume);
late_initcall(software_resume);
static char * pm_disk_modes[] = {
......@@ -336,3 +340,22 @@ static int __init pm_disk_init(void)
}
core_initcall(pm_disk_init);
static int __init resume_setup(char *str)
{
if (noresume)
return 1;
strncpy( resume_file, str, 255 );
return 1;
}
static int __init noresume_setup(char *str)
{
noresume = 1;
return 1;
}
__setup("noresume", noresume_setup);
__setup("resume=", resume_setup);
......@@ -169,6 +169,21 @@ static int enter_state(u32 state)
return error;
}
/*
* This is main interface to the outside world. It needs to be
* called from process context.
*/
int software_suspend(void)
{
int error;
if (down_trylock(&pm_sem))
return -EBUSY;
error = pm_suspend_disk();
up(&pm_sem);
return error;
}
/**
* pm_suspend - Externally visible function for suspending system.
......
This diff is collapsed.
#include <linux/suspend.h>
#include <linux/utsname.h>
/* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but
we probably do not take enough locks for switching consoles, etc,
......@@ -9,7 +10,20 @@
#endif
#ifdef CONFIG_PM_DISK
struct swsusp_info {
struct new_utsname uts;
u32 version_code;
unsigned long num_physpages;
int cpus;
unsigned long image_pages;
unsigned long pagedir_pages;
suspend_pagedir_t * suspend_pagedir;
swp_entry_t pagedir[768];
} __attribute__((aligned(PAGE_SIZE)));
#ifdef CONFIG_SOFTWARE_SUSPEND
extern int pm_suspend_disk(void);
#else
......@@ -18,7 +32,6 @@ static inline int pm_suspend_disk(void)
return -EPERM;
}
#endif
extern struct semaphore pm_sem;
#define power_attr(_name) \
static struct subsys_attribute _name##_attr = { \
......
This diff is collapsed.
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