diff options
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Kconfig | 8 | ||||
-rw-r--r-- | kernel/power/Makefile | 6 | ||||
-rw-r--r-- | kernel/power/disk.c | 35 | ||||
-rw-r--r-- | kernel/power/main.c | 16 | ||||
-rw-r--r-- | kernel/power/smp.c | 89 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 93 |
6 files changed, 111 insertions, 136 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 | ||
29 | config SOFTWARE_SUSPEND | 29 | config 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 | ||
75 | config 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) | |||
3 | EXTRA_CFLAGS += -DDEBUG | 3 | EXTRA_CFLAGS += -DDEBUG |
4 | endif | 4 | endif |
5 | 5 | ||
6 | swsusp-smp-$(CONFIG_SMP) += smp.o | ||
7 | |||
8 | obj-y := main.o process.o console.o pm.o | 6 | obj-y := main.o process.o console.o pm.o |
9 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o | 7 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o |
8 | |||
9 | obj-$(CONFIG_SUSPEND_SMP) += smp.o | ||
10 | 10 | ||
11 | obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o | 11 | obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 02b6764034dc..fb8de63c2919 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -117,8 +117,8 @@ static void finish(void) | |||
117 | { | 117 | { |
118 | device_resume(); | 118 | device_resume(); |
119 | platform_finish(); | 119 | platform_finish(); |
120 | enable_nonboot_cpus(); | ||
121 | thaw_processes(); | 120 | thaw_processes(); |
121 | enable_nonboot_cpus(); | ||
122 | pm_restore_console(); | 122 | pm_restore_console(); |
123 | } | 123 | } |
124 | 124 | ||
@@ -131,28 +131,35 @@ static int prepare_processes(void) | |||
131 | 131 | ||
132 | sys_sync(); | 132 | sys_sync(); |
133 | 133 | ||
134 | disable_nonboot_cpus(); | ||
135 | |||
134 | if (freeze_processes()) { | 136 | if (freeze_processes()) { |
135 | error = -EBUSY; | 137 | error = -EBUSY; |
136 | return error; | 138 | goto thaw; |
137 | } | 139 | } |
138 | 140 | ||
139 | if (pm_disk_mode == PM_DISK_PLATFORM) { | 141 | if (pm_disk_mode == PM_DISK_PLATFORM) { |
140 | if (pm_ops && pm_ops->prepare) { | 142 | if (pm_ops && pm_ops->prepare) { |
141 | if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) | 143 | if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) |
142 | return error; | 144 | goto thaw; |
143 | } | 145 | } |
144 | } | 146 | } |
145 | 147 | ||
146 | /* Free memory before shutting down devices. */ | 148 | /* Free memory before shutting down devices. */ |
147 | free_some_memory(); | 149 | free_some_memory(); |
148 | |||
149 | return 0; | 150 | return 0; |
151 | thaw: | ||
152 | thaw_processes(); | ||
153 | enable_nonboot_cpus(); | ||
154 | pm_restore_console(); | ||
155 | return error; | ||
150 | } | 156 | } |
151 | 157 | ||
152 | static void unprepare_processes(void) | 158 | static void unprepare_processes(void) |
153 | { | 159 | { |
154 | enable_nonboot_cpus(); | 160 | platform_finish(); |
155 | thaw_processes(); | 161 | thaw_processes(); |
162 | enable_nonboot_cpus(); | ||
156 | pm_restore_console(); | 163 | pm_restore_console(); |
157 | } | 164 | } |
158 | 165 | ||
@@ -160,15 +167,9 @@ static int prepare_devices(void) | |||
160 | { | 167 | { |
161 | int error; | 168 | int error; |
162 | 169 | ||
163 | disable_nonboot_cpus(); | 170 | if ((error = device_suspend(PMSG_FREEZE))) |
164 | if ((error = device_suspend(PMSG_FREEZE))) { | ||
165 | printk("Some devices failed to suspend\n"); | 171 | printk("Some devices failed to suspend\n"); |
166 | platform_finish(); | 172 | return error; |
167 | enable_nonboot_cpus(); | ||
168 | return error; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | 173 | } |
173 | 174 | ||
174 | /** | 175 | /** |
@@ -185,9 +186,9 @@ int pm_suspend_disk(void) | |||
185 | int error; | 186 | int error; |
186 | 187 | ||
187 | error = prepare_processes(); | 188 | error = prepare_processes(); |
188 | if (!error) { | 189 | if (error) |
189 | error = prepare_devices(); | 190 | return error; |
190 | } | 191 | error = prepare_devices(); |
191 | 192 | ||
192 | if (error) { | 193 | if (error) { |
193 | unprepare_processes(); | 194 | unprepare_processes(); |
@@ -250,7 +251,7 @@ static int software_resume(void) | |||
250 | 251 | ||
251 | if ((error = prepare_processes())) { | 252 | if ((error = prepare_processes())) { |
252 | swsusp_close(); | 253 | swsusp_close(); |
253 | goto Cleanup; | 254 | goto Done; |
254 | } | 255 | } |
255 | 256 | ||
256 | pr_debug("PM: Reading swsusp image.\n"); | 257 | pr_debug("PM: Reading swsusp image.\n"); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 4cdebc972ff2..c94cb9e95090 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -55,6 +55,13 @@ static int suspend_prepare(suspend_state_t state) | |||
55 | 55 | ||
56 | pm_prepare_console(); | 56 | pm_prepare_console(); |
57 | 57 | ||
58 | disable_nonboot_cpus(); | ||
59 | |||
60 | if (num_online_cpus() != 1) { | ||
61 | error = -EPERM; | ||
62 | goto Enable_cpu; | ||
63 | } | ||
64 | |||
58 | if (freeze_processes()) { | 65 | if (freeze_processes()) { |
59 | error = -EAGAIN; | 66 | error = -EAGAIN; |
60 | goto Thaw; | 67 | goto Thaw; |
@@ -75,6 +82,8 @@ static int suspend_prepare(suspend_state_t state) | |||
75 | pm_ops->finish(state); | 82 | pm_ops->finish(state); |
76 | Thaw: | 83 | Thaw: |
77 | thaw_processes(); | 84 | thaw_processes(); |
85 | Enable_cpu: | ||
86 | enable_nonboot_cpus(); | ||
78 | pm_restore_console(); | 87 | pm_restore_console(); |
79 | return error; | 88 | return error; |
80 | } | 89 | } |
@@ -113,6 +122,7 @@ static void suspend_finish(suspend_state_t state) | |||
113 | if (pm_ops && pm_ops->finish) | 122 | if (pm_ops && pm_ops->finish) |
114 | pm_ops->finish(state); | 123 | pm_ops->finish(state); |
115 | thaw_processes(); | 124 | thaw_processes(); |
125 | enable_nonboot_cpus(); | ||
116 | pm_restore_console(); | 126 | pm_restore_console(); |
117 | } | 127 | } |
118 | 128 | ||
@@ -150,12 +160,6 @@ static int enter_state(suspend_state_t state) | |||
150 | goto Unlock; | 160 | goto Unlock; |
151 | } | 161 | } |
152 | 162 | ||
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]); | 163 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); |
160 | if ((error = suspend_prepare(state))) | 164 | if ((error = suspend_prepare(state))) |
161 | goto Unlock; | 165 | goto Unlock; |
diff --git a/kernel/power/smp.c b/kernel/power/smp.c index 457c2302ed42..bbe23079c62c 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 | ||
19 | static atomic_t cpu_counter, freeze; | 20 | /* This is protected by pm_sem semaphore */ |
20 | 21 | static cpumask_t frozen_cpus; | |
21 | |||
22 | static 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 | |||
45 | static cpumask_t oldmask; | ||
46 | 22 | ||
47 | void disable_nonboot_cpus(void) | 23 | void 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 | |||
57 | /* FIXME: for this to work, all the CPUs must be running | ||
58 | * "idle" thread (or we deadlock). Is that guaranteed? */ | ||
59 | 26 | ||
60 | atomic_set(&cpu_counter, 0); | 27 | error = 0; |
61 | atomic_set(&freeze, 1); | 28 | cpus_clear(frozen_cpus); |
62 | smp_call_function(smp_pause, NULL, 0, 0); | 29 | printk("Freezing cpus ...\n"); |
63 | while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) { | 30 | for_each_online_cpu(cpu) { |
64 | cpu_relax(); | 31 | if (cpu == 0) |
65 | barrier(); | 32 | continue; |
33 | error = cpu_down(cpu); | ||
34 | if (!error) { | ||
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(smp_processor_id() != 0); |
42 | if (error) | ||
43 | panic("cpus not sleeping"); | ||
68 | } | 44 | } |
69 | 45 | ||
70 | void enable_nonboot_cpus(void) | 46 | void 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 53f9f8720ee4..c285fc5a2320 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>: |
@@ -84,11 +84,11 @@ extern char resume_file[]; | |||
84 | static unsigned int nr_copy_pages __nosavedata = 0; | 84 | static unsigned int nr_copy_pages __nosavedata = 0; |
85 | 85 | ||
86 | /* Suspend pagedir is allocated before final copy, therefore it | 86 | /* Suspend pagedir is allocated before final copy, therefore it |
87 | must be freed after resume | 87 | must be freed after resume |
88 | 88 | ||
89 | Warning: this is evil. There are actually two pagedirs at time of | 89 | Warning: this is evil. There are actually two pagedirs at time of |
90 | resume. One is "pagedir_save", which is empty frame allocated at | 90 | resume. One is "pagedir_save", which is empty frame allocated at |
91 | time of suspend, that must be freed. Second is "pagedir_nosave", | 91 | time of suspend, that must be freed. Second is "pagedir_nosave", |
92 | allocated at time of resume, that travels through memory not to | 92 | allocated at time of resume, that travels through memory not to |
93 | collide with anything. | 93 | collide with anything. |
94 | 94 | ||
@@ -132,7 +132,7 @@ static int mark_swapfiles(swp_entry_t prev) | |||
132 | { | 132 | { |
133 | int error; | 133 | int error; |
134 | 134 | ||
135 | rw_swap_page_sync(READ, | 135 | rw_swap_page_sync(READ, |
136 | swp_entry(root_swap, 0), | 136 | swp_entry(root_swap, 0), |
137 | virt_to_page((unsigned long)&swsusp_header)); | 137 | virt_to_page((unsigned long)&swsusp_header)); |
138 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || | 138 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || |
@@ -140,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev) | |||
140 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); | 140 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); |
141 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); | 141 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); |
142 | swsusp_header.swsusp_info = prev; | 142 | swsusp_header.swsusp_info = prev; |
143 | error = rw_swap_page_sync(WRITE, | 143 | error = rw_swap_page_sync(WRITE, |
144 | swp_entry(root_swap, 0), | 144 | swp_entry(root_swap, 0), |
145 | virt_to_page((unsigned long) | 145 | virt_to_page((unsigned long) |
146 | &swsusp_header)); | 146 | &swsusp_header)); |
@@ -174,22 +174,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info) | |||
174 | static int swsusp_swap_check(void) /* This is called before saving image */ | 174 | static int swsusp_swap_check(void) /* This is called before saving image */ |
175 | { | 175 | { |
176 | int i, len; | 176 | int i, len; |
177 | 177 | ||
178 | len=strlen(resume_file); | 178 | len=strlen(resume_file); |
179 | root_swap = 0xFFFF; | 179 | root_swap = 0xFFFF; |
180 | 180 | ||
181 | swap_list_lock(); | 181 | swap_list_lock(); |
182 | for(i=0; i<MAX_SWAPFILES; i++) { | 182 | for (i=0; i<MAX_SWAPFILES; i++) { |
183 | if (swap_info[i].flags == 0) { | 183 | if (swap_info[i].flags == 0) { |
184 | swapfile_used[i]=SWAPFILE_UNUSED; | 184 | swapfile_used[i]=SWAPFILE_UNUSED; |
185 | } else { | 185 | } else { |
186 | if(!len) { | 186 | if (!len) { |
187 | printk(KERN_WARNING "resume= option should be used to set suspend device" ); | 187 | printk(KERN_WARNING "resume= option should be used to set suspend device" ); |
188 | if(root_swap == 0xFFFF) { | 188 | if (root_swap == 0xFFFF) { |
189 | swapfile_used[i] = SWAPFILE_SUSPEND; | 189 | swapfile_used[i] = SWAPFILE_SUSPEND; |
190 | root_swap = i; | 190 | root_swap = i; |
191 | } else | 191 | } else |
192 | swapfile_used[i] = SWAPFILE_IGNORED; | 192 | swapfile_used[i] = SWAPFILE_IGNORED; |
193 | } else { | 193 | } else { |
194 | /* we ignore all swap devices that are not the resume_file */ | 194 | /* we ignore all swap devices that are not the resume_file */ |
195 | if (is_resume_device(&swap_info[i])) { | 195 | if (is_resume_device(&swap_info[i])) { |
@@ -209,15 +209,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */ | |||
209 | * This is called after saving image so modification | 209 | * This is called after saving image so modification |
210 | * will be lost after resume... and that's what we want. | 210 | * will be lost after resume... and that's what we want. |
211 | * we make the device unusable. A new call to | 211 | * we make the device unusable. A new call to |
212 | * lock_swapdevices can unlock the devices. | 212 | * lock_swapdevices can unlock the devices. |
213 | */ | 213 | */ |
214 | static void lock_swapdevices(void) | 214 | static void lock_swapdevices(void) |
215 | { | 215 | { |
216 | int i; | 216 | int i; |
217 | 217 | ||
218 | swap_list_lock(); | 218 | swap_list_lock(); |
219 | for(i = 0; i< MAX_SWAPFILES; i++) | 219 | for (i = 0; i< MAX_SWAPFILES; i++) |
220 | if(swapfile_used[i] == SWAPFILE_IGNORED) { | 220 | if (swapfile_used[i] == SWAPFILE_IGNORED) { |
221 | swap_info[i].flags ^= 0xFF; | 221 | swap_info[i].flags ^= 0xFF; |
222 | } | 222 | } |
223 | swap_list_unlock(); | 223 | swap_list_unlock(); |
@@ -229,7 +229,7 @@ static void lock_swapdevices(void) | |||
229 | * @loc: Place to store the entry we used. | 229 | * @loc: Place to store the entry we used. |
230 | * | 230 | * |
231 | * Allocate a new swap entry and 'sync' it. Note we discard -EIO | 231 | * 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 | 232 | * 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 | 233 | * check the return of rw_swap_page_sync() at all, since most pages |
234 | * written back to swap would return -EIO. | 234 | * written back to swap would return -EIO. |
235 | * This is a partial improvement, since we will at least return other | 235 | * This is a partial improvement, since we will at least return other |
@@ -241,7 +241,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) | |||
241 | int error = 0; | 241 | int error = 0; |
242 | 242 | ||
243 | entry = get_swap_page(); | 243 | entry = get_swap_page(); |
244 | if (swp_offset(entry) && | 244 | if (swp_offset(entry) && |
245 | swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { | 245 | swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { |
246 | error = rw_swap_page_sync(WRITE, entry, | 246 | error = rw_swap_page_sync(WRITE, entry, |
247 | virt_to_page(addr)); | 247 | virt_to_page(addr)); |
@@ -257,7 +257,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) | |||
257 | /** | 257 | /** |
258 | * data_free - Free the swap entries used by the saved image. | 258 | * data_free - Free the swap entries used by the saved image. |
259 | * | 259 | * |
260 | * Walk the list of used swap entries and free each one. | 260 | * Walk the list of used swap entries and free each one. |
261 | * This is only used for cleanup when suspend fails. | 261 | * This is only used for cleanup when suspend fails. |
262 | */ | 262 | */ |
263 | static void data_free(void) | 263 | static void data_free(void) |
@@ -290,7 +290,7 @@ static int data_write(void) | |||
290 | mod = 1; | 290 | mod = 1; |
291 | 291 | ||
292 | printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); | 292 | printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); |
293 | for_each_pbe(p, pagedir_nosave) { | 293 | for_each_pbe (p, pagedir_nosave) { |
294 | if (!(i%mod)) | 294 | if (!(i%mod)) |
295 | printk( "\b\b\b\b%3d%%", i / mod ); | 295 | printk( "\b\b\b\b%3d%%", i / mod ); |
296 | if ((error = write_page(p->address, &(p->swap_address)))) | 296 | if ((error = write_page(p->address, &(p->swap_address)))) |
@@ -335,7 +335,7 @@ static int close_swap(void) | |||
335 | 335 | ||
336 | dump_info(); | 336 | dump_info(); |
337 | error = write_page((unsigned long)&swsusp_info, &entry); | 337 | error = write_page((unsigned long)&swsusp_info, &entry); |
338 | if (!error) { | 338 | if (!error) { |
339 | printk( "S" ); | 339 | printk( "S" ); |
340 | error = mark_swapfiles(entry); | 340 | error = mark_swapfiles(entry); |
341 | printk( "|\n" ); | 341 | printk( "|\n" ); |
@@ -370,7 +370,7 @@ static int write_pagedir(void) | |||
370 | struct pbe * pbe; | 370 | struct pbe * pbe; |
371 | 371 | ||
372 | printk( "Writing pagedir..."); | 372 | printk( "Writing pagedir..."); |
373 | for_each_pb_page(pbe, pagedir_nosave) { | 373 | for_each_pb_page (pbe, pagedir_nosave) { |
374 | if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) | 374 | if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) |
375 | return error; | 375 | return error; |
376 | } | 376 | } |
@@ -472,7 +472,7 @@ static int save_highmem(void) | |||
472 | int res = 0; | 472 | int res = 0; |
473 | 473 | ||
474 | pr_debug("swsusp: Saving Highmem\n"); | 474 | pr_debug("swsusp: Saving Highmem\n"); |
475 | for_each_zone(zone) { | 475 | for_each_zone (zone) { |
476 | if (is_highmem(zone)) | 476 | if (is_highmem(zone)) |
477 | res = save_highmem_zone(zone); | 477 | res = save_highmem_zone(zone); |
478 | if (res) | 478 | if (res) |
@@ -547,7 +547,7 @@ static void count_data_pages(void) | |||
547 | 547 | ||
548 | nr_copy_pages = 0; | 548 | nr_copy_pages = 0; |
549 | 549 | ||
550 | for_each_zone(zone) { | 550 | for_each_zone (zone) { |
551 | if (is_highmem(zone)) | 551 | if (is_highmem(zone)) |
552 | continue; | 552 | continue; |
553 | mark_free_pages(zone); | 553 | mark_free_pages(zone); |
@@ -562,9 +562,9 @@ static void copy_data_pages(void) | |||
562 | struct zone *zone; | 562 | struct zone *zone; |
563 | unsigned long zone_pfn; | 563 | unsigned long zone_pfn; |
564 | struct pbe * pbe = pagedir_nosave; | 564 | struct pbe * pbe = pagedir_nosave; |
565 | 565 | ||
566 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); | 566 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); |
567 | for_each_zone(zone) { | 567 | for_each_zone (zone) { |
568 | if (is_highmem(zone)) | 568 | if (is_highmem(zone)) |
569 | continue; | 569 | continue; |
570 | mark_free_pages(zone); | 570 | mark_free_pages(zone); |
@@ -702,7 +702,7 @@ static void free_image_pages(void) | |||
702 | { | 702 | { |
703 | struct pbe * p; | 703 | struct pbe * p; |
704 | 704 | ||
705 | for_each_pbe(p, pagedir_save) { | 705 | for_each_pbe (p, pagedir_save) { |
706 | if (p->address) { | 706 | if (p->address) { |
707 | ClearPageNosave(virt_to_page(p->address)); | 707 | ClearPageNosave(virt_to_page(p->address)); |
708 | free_page(p->address); | 708 | free_page(p->address); |
@@ -719,7 +719,7 @@ static int alloc_image_pages(void) | |||
719 | { | 719 | { |
720 | struct pbe * p; | 720 | struct pbe * p; |
721 | 721 | ||
722 | for_each_pbe(p, pagedir_save) { | 722 | for_each_pbe (p, pagedir_save) { |
723 | p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | 723 | p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); |
724 | if (!p->address) | 724 | if (!p->address) |
725 | return -ENOMEM; | 725 | return -ENOMEM; |
@@ -740,7 +740,7 @@ void swsusp_free(void) | |||
740 | /** | 740 | /** |
741 | * enough_free_mem - Make sure we enough free memory to snapshot. | 741 | * enough_free_mem - Make sure we enough free memory to snapshot. |
742 | * | 742 | * |
743 | * Returns TRUE or FALSE after checking the number of available | 743 | * Returns TRUE or FALSE after checking the number of available |
744 | * free pages. | 744 | * free pages. |
745 | */ | 745 | */ |
746 | 746 | ||
@@ -758,11 +758,11 @@ static int enough_free_mem(void) | |||
758 | /** | 758 | /** |
759 | * enough_swap - Make sure we have enough swap to save the image. | 759 | * enough_swap - Make sure we have enough swap to save the image. |
760 | * | 760 | * |
761 | * Returns TRUE or FALSE after checking the total amount of swap | 761 | * Returns TRUE or FALSE after checking the total amount of swap |
762 | * space avaiable. | 762 | * space avaiable. |
763 | * | 763 | * |
764 | * FIXME: si_swapinfo(&i) returns all swap devices information. | 764 | * FIXME: si_swapinfo(&i) returns all swap devices information. |
765 | * We should only consider resume_device. | 765 | * We should only consider resume_device. |
766 | */ | 766 | */ |
767 | 767 | ||
768 | static int enough_swap(void) | 768 | static int enough_swap(void) |
@@ -781,18 +781,18 @@ static int swsusp_alloc(void) | |||
781 | { | 781 | { |
782 | int error; | 782 | int error; |
783 | 783 | ||
784 | pagedir_nosave = NULL; | ||
785 | nr_copy_pages = calc_nr(nr_copy_pages); | ||
786 | |||
784 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", | 787 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", |
785 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); | 788 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); |
786 | 789 | ||
787 | pagedir_nosave = NULL; | ||
788 | if (!enough_free_mem()) | 790 | if (!enough_free_mem()) |
789 | return -ENOMEM; | 791 | return -ENOMEM; |
790 | 792 | ||
791 | if (!enough_swap()) | 793 | if (!enough_swap()) |
792 | return -ENOSPC; | 794 | return -ENOSPC; |
793 | 795 | ||
794 | nr_copy_pages = calc_nr(nr_copy_pages); | ||
795 | |||
796 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { | 796 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { |
797 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | 797 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); |
798 | return -ENOMEM; | 798 | return -ENOMEM; |
@@ -827,8 +827,8 @@ static int suspend_prepare_image(void) | |||
827 | error = swsusp_alloc(); | 827 | error = swsusp_alloc(); |
828 | if (error) | 828 | if (error) |
829 | return error; | 829 | return error; |
830 | 830 | ||
831 | /* During allocating of suspend pagedir, new cold pages may appear. | 831 | /* During allocating of suspend pagedir, new cold pages may appear. |
832 | * Kill them. | 832 | * Kill them. |
833 | */ | 833 | */ |
834 | drain_local_pages(); | 834 | drain_local_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 | */ | ||
937 | static 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; |
@@ -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 | ||