Commit 9550cdcb authored by Patrick Mochel's avatar Patrick Mochel

Merge kernel.bkbits.net:linux-2.5-power

into osdl.org:/home/mochel/src/kernel/linux-2.5-power
parents add74a2b b866a7fc
......@@ -96,6 +96,7 @@ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/
drivers-$(CONFIG_PCI) += arch/i386/pci/
# must be linked after kernel/
drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/
drivers-$(CONFIG_PM) += arch/i386/power/
CFLAGS += $(mflags-y)
AFLAGS += $(mflags-y)
......
......@@ -17,9 +17,7 @@ obj-$(CONFIG_MCA) += mca.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_PM) += suspend.o
obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
obj-$(CONFIG_X86_MPPARSE) += mpparse.o
......
obj-$(CONFIG_PM) += cpu.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
......@@ -8,11 +8,10 @@
.text
ENTRY(do_magic)
ENTRY(swsusp_arch_suspend)
pushl %ebx
cmpl $0,8(%esp)
jne .L1450
call do_magic_suspend_1
call save_processor_state
movl %esp, saved_context_esp
......@@ -25,14 +24,13 @@ ENTRY(do_magic)
movl %edi, saved_context_edi
pushfl ; popl saved_context_eflags
call do_magic_suspend_2
call swsusp_suspend
jmp .L1449
.p2align 4,,7
.L1450:
movl $swapper_pg_dir-__PAGE_OFFSET,%ecx
movl %ecx,%cr3
call do_magic_resume_1
movl $0,loop
cmpl $0,nr_copy_pages
je .L1453
......@@ -80,7 +78,7 @@ ENTRY(do_magic)
movl saved_context_edi, %edi
call restore_processor_state
pushl saved_context_eflags ; popfl
call do_magic_resume_2
call swsusp_resume
.L1449:
popl %ebx
ret
......
......@@ -6,11 +6,12 @@
#include <asm/desc.h>
#include <asm/i387.h>
static inline void
static inline int
arch_prepare_suspend(void)
{
if (!cpu_has_pse)
panic("pse required");
return -EPERM;
return 0;
}
/* image of the saved processor state */
......@@ -38,8 +39,6 @@ struct saved_context {
extern void save_processor_state(void);
extern void restore_processor_state(void);
extern int do_magic(int resume);
#ifdef CONFIG_ACPI_SLEEP
extern unsigned long saved_eip;
extern unsigned long saved_esp;
......
......@@ -8,7 +8,7 @@
#include <linux/kbd_kern.h>
#include "power.h"
static int new_loglevel = 7;
static int new_loglevel = 10;
static int orig_loglevel;
static int orig_fgconsole, orig_kmsg;
......
......@@ -8,10 +8,13 @@
*
*/
#define DEBUG
#include <linux/suspend.h>
#include <linux/kobject.h>
#include <linux/reboot.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pm.h>
......@@ -122,12 +125,9 @@ static int power_down(u32 mode)
switch(mode) {
case PM_DISK_PLATFORM:
error = pm_ops->enter(PM_SUSPEND_DISK);
if (error) {
device_power_up();
local_irq_restore(flags);
return error;
}
break;
case PM_DISK_SHUTDOWN:
printk("Powering off system\n");
machine_power_off();
break;
case PM_DISK_REBOOT:
......@@ -135,6 +135,8 @@ static int power_down(u32 mode)
break;
}
machine_halt();
device_power_up();
local_irq_restore(flags);
return 0;
}
......@@ -183,11 +185,19 @@ static int pm_suspend_disk(void)
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
local_irq_disable();
if ((error = swsusp_save()))
goto Done;
if (in_suspend) {
pr_debug("PM: writing image.\n");
/*
* FIXME: Leftover from swsusp. Are they necessary?
*/
mb();
barrier();
error = swsusp_write();
if (!error)
error = power_down(pm_disk_mode);
......@@ -196,6 +206,7 @@ static int pm_suspend_disk(void)
pr_debug("PM: Image restored successfully.\n");
swsusp_free();
Done:
local_irq_enable();
return error;
}
......@@ -304,7 +315,7 @@ static int enter_state(u32 state)
goto Unlock;
}
pr_debug("PM: Preparing system for suspend.\n");
pr_debug("PM: Preparing system for suspend\n");
if ((error = suspend_prepare(state)))
goto Unlock;
......@@ -364,9 +375,23 @@ static int pm_resume(void)
if ((error = suspend_prepare(PM_SUSPEND_DISK)))
goto Free;
barrier();
mb();
local_irq_disable();
/* 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");
swsusp_restore();
local_irq_enable();
pr_debug("PM: Restore failed, recovering.n");
suspend_finish(PM_SUSPEND_DISK);
Free:
......@@ -480,27 +505,28 @@ power_attr(disk);
static ssize_t state_show(struct subsystem * subsys, char * buf)
{
struct pm_state * state;
int i;
char * s = buf;
for (state = &pm_states[0]; state->name; state++)
s += sprintf(s,"%s ",state->name);
for (i = 0; i < PM_SUSPEND_MAX; i++) {
if (pm_states[i].name)
s += sprintf(s,"%s ",pm_states[i].name);
}
s += sprintf(s,"\n");
return (s - buf);
}
static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
{
u32 state;
u32 state = PM_SUSPEND_STANDBY;
struct pm_state * s;
int error;
for (state = 0; state < PM_SUSPEND_MAX; state++) {
s = &pm_states[state];
if (s->name && !strcmp(buf,s->name))
for (s = &pm_states[state]; s->name; s++, state++) {
if (!strcmp(buf,s->name))
break;
}
if (s)
if (s->name)
error = enter_state(state);
else
error = -EINVAL;
......
......@@ -34,38 +34,21 @@
* For TODOs,FIXMEs also look in Documentation/swsusp.txt
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/suspend.h>
#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/bitops.h>
#include <linux/vt_kern.h>
#include <linux/kbd_kern.h>
#include <linux/keyboard.h>
#include <linux/spinlock.h>
#include <linux/genhd.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/swap.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/buffer_head.h>
#include <linux/swapops.h>
#include <linux/bootmem.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include "power.h"
unsigned char software_suspend_enabled = 1;
extern int swsusp_arch_suspend(int resume);
#define __ADDRESS(x) ((unsigned long) phys_to_virt(x))
#define ADDRESS(x) __ADDRESS((x) << PAGE_SHIFT)
......@@ -76,9 +59,6 @@ extern char __nosave_begin, __nosave_end;
extern int is_head_of_free_region(struct page *);
/* Locks */
spinlock_t suspend_pagedir_lock __nosavedata = SPIN_LOCK_UNLOCKED;
/* Variables to be preserved over suspend */
static int pagedir_order_check;
static int nr_copy_pages_check;
......@@ -488,21 +468,30 @@ static int suspend_prepare_image(void)
return 0;
}
/**
* suspend_save_image - Prepare and write saved image to swap.
*
* IRQs are re-enabled here so we can resume devices and safely write
* to the swap devices. We disable them again before we leave.
*
* The second lock_swapdevices() will unlock ignored swap devices since
* writing is finished.
* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/
static int suspend_save_image(void)
{
int error;
local_irq_enable();
device_resume();
lock_swapdevices();
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
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/
lock_swapdevices();
local_irq_disable();
return error;
}
......@@ -510,66 +499,49 @@ static int suspend_save_image(void)
* Magic happens here
*/
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");
/* 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)
int swsusp_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();
spin_unlock_irq(&suspend_pagedir_lock);
return 0;
}
/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically does:
/* swsusp_arch_suspend() is implemented in arch/?/power/swsusp.S,
and basically does:
if (!resume) {
do_magic_suspend_1();
save_processor_state();
SAVE_REGISTERS
do_magic_suspend_2();
swsusp_suspend();
return;
}
GO_TO_SWAPPER_PAGE_TABLES
do_magic_resume_1();
COPY_PAGES_BACK
RESTORE_REGISTERS
restore_processor_state();
do_magic_resume_2();
swsusp_resume();
*/
void do_magic_suspend_1(void)
{
mb();
barrier();
spin_lock_irq(&suspend_pagedir_lock);
}
int do_magic_suspend_2(void)
int swsusp_suspend(void)
{
int is_problem;
int error;
read_swapfiles();
is_problem = suspend_prepare_image();
spin_unlock_irq(&suspend_pagedir_lock);
if (!is_problem)
return suspend_save_image();
printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend);
error = suspend_prepare_image();
if (!error)
error = suspend_save_image();
if (error) {
printk(KERN_EMERG "%sSuspend failed, trying to recover...\n",
name_suspend);
barrier();
mb();
mdelay(1000);
return -EFAULT;
}
return error;
}
/* More restore stuff */
......@@ -806,24 +778,23 @@ int swsusp_save(void)
printk("swsusp is not supported with high- or discontig-mem.\n");
return -EPERM;
#endif
return 0;
return arch_prepare_suspend();
}
/**
* swsusp_write - Write saved memory image to swap.
*
* do_magic(0) returns after system is resumed.
* swsusp_arch_suspend(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
* swsusp_arch_suspend() copies all "used" memory to "free" memory,
* then unsuspends all device drivers, and writes memory to disk
* using normal kernel mechanism.
*/
int swsusp_write(void)
{
arch_prepare_suspend();
return do_magic(0);
return swsusp_arch_suspend(0);
}
......@@ -873,7 +844,7 @@ int __init swsusp_read(void)
int __init swsusp_restore(void)
{
return do_magic(1);
return swsusp_arch_suspend(1);
}
......
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