aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/Kconfig8
-rw-r--r--kernel/power/Makefile6
-rw-r--r--kernel/power/disk.c56
-rw-r--r--kernel/power/main.c32
-rw-r--r--kernel/power/poweroff.c4
-rw-r--r--kernel/power/process.c30
-rw-r--r--kernel/power/smp.c89
-rw-r--r--kernel/power/swsusp.c131
8 files changed, 167 insertions, 189 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 696387ffe49c..2c7121d9bff1 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -27,8 +27,8 @@ config PM_DEBUG
27 like suspend support. 27 like suspend support.
28 28
29config SOFTWARE_SUSPEND 29config SOFTWARE_SUSPEND
30 bool "Software Suspend (EXPERIMENTAL)" 30 bool "Software Suspend"
31 depends on EXPERIMENTAL && PM && SWAP 31 depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP))
32 ---help--- 32 ---help---
33 Enable the possibility of suspending the machine. 33 Enable the possibility of suspending the machine.
34 It doesn't need APM. 34 It doesn't need APM.
@@ -72,3 +72,7 @@ config PM_STD_PARTITION
72 suspended image to. It will simply pick the first available swap 72 suspended image to. It will simply pick the first available swap
73 device. 73 device.
74 74
75config SUSPEND_SMP
76 bool
77 depends on HOTPLUG_CPU && X86 && PM
78 default y
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index fbdc634135a7..2f438d0eaa13 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -3,9 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y)
3EXTRA_CFLAGS += -DDEBUG 3EXTRA_CFLAGS += -DDEBUG
4endif 4endif
5 5
6swsusp-smp-$(CONFIG_SMP) += smp.o
7
8obj-y := main.o process.o console.o pm.o 6obj-y := main.o process.o console.o pm.o
9obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o 7obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o
8
9obj-$(CONFIG_SUSPEND_SMP) += smp.o
10 10
11obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o 11obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 02b6764034dc..664eb0469b6e 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -16,6 +16,8 @@
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/delay.h> 17#include <linux/delay.h>
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/mount.h>
20
19#include "power.h" 21#include "power.h"
20 22
21 23
@@ -57,16 +59,13 @@ static void power_down(suspend_disk_method_t mode)
57 error = pm_ops->enter(PM_SUSPEND_DISK); 59 error = pm_ops->enter(PM_SUSPEND_DISK);
58 break; 60 break;
59 case PM_DISK_SHUTDOWN: 61 case PM_DISK_SHUTDOWN:
60 printk("Powering off system\n"); 62 kernel_power_off();
61 device_shutdown();
62 machine_power_off();
63 break; 63 break;
64 case PM_DISK_REBOOT: 64 case PM_DISK_REBOOT:
65 device_shutdown(); 65 kernel_restart(NULL);
66 machine_restart(NULL);
67 break; 66 break;
68 } 67 }
69 machine_halt(); 68 kernel_halt();
70 /* Valid image is on the disk, if we continue we risk serious data corruption 69 /* Valid image is on the disk, if we continue we risk serious data corruption
71 after resume. */ 70 after resume. */
72 printk(KERN_CRIT "Please power me down manually\n"); 71 printk(KERN_CRIT "Please power me down manually\n");
@@ -117,8 +116,8 @@ static void finish(void)
117{ 116{
118 device_resume(); 117 device_resume();
119 platform_finish(); 118 platform_finish();
120 enable_nonboot_cpus();
121 thaw_processes(); 119 thaw_processes();
120 enable_nonboot_cpus();
122 pm_restore_console(); 121 pm_restore_console();
123} 122}
124 123
@@ -131,28 +130,35 @@ static int prepare_processes(void)
131 130
132 sys_sync(); 131 sys_sync();
133 132
133 disable_nonboot_cpus();
134
134 if (freeze_processes()) { 135 if (freeze_processes()) {
135 error = -EBUSY; 136 error = -EBUSY;
136 return error; 137 goto thaw;
137 } 138 }
138 139
139 if (pm_disk_mode == PM_DISK_PLATFORM) { 140 if (pm_disk_mode == PM_DISK_PLATFORM) {
140 if (pm_ops && pm_ops->prepare) { 141 if (pm_ops && pm_ops->prepare) {
141 if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) 142 if ((error = pm_ops->prepare(PM_SUSPEND_DISK)))
142 return error; 143 goto thaw;
143 } 144 }
144 } 145 }
145 146
146 /* Free memory before shutting down devices. */ 147 /* Free memory before shutting down devices. */
147 free_some_memory(); 148 free_some_memory();
148
149 return 0; 149 return 0;
150thaw:
151 thaw_processes();
152 enable_nonboot_cpus();
153 pm_restore_console();
154 return error;
150} 155}
151 156
152static void unprepare_processes(void) 157static void unprepare_processes(void)
153{ 158{
154 enable_nonboot_cpus(); 159 platform_finish();
155 thaw_processes(); 160 thaw_processes();
161 enable_nonboot_cpus();
156 pm_restore_console(); 162 pm_restore_console();
157} 163}
158 164
@@ -160,15 +166,9 @@ static int prepare_devices(void)
160{ 166{
161 int error; 167 int error;
162 168
163 disable_nonboot_cpus(); 169 if ((error = device_suspend(PMSG_FREEZE)))
164 if ((error = device_suspend(PMSG_FREEZE))) {
165 printk("Some devices failed to suspend\n"); 170 printk("Some devices failed to suspend\n");
166 platform_finish(); 171 return error;
167 enable_nonboot_cpus();
168 return error;
169 }
170
171 return 0;
172} 172}
173 173
174/** 174/**
@@ -185,9 +185,9 @@ int pm_suspend_disk(void)
185 int error; 185 int error;
186 186
187 error = prepare_processes(); 187 error = prepare_processes();
188 if (!error) { 188 if (error)
189 error = prepare_devices(); 189 return error;
190 } 190 error = prepare_devices();
191 191
192 if (error) { 192 if (error) {
193 unprepare_processes(); 193 unprepare_processes();
@@ -233,6 +233,16 @@ static int software_resume(void)
233{ 233{
234 int error; 234 int error;
235 235
236 if (!swsusp_resume_device) {
237 if (!strlen(resume_file))
238 return -ENOENT;
239 swsusp_resume_device = name_to_dev_t(resume_file);
240 pr_debug("swsusp: Resume From Partition %s\n", resume_file);
241 } else {
242 pr_debug("swsusp: Resume From Partition %d:%d\n",
243 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
244 }
245
236 if (noresume) { 246 if (noresume) {
237 /** 247 /**
238 * FIXME: If noresume is specified, we need to find the partition 248 * FIXME: If noresume is specified, we need to find the partition
@@ -250,7 +260,7 @@ static int software_resume(void)
250 260
251 if ((error = prepare_processes())) { 261 if ((error = prepare_processes())) {
252 swsusp_close(); 262 swsusp_close();
253 goto Cleanup; 263 goto Done;
254 } 264 }
255 265
256 pr_debug("PM: Reading swsusp image.\n"); 266 pr_debug("PM: Reading swsusp image.\n");
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 4cdebc972ff2..71aa0fd22007 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -19,6 +19,9 @@
19 19
20#include "power.h" 20#include "power.h"
21 21
22/*This is just an arbitrary number */
23#define FREE_PAGE_NUMBER (100)
24
22DECLARE_MUTEX(pm_sem); 25DECLARE_MUTEX(pm_sem);
23 26
24struct pm_ops * pm_ops = NULL; 27struct pm_ops * pm_ops = NULL;
@@ -49,17 +52,35 @@ void pm_set_ops(struct pm_ops * ops)
49static int suspend_prepare(suspend_state_t state) 52static int suspend_prepare(suspend_state_t state)
50{ 53{
51 int error = 0; 54 int error = 0;
55 unsigned int free_pages;
52 56
53 if (!pm_ops || !pm_ops->enter) 57 if (!pm_ops || !pm_ops->enter)
54 return -EPERM; 58 return -EPERM;
55 59
56 pm_prepare_console(); 60 pm_prepare_console();
57 61
62 disable_nonboot_cpus();
63
64 if (num_online_cpus() != 1) {
65 error = -EPERM;
66 goto Enable_cpu;
67 }
68
58 if (freeze_processes()) { 69 if (freeze_processes()) {
59 error = -EAGAIN; 70 error = -EAGAIN;
60 goto Thaw; 71 goto Thaw;
61 } 72 }
62 73
74 if ((free_pages = nr_free_pages()) < FREE_PAGE_NUMBER) {
75 pr_debug("PM: free some memory\n");
76 shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
77 if (nr_free_pages() < FREE_PAGE_NUMBER) {
78 error = -ENOMEM;
79 printk(KERN_ERR "PM: No enough memory\n");
80 goto Thaw;
81 }
82 }
83
63 if (pm_ops->prepare) { 84 if (pm_ops->prepare) {
64 if ((error = pm_ops->prepare(state))) 85 if ((error = pm_ops->prepare(state)))
65 goto Thaw; 86 goto Thaw;
@@ -75,6 +96,8 @@ static int suspend_prepare(suspend_state_t state)
75 pm_ops->finish(state); 96 pm_ops->finish(state);
76 Thaw: 97 Thaw:
77 thaw_processes(); 98 thaw_processes();
99 Enable_cpu:
100 enable_nonboot_cpus();
78 pm_restore_console(); 101 pm_restore_console();
79 return error; 102 return error;
80} 103}
@@ -113,6 +136,7 @@ static void suspend_finish(suspend_state_t state)
113 if (pm_ops && pm_ops->finish) 136 if (pm_ops && pm_ops->finish)
114 pm_ops->finish(state); 137 pm_ops->finish(state);
115 thaw_processes(); 138 thaw_processes();
139 enable_nonboot_cpus();
116 pm_restore_console(); 140 pm_restore_console();
117} 141}
118 142
@@ -150,12 +174,6 @@ static int enter_state(suspend_state_t state)
150 goto Unlock; 174 goto Unlock;
151 } 175 }
152 176
153 /* Suspend is hard to get right on SMP. */
154 if (num_online_cpus() != 1) {
155 error = -EPERM;
156 goto Unlock;
157 }
158
159 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 177 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
160 if ((error = suspend_prepare(state))) 178 if ((error = suspend_prepare(state)))
161 goto Unlock; 179 goto Unlock;
@@ -190,7 +208,7 @@ int software_suspend(void)
190 208
191int pm_suspend(suspend_state_t state) 209int pm_suspend(suspend_state_t state)
192{ 210{
193 if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) 211 if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
194 return enter_state(state); 212 return enter_state(state);
195 return -EINVAL; 213 return -EINVAL;
196} 214}
diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c
index 715081b2d829..7a4144ba3afd 100644
--- a/kernel/power/poweroff.c
+++ b/kernel/power/poweroff.c
@@ -9,6 +9,7 @@
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/pm.h> 10#include <linux/pm.h>
11#include <linux/workqueue.h> 11#include <linux/workqueue.h>
12#include <linux/reboot.h>
12 13
13/* 14/*
14 * When the user hits Sys-Rq o to power down the machine this is the 15 * When the user hits Sys-Rq o to power down the machine this is the
@@ -17,8 +18,7 @@
17 18
18static void do_poweroff(void *dummy) 19static void do_poweroff(void *dummy)
19{ 20{
20 if (pm_power_off) 21 kernel_power_off();
21 pm_power_off();
22} 22}
23 23
24static DECLARE_WORK(poweroff_work, do_poweroff, NULL); 24static DECLARE_WORK(poweroff_work, do_poweroff, NULL);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 78d92dc6a1ed..3bd0d261818f 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -32,7 +32,7 @@ static inline int freezeable(struct task_struct * p)
32} 32}
33 33
34/* Refrigerator is place where frozen processes are stored :-). */ 34/* Refrigerator is place where frozen processes are stored :-). */
35void refrigerator(unsigned long flag) 35void refrigerator(void)
36{ 36{
37 /* Hmm, should we be allowed to suspend when there are realtime 37 /* Hmm, should we be allowed to suspend when there are realtime
38 processes around? */ 38 processes around? */
@@ -41,14 +41,13 @@ void refrigerator(unsigned long flag)
41 current->state = TASK_UNINTERRUPTIBLE; 41 current->state = TASK_UNINTERRUPTIBLE;
42 pr_debug("%s entered refrigerator\n", current->comm); 42 pr_debug("%s entered refrigerator\n", current->comm);
43 printk("="); 43 printk("=");
44 current->flags &= ~PF_FREEZE;
45 44
45 frozen_process(current);
46 spin_lock_irq(&current->sighand->siglock); 46 spin_lock_irq(&current->sighand->siglock);
47 recalc_sigpending(); /* We sent fake signal, clean it up */ 47 recalc_sigpending(); /* We sent fake signal, clean it up */
48 spin_unlock_irq(&current->sighand->siglock); 48 spin_unlock_irq(&current->sighand->siglock);
49 49
50 current->flags |= PF_FROZEN; 50 while (frozen(current))
51 while (current->flags & PF_FROZEN)
52 schedule(); 51 schedule();
53 pr_debug("%s left refrigerator\n", current->comm); 52 pr_debug("%s left refrigerator\n", current->comm);
54 current->state = save; 53 current->state = save;
@@ -57,27 +56,23 @@ void refrigerator(unsigned long flag)
57/* 0 = success, else # of processes that we failed to stop */ 56/* 0 = success, else # of processes that we failed to stop */
58int freeze_processes(void) 57int freeze_processes(void)
59{ 58{
60 int todo; 59 int todo;
61 unsigned long start_time; 60 unsigned long start_time;
62 struct task_struct *g, *p; 61 struct task_struct *g, *p;
63 62 unsigned long flags;
63
64 printk( "Stopping tasks: " ); 64 printk( "Stopping tasks: " );
65 start_time = jiffies; 65 start_time = jiffies;
66 do { 66 do {
67 todo = 0; 67 todo = 0;
68 read_lock(&tasklist_lock); 68 read_lock(&tasklist_lock);
69 do_each_thread(g, p) { 69 do_each_thread(g, p) {
70 unsigned long flags;
71 if (!freezeable(p)) 70 if (!freezeable(p))
72 continue; 71 continue;
73 if ((p->flags & PF_FROZEN) || 72 if (frozen(p))
74 (p->state == TASK_TRACED) ||
75 (p->state == TASK_STOPPED))
76 continue; 73 continue;
77 74
78 /* FIXME: smp problem here: we may not access other process' flags 75 freeze(p);
79 without locking */
80 p->flags |= PF_FREEZE;
81 spin_lock_irqsave(&p->sighand->siglock, flags); 76 spin_lock_irqsave(&p->sighand->siglock, flags);
82 signal_wake_up(p, 0); 77 signal_wake_up(p, 0);
83 spin_unlock_irqrestore(&p->sighand->siglock, flags); 78 spin_unlock_irqrestore(&p->sighand->siglock, flags);
@@ -91,7 +86,7 @@ int freeze_processes(void)
91 return todo; 86 return todo;
92 } 87 }
93 } while(todo); 88 } while(todo);
94 89
95 printk( "|\n" ); 90 printk( "|\n" );
96 BUG_ON(in_atomic()); 91 BUG_ON(in_atomic());
97 return 0; 92 return 0;
@@ -106,10 +101,7 @@ void thaw_processes(void)
106 do_each_thread(g, p) { 101 do_each_thread(g, p) {
107 if (!freezeable(p)) 102 if (!freezeable(p))
108 continue; 103 continue;
109 if (p->flags & PF_FROZEN) { 104 if (!thaw_process(p))
110 p->flags &= ~PF_FROZEN;
111 wake_up_process(p);
112 } else
113 printk(KERN_INFO " Strange, %s not stopped\n", p->comm ); 105 printk(KERN_INFO " Strange, %s not stopped\n", p->comm );
114 } while_each_thread(g, p); 106 } while_each_thread(g, p);
115 107
diff --git a/kernel/power/smp.c b/kernel/power/smp.c
index 457c2302ed42..911fc62b8225 100644
--- a/kernel/power/smp.c
+++ b/kernel/power/smp.c
@@ -13,73 +13,52 @@
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/suspend.h> 14#include <linux/suspend.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/cpu.h>
16#include <asm/atomic.h> 17#include <asm/atomic.h>
17#include <asm/tlbflush.h> 18#include <asm/tlbflush.h>
18 19
19static atomic_t cpu_counter, freeze; 20/* This is protected by pm_sem semaphore */
20 21static cpumask_t frozen_cpus;
21
22static void smp_pause(void * data)
23{
24 struct saved_context ctxt;
25 __save_processor_state(&ctxt);
26 printk("Sleeping in:\n");
27 dump_stack();
28 atomic_inc(&cpu_counter);
29 while (atomic_read(&freeze)) {
30 /* FIXME: restore takes place at random piece inside this.
31 This should probably be written in assembly, and
32 preserve general-purpose registers, too
33
34 What about stack? We may need to move to new stack here.
35
36 This should better be ran with interrupts disabled.
37 */
38 cpu_relax();
39 barrier();
40 }
41 atomic_dec(&cpu_counter);
42 __restore_processor_state(&ctxt);
43}
44
45static cpumask_t oldmask;
46 22
47void disable_nonboot_cpus(void) 23void disable_nonboot_cpus(void)
48{ 24{
49 oldmask = current->cpus_allowed; 25 int cpu, error;
50 set_cpus_allowed(current, cpumask_of_cpu(0));
51 printk("Freezing CPUs (at %d)", raw_smp_processor_id());
52 current->state = TASK_INTERRUPTIBLE;
53 schedule_timeout(HZ);
54 printk("...");
55 BUG_ON(raw_smp_processor_id() != 0);
56 26
57 /* FIXME: for this to work, all the CPUs must be running 27 error = 0;
58 * "idle" thread (or we deadlock). Is that guaranteed? */ 28 cpus_clear(frozen_cpus);
59 29 printk("Freezing cpus ...\n");
60 atomic_set(&cpu_counter, 0); 30 for_each_online_cpu(cpu) {
61 atomic_set(&freeze, 1); 31 if (cpu == 0)
62 smp_call_function(smp_pause, NULL, 0, 0); 32 continue;
63 while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) { 33 error = cpu_down(cpu);
64 cpu_relax(); 34 if (!error) {
65 barrier(); 35 cpu_set(cpu, frozen_cpus);
36 printk("CPU%d is down\n", cpu);
37 continue;
38 }
39 printk("Error taking cpu %d down: %d\n", cpu, error);
66 } 40 }
67 printk("ok\n"); 41 BUG_ON(raw_smp_processor_id() != 0);
42 if (error)
43 panic("cpus not sleeping");
68} 44}
69 45
70void enable_nonboot_cpus(void) 46void enable_nonboot_cpus(void)
71{ 47{
72 printk("Restarting CPUs"); 48 int cpu, error;
73 atomic_set(&freeze, 0);
74 while (atomic_read(&cpu_counter)) {
75 cpu_relax();
76 barrier();
77 }
78 printk("...");
79 set_cpus_allowed(current, oldmask);
80 schedule();
81 printk("ok\n");
82 49
50 printk("Thawing cpus ...\n");
51 for_each_cpu_mask(cpu, frozen_cpus) {
52 error = smp_prepare_cpu(cpu);
53 if (!error)
54 error = cpu_up(cpu);
55 if (!error) {
56 printk("CPU%d is up\n", cpu);
57 continue;
58 }
59 printk("Error taking cpu %d up: %d\n", cpu, error);
60 panic("Not enough cpus");
61 }
62 cpus_clear(frozen_cpus);
83} 63}
84 64
85
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 90b3b68dee3f..f2bc71b9fe8b 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -10,12 +10,12 @@
10 * This file is released under the GPLv2. 10 * This file is released under the GPLv2.
11 * 11 *
12 * I'd like to thank the following people for their work: 12 * I'd like to thank the following people for their work:
13 * 13 *
14 * Pavel Machek <pavel@ucw.cz>: 14 * Pavel Machek <pavel@ucw.cz>:
15 * Modifications, defectiveness pointing, being with me at the very beginning, 15 * Modifications, defectiveness pointing, being with me at the very beginning,
16 * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. 16 * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
17 * 17 *
18 * Steve Doddi <dirk@loth.demon.co.uk>: 18 * Steve Doddi <dirk@loth.demon.co.uk>:
19 * Support the possibility of hardware state restoring. 19 * Support the possibility of hardware state restoring.
20 * 20 *
21 * Raph <grey.havens@earthling.net>: 21 * Raph <grey.havens@earthling.net>:
@@ -63,6 +63,7 @@
63#include <linux/console.h> 63#include <linux/console.h>
64#include <linux/highmem.h> 64#include <linux/highmem.h>
65#include <linux/bio.h> 65#include <linux/bio.h>
66#include <linux/mount.h>
66 67
67#include <asm/uaccess.h> 68#include <asm/uaccess.h>
68#include <asm/mmu_context.h> 69#include <asm/mmu_context.h>
@@ -81,14 +82,14 @@ static int nr_copy_pages_check;
81extern char resume_file[]; 82extern char resume_file[];
82 83
83/* Local variables that should not be affected by save */ 84/* Local variables that should not be affected by save */
84unsigned int nr_copy_pages __nosavedata = 0; 85static unsigned int nr_copy_pages __nosavedata = 0;
85 86
86/* Suspend pagedir is allocated before final copy, therefore it 87/* Suspend pagedir is allocated before final copy, therefore it
87 must be freed after resume 88 must be freed after resume
88 89
89 Warning: this is evil. There are actually two pagedirs at time of 90 Warning: this is evil. There are actually two pagedirs at time of
90 resume. One is "pagedir_save", which is empty frame allocated at 91 resume. One is "pagedir_save", which is empty frame allocated at
91 time of suspend, that must be freed. Second is "pagedir_nosave", 92 time of suspend, that must be freed. Second is "pagedir_nosave",
92 allocated at time of resume, that travels through memory not to 93 allocated at time of resume, that travels through memory not to
93 collide with anything. 94 collide with anything.
94 95
@@ -132,7 +133,7 @@ static int mark_swapfiles(swp_entry_t prev)
132{ 133{
133 int error; 134 int error;
134 135
135 rw_swap_page_sync(READ, 136 rw_swap_page_sync(READ,
136 swp_entry(root_swap, 0), 137 swp_entry(root_swap, 0),
137 virt_to_page((unsigned long)&swsusp_header)); 138 virt_to_page((unsigned long)&swsusp_header));
138 if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || 139 if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
@@ -140,7 +141,7 @@ static int mark_swapfiles(swp_entry_t prev)
140 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); 141 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
141 memcpy(swsusp_header.sig,SWSUSP_SIG, 10); 142 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
142 swsusp_header.swsusp_info = prev; 143 swsusp_header.swsusp_info = prev;
143 error = rw_swap_page_sync(WRITE, 144 error = rw_swap_page_sync(WRITE,
144 swp_entry(root_swap, 0), 145 swp_entry(root_swap, 0),
145 virt_to_page((unsigned long) 146 virt_to_page((unsigned long)
146 &swsusp_header)); 147 &swsusp_header));
@@ -174,22 +175,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info)
174static int swsusp_swap_check(void) /* This is called before saving image */ 175static int swsusp_swap_check(void) /* This is called before saving image */
175{ 176{
176 int i, len; 177 int i, len;
177 178
178 len=strlen(resume_file); 179 len=strlen(resume_file);
179 root_swap = 0xFFFF; 180 root_swap = 0xFFFF;
180 181
181 swap_list_lock(); 182 swap_list_lock();
182 for(i=0; i<MAX_SWAPFILES; i++) { 183 for (i=0; i<MAX_SWAPFILES; i++) {
183 if (swap_info[i].flags == 0) { 184 if (swap_info[i].flags == 0) {
184 swapfile_used[i]=SWAPFILE_UNUSED; 185 swapfile_used[i]=SWAPFILE_UNUSED;
185 } else { 186 } else {
186 if(!len) { 187 if (!len) {
187 printk(KERN_WARNING "resume= option should be used to set suspend device" ); 188 printk(KERN_WARNING "resume= option should be used to set suspend device" );
188 if(root_swap == 0xFFFF) { 189 if (root_swap == 0xFFFF) {
189 swapfile_used[i] = SWAPFILE_SUSPEND; 190 swapfile_used[i] = SWAPFILE_SUSPEND;
190 root_swap = i; 191 root_swap = i;
191 } else 192 } else
192 swapfile_used[i] = SWAPFILE_IGNORED; 193 swapfile_used[i] = SWAPFILE_IGNORED;
193 } else { 194 } else {
194 /* we ignore all swap devices that are not the resume_file */ 195 /* we ignore all swap devices that are not the resume_file */
195 if (is_resume_device(&swap_info[i])) { 196 if (is_resume_device(&swap_info[i])) {
@@ -209,15 +210,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */
209 * This is called after saving image so modification 210 * This is called after saving image so modification
210 * will be lost after resume... and that's what we want. 211 * will be lost after resume... and that's what we want.
211 * we make the device unusable. A new call to 212 * we make the device unusable. A new call to
212 * lock_swapdevices can unlock the devices. 213 * lock_swapdevices can unlock the devices.
213 */ 214 */
214static void lock_swapdevices(void) 215static void lock_swapdevices(void)
215{ 216{
216 int i; 217 int i;
217 218
218 swap_list_lock(); 219 swap_list_lock();
219 for(i = 0; i< MAX_SWAPFILES; i++) 220 for (i = 0; i< MAX_SWAPFILES; i++)
220 if(swapfile_used[i] == SWAPFILE_IGNORED) { 221 if (swapfile_used[i] == SWAPFILE_IGNORED) {
221 swap_info[i].flags ^= 0xFF; 222 swap_info[i].flags ^= 0xFF;
222 } 223 }
223 swap_list_unlock(); 224 swap_list_unlock();
@@ -229,7 +230,7 @@ static void lock_swapdevices(void)
229 * @loc: Place to store the entry we used. 230 * @loc: Place to store the entry we used.
230 * 231 *
231 * Allocate a new swap entry and 'sync' it. Note we discard -EIO 232 * Allocate a new swap entry and 'sync' it. Note we discard -EIO
232 * errors. That is an artifact left over from swsusp. It did not 233 * errors. That is an artifact left over from swsusp. It did not
233 * check the return of rw_swap_page_sync() at all, since most pages 234 * check the return of rw_swap_page_sync() at all, since most pages
234 * written back to swap would return -EIO. 235 * written back to swap would return -EIO.
235 * This is a partial improvement, since we will at least return other 236 * This is a partial improvement, since we will at least return other
@@ -241,7 +242,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
241 int error = 0; 242 int error = 0;
242 243
243 entry = get_swap_page(); 244 entry = get_swap_page();
244 if (swp_offset(entry) && 245 if (swp_offset(entry) &&
245 swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { 246 swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
246 error = rw_swap_page_sync(WRITE, entry, 247 error = rw_swap_page_sync(WRITE, entry,
247 virt_to_page(addr)); 248 virt_to_page(addr));
@@ -257,7 +258,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
257/** 258/**
258 * data_free - Free the swap entries used by the saved image. 259 * data_free - Free the swap entries used by the saved image.
259 * 260 *
260 * Walk the list of used swap entries and free each one. 261 * Walk the list of used swap entries and free each one.
261 * This is only used for cleanup when suspend fails. 262 * This is only used for cleanup when suspend fails.
262 */ 263 */
263static void data_free(void) 264static void data_free(void)
@@ -290,7 +291,7 @@ static int data_write(void)
290 mod = 1; 291 mod = 1;
291 292
292 printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); 293 printk( "Writing data to swap (%d pages)... ", nr_copy_pages );
293 for_each_pbe(p, pagedir_nosave) { 294 for_each_pbe (p, pagedir_nosave) {
294 if (!(i%mod)) 295 if (!(i%mod))
295 printk( "\b\b\b\b%3d%%", i / mod ); 296 printk( "\b\b\b\b%3d%%", i / mod );
296 if ((error = write_page(p->address, &(p->swap_address)))) 297 if ((error = write_page(p->address, &(p->swap_address))))
@@ -335,7 +336,7 @@ static int close_swap(void)
335 336
336 dump_info(); 337 dump_info();
337 error = write_page((unsigned long)&swsusp_info, &entry); 338 error = write_page((unsigned long)&swsusp_info, &entry);
338 if (!error) { 339 if (!error) {
339 printk( "S" ); 340 printk( "S" );
340 error = mark_swapfiles(entry); 341 error = mark_swapfiles(entry);
341 printk( "|\n" ); 342 printk( "|\n" );
@@ -370,7 +371,7 @@ static int write_pagedir(void)
370 struct pbe * pbe; 371 struct pbe * pbe;
371 372
372 printk( "Writing pagedir..."); 373 printk( "Writing pagedir...");
373 for_each_pb_page(pbe, pagedir_nosave) { 374 for_each_pb_page (pbe, pagedir_nosave) {
374 if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) 375 if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++])))
375 return error; 376 return error;
376 } 377 }
@@ -472,7 +473,7 @@ static int save_highmem(void)
472 int res = 0; 473 int res = 0;
473 474
474 pr_debug("swsusp: Saving Highmem\n"); 475 pr_debug("swsusp: Saving Highmem\n");
475 for_each_zone(zone) { 476 for_each_zone (zone) {
476 if (is_highmem(zone)) 477 if (is_highmem(zone))
477 res = save_highmem_zone(zone); 478 res = save_highmem_zone(zone);
478 if (res) 479 if (res)
@@ -547,7 +548,7 @@ static void count_data_pages(void)
547 548
548 nr_copy_pages = 0; 549 nr_copy_pages = 0;
549 550
550 for_each_zone(zone) { 551 for_each_zone (zone) {
551 if (is_highmem(zone)) 552 if (is_highmem(zone))
552 continue; 553 continue;
553 mark_free_pages(zone); 554 mark_free_pages(zone);
@@ -562,9 +563,9 @@ static void copy_data_pages(void)
562 struct zone *zone; 563 struct zone *zone;
563 unsigned long zone_pfn; 564 unsigned long zone_pfn;
564 struct pbe * pbe = pagedir_nosave; 565 struct pbe * pbe = pagedir_nosave;
565 566
566 pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); 567 pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages);
567 for_each_zone(zone) { 568 for_each_zone (zone) {
568 if (is_highmem(zone)) 569 if (is_highmem(zone))
569 continue; 570 continue;
570 mark_free_pages(zone); 571 mark_free_pages(zone);
@@ -702,7 +703,7 @@ static void free_image_pages(void)
702{ 703{
703 struct pbe * p; 704 struct pbe * p;
704 705
705 for_each_pbe(p, pagedir_save) { 706 for_each_pbe (p, pagedir_save) {
706 if (p->address) { 707 if (p->address) {
707 ClearPageNosave(virt_to_page(p->address)); 708 ClearPageNosave(virt_to_page(p->address));
708 free_page(p->address); 709 free_page(p->address);
@@ -719,7 +720,7 @@ static int alloc_image_pages(void)
719{ 720{
720 struct pbe * p; 721 struct pbe * p;
721 722
722 for_each_pbe(p, pagedir_save) { 723 for_each_pbe (p, pagedir_save) {
723 p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); 724 p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
724 if (!p->address) 725 if (!p->address)
725 return -ENOMEM; 726 return -ENOMEM;
@@ -740,7 +741,7 @@ void swsusp_free(void)
740/** 741/**
741 * enough_free_mem - Make sure we enough free memory to snapshot. 742 * enough_free_mem - Make sure we enough free memory to snapshot.
742 * 743 *
743 * Returns TRUE or FALSE after checking the number of available 744 * Returns TRUE or FALSE after checking the number of available
744 * free pages. 745 * free pages.
745 */ 746 */
746 747
@@ -758,11 +759,11 @@ static int enough_free_mem(void)
758/** 759/**
759 * enough_swap - Make sure we have enough swap to save the image. 760 * enough_swap - Make sure we have enough swap to save the image.
760 * 761 *
761 * Returns TRUE or FALSE after checking the total amount of swap 762 * Returns TRUE or FALSE after checking the total amount of swap
762 * space avaiable. 763 * space avaiable.
763 * 764 *
764 * FIXME: si_swapinfo(&i) returns all swap devices information. 765 * FIXME: si_swapinfo(&i) returns all swap devices information.
765 * We should only consider resume_device. 766 * We should only consider resume_device.
766 */ 767 */
767 768
768static int enough_swap(void) 769static int enough_swap(void)
@@ -781,18 +782,18 @@ static int swsusp_alloc(void)
781{ 782{
782 int error; 783 int error;
783 784
785 pagedir_nosave = NULL;
786 nr_copy_pages = calc_nr(nr_copy_pages);
787
784 pr_debug("suspend: (pages needed: %d + %d free: %d)\n", 788 pr_debug("suspend: (pages needed: %d + %d free: %d)\n",
785 nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); 789 nr_copy_pages, PAGES_FOR_IO, nr_free_pages());
786 790
787 pagedir_nosave = NULL;
788 if (!enough_free_mem()) 791 if (!enough_free_mem())
789 return -ENOMEM; 792 return -ENOMEM;
790 793
791 if (!enough_swap()) 794 if (!enough_swap())
792 return -ENOSPC; 795 return -ENOSPC;
793 796
794 nr_copy_pages = calc_nr(nr_copy_pages);
795
796 if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { 797 if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
797 printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); 798 printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
798 return -ENOMEM; 799 return -ENOMEM;
@@ -827,8 +828,8 @@ static int suspend_prepare_image(void)
827 error = swsusp_alloc(); 828 error = swsusp_alloc();
828 if (error) 829 if (error)
829 return error; 830 return error;
830 831
831 /* During allocating of suspend pagedir, new cold pages may appear. 832 /* During allocating of suspend pagedir, new cold pages may appear.
832 * Kill them. 833 * Kill them.
833 */ 834 */
834 drain_local_pages(); 835 drain_local_pages();
@@ -869,13 +870,6 @@ extern asmlinkage int swsusp_arch_resume(void);
869 870
870asmlinkage int swsusp_save(void) 871asmlinkage int swsusp_save(void)
871{ 872{
872 int error = 0;
873
874 if ((error = swsusp_swap_check())) {
875 printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
876 "swapon -a!\n");
877 return error;
878 }
879 return suspend_prepare_image(); 873 return suspend_prepare_image();
880} 874}
881 875
@@ -892,14 +886,20 @@ int swsusp_suspend(void)
892 * at resume time, and evil weirdness ensues. 886 * at resume time, and evil weirdness ensues.
893 */ 887 */
894 if ((error = device_power_down(PMSG_FREEZE))) { 888 if ((error = device_power_down(PMSG_FREEZE))) {
895 printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
896 local_irq_enable(); 889 local_irq_enable();
897 swsusp_free();
898 return error; 890 return error;
899 } 891 }
892
893 if ((error = swsusp_swap_check())) {
894 printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
895 "swapon -a!\n");
896 local_irq_enable();
897 return error;
898 }
899
900 save_processor_state(); 900 save_processor_state();
901 if ((error = swsusp_arch_suspend())) 901 if ((error = swsusp_arch_suspend()))
902 swsusp_free(); 902 printk("Error %d suspending\n", error);
903 /* Restore control flow magically appears here */ 903 /* Restore control flow magically appears here */
904 restore_processor_state(); 904 restore_processor_state();
905 BUG_ON (nr_copy_pages_check != nr_copy_pages); 905 BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -929,21 +929,6 @@ int swsusp_resume(void)
929 return error; 929 return error;
930} 930}
931 931
932/* More restore stuff */
933
934/*
935 * Returns true if given address/order collides with any orig_address
936 */
937static int does_collide_order(unsigned long addr, int order)
938{
939 int i;
940
941 for (i=0; i < (1<<order); i++)
942 if (!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE)))
943 return 1;
944 return 0;
945}
946
947/** 932/**
948 * On resume, for storing the PBE list and the image, 933 * On resume, for storing the PBE list and the image,
949 * we can only use memory pages that do not conflict with the pages 934 * we can only use memory pages that do not conflict with the pages
@@ -973,7 +958,7 @@ static unsigned long get_usable_page(unsigned gfp_mask)
973 unsigned long m; 958 unsigned long m;
974 959
975 m = get_zeroed_page(gfp_mask); 960 m = get_zeroed_page(gfp_mask);
976 while (does_collide_order(m, 0)) { 961 while (!PageNosaveFree(virt_to_page(m))) {
977 eat_page((void *)m); 962 eat_page((void *)m);
978 m = get_zeroed_page(gfp_mask); 963 m = get_zeroed_page(gfp_mask);
979 if (!m) 964 if (!m)
@@ -1045,7 +1030,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
1045 1030
1046 /* Set page flags */ 1031 /* Set page flags */
1047 1032
1048 for_each_zone(zone) { 1033 for_each_zone (zone) {
1049 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) 1034 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
1050 SetPageNosaveFree(pfn_to_page(zone_pfn + 1035 SetPageNosaveFree(pfn_to_page(zone_pfn +
1051 zone->zone_start_pfn)); 1036 zone->zone_start_pfn));
@@ -1061,7 +1046,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
1061 /* Relocate colliding pages */ 1046 /* Relocate colliding pages */
1062 1047
1063 for_each_pb_page (pbpage, pblist) { 1048 for_each_pb_page (pbpage, pblist) {
1064 if (does_collide_order((unsigned long)pbpage, 0)) { 1049 if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
1065 m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); 1050 m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD);
1066 if (!m) { 1051 if (!m) {
1067 error = -ENOMEM; 1052 error = -ENOMEM;
@@ -1181,9 +1166,9 @@ static int bio_write_page(pgoff_t page_off, void * page)
1181static const char * sanity_check(void) 1166static const char * sanity_check(void)
1182{ 1167{
1183 dump_info(); 1168 dump_info();
1184 if(swsusp_info.version_code != LINUX_VERSION_CODE) 1169 if (swsusp_info.version_code != LINUX_VERSION_CODE)
1185 return "kernel version"; 1170 return "kernel version";
1186 if(swsusp_info.num_physpages != num_physpages) 1171 if (swsusp_info.num_physpages != num_physpages)
1187 return "memory size"; 1172 return "memory size";
1188 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname)) 1173 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
1189 return "system type"; 1174 return "system type";
@@ -1193,8 +1178,10 @@ static const char * sanity_check(void)
1193 return "version"; 1178 return "version";
1194 if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) 1179 if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
1195 return "machine"; 1180 return "machine";
1181#if 0
1196 if(swsusp_info.cpus != num_online_cpus()) 1182 if(swsusp_info.cpus != num_online_cpus())
1197 return "number of cpus"; 1183 return "number of cpus";
1184#endif
1198 return NULL; 1185 return NULL;
1199} 1186}
1200 1187
@@ -1274,8 +1261,6 @@ static int data_read(struct pbe *pblist)
1274 return error; 1261 return error;
1275} 1262}
1276 1263
1277extern dev_t name_to_dev_t(const char *line);
1278
1279/** 1264/**
1280 * read_pagedir - Read page backup list pages from swap 1265 * read_pagedir - Read page backup list pages from swap
1281 */ 1266 */
@@ -1369,16 +1354,6 @@ int swsusp_check(void)
1369{ 1354{
1370 int error; 1355 int error;
1371 1356
1372 if (!swsusp_resume_device) {
1373 if (!strlen(resume_file))
1374 return -ENOENT;
1375 swsusp_resume_device = name_to_dev_t(resume_file);
1376 pr_debug("swsusp: Resume From Partition %s\n", resume_file);
1377 } else {
1378 pr_debug("swsusp: Resume From Partition %d:%d\n",
1379 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
1380 }
1381
1382 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); 1357 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
1383 if (!IS_ERR(resume_bdev)) { 1358 if (!IS_ERR(resume_bdev)) {
1384 set_blocksize(resume_bdev, PAGE_SIZE); 1359 set_blocksize(resume_bdev, PAGE_SIZE);