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 | 45 | ||||
-rw-r--r-- | kernel/power/main.c | 16 | ||||
-rw-r--r-- | kernel/power/process.c | 30 | ||||
-rw-r--r-- | kernel/power/smp.c | 89 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 128 |
7 files changed, 144 insertions, 178 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..c51a4d96d4eb 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(); |
@@ -233,6 +234,16 @@ static int software_resume(void) | |||
233 | { | 234 | { |
234 | int error; | 235 | int error; |
235 | 236 | ||
237 | if (!swsusp_resume_device) { | ||
238 | if (!strlen(resume_file)) | ||
239 | return -ENOENT; | ||
240 | swsusp_resume_device = name_to_dev_t(resume_file); | ||
241 | pr_debug("swsusp: Resume From Partition %s\n", resume_file); | ||
242 | } else { | ||
243 | pr_debug("swsusp: Resume From Partition %d:%d\n", | ||
244 | MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); | ||
245 | } | ||
246 | |||
236 | if (noresume) { | 247 | if (noresume) { |
237 | /** | 248 | /** |
238 | * FIXME: If noresume is specified, we need to find the partition | 249 | * FIXME: If noresume is specified, we need to find the partition |
@@ -250,7 +261,7 @@ static int software_resume(void) | |||
250 | 261 | ||
251 | if ((error = prepare_processes())) { | 262 | if ((error = prepare_processes())) { |
252 | swsusp_close(); | 263 | swsusp_close(); |
253 | goto Cleanup; | 264 | goto Done; |
254 | } | 265 | } |
255 | 266 | ||
256 | pr_debug("PM: Reading swsusp image.\n"); | 267 | pr_debug("PM: Reading swsusp image.\n"); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 454434716f35..71aa0fd22007 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -59,6 +59,13 @@ static int suspend_prepare(suspend_state_t state) | |||
59 | 59 | ||
60 | pm_prepare_console(); | 60 | pm_prepare_console(); |
61 | 61 | ||
62 | disable_nonboot_cpus(); | ||
63 | |||
64 | if (num_online_cpus() != 1) { | ||
65 | error = -EPERM; | ||
66 | goto Enable_cpu; | ||
67 | } | ||
68 | |||
62 | if (freeze_processes()) { | 69 | if (freeze_processes()) { |
63 | error = -EAGAIN; | 70 | error = -EAGAIN; |
64 | goto Thaw; | 71 | goto Thaw; |
@@ -89,6 +96,8 @@ static int suspend_prepare(suspend_state_t state) | |||
89 | pm_ops->finish(state); | 96 | pm_ops->finish(state); |
90 | Thaw: | 97 | Thaw: |
91 | thaw_processes(); | 98 | thaw_processes(); |
99 | Enable_cpu: | ||
100 | enable_nonboot_cpus(); | ||
92 | pm_restore_console(); | 101 | pm_restore_console(); |
93 | return error; | 102 | return error; |
94 | } | 103 | } |
@@ -127,6 +136,7 @@ static void suspend_finish(suspend_state_t state) | |||
127 | if (pm_ops && pm_ops->finish) | 136 | if (pm_ops && pm_ops->finish) |
128 | pm_ops->finish(state); | 137 | pm_ops->finish(state); |
129 | thaw_processes(); | 138 | thaw_processes(); |
139 | enable_nonboot_cpus(); | ||
130 | pm_restore_console(); | 140 | pm_restore_console(); |
131 | } | 141 | } |
132 | 142 | ||
@@ -164,12 +174,6 @@ static int enter_state(suspend_state_t state) | |||
164 | goto Unlock; | 174 | goto Unlock; |
165 | } | 175 | } |
166 | 176 | ||
167 | /* Suspend is hard to get right on SMP. */ | ||
168 | if (num_online_cpus() != 1) { | ||
169 | error = -EPERM; | ||
170 | goto Unlock; | ||
171 | } | ||
172 | |||
173 | 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]); |
174 | if ((error = suspend_prepare(state))) | 178 | if ((error = suspend_prepare(state))) |
175 | goto Unlock; | 179 | goto Unlock; |
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 :-). */ |
35 | void refrigerator(unsigned long flag) | 35 | void 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(¤t->sighand->siglock); | 46 | spin_lock_irq(¤t->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(¤t->sighand->siglock); | 48 | spin_unlock_irq(¤t->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 */ |
58 | int freeze_processes(void) | 57 | int 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 cba3584b80fe..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)", _smp_processor_id()); | ||
52 | current->state = TASK_INTERRUPTIBLE; | ||
53 | schedule_timeout(HZ); | ||
54 | printk("..."); | ||
55 | BUG_ON(_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 90b3b68dee3f..7d7801cd01f0 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>: |
@@ -81,14 +81,14 @@ static int nr_copy_pages_check; | |||
81 | extern char resume_file[]; | 81 | extern char resume_file[]; |
82 | 82 | ||
83 | /* Local variables that should not be affected by save */ | 83 | /* Local variables that should not be affected by save */ |
84 | 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(); |
@@ -869,13 +869,6 @@ extern asmlinkage int swsusp_arch_resume(void); | |||
869 | 869 | ||
870 | asmlinkage int swsusp_save(void) | 870 | asmlinkage int swsusp_save(void) |
871 | { | 871 | { |
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(); | 872 | return suspend_prepare_image(); |
880 | } | 873 | } |
881 | 874 | ||
@@ -892,14 +885,20 @@ int swsusp_suspend(void) | |||
892 | * at resume time, and evil weirdness ensues. | 885 | * at resume time, and evil weirdness ensues. |
893 | */ | 886 | */ |
894 | if ((error = device_power_down(PMSG_FREEZE))) { | 887 | if ((error = device_power_down(PMSG_FREEZE))) { |
895 | printk(KERN_ERR "Some devices failed to power down, aborting suspend\n"); | ||
896 | local_irq_enable(); | 888 | local_irq_enable(); |
897 | swsusp_free(); | ||
898 | return error; | 889 | return error; |
899 | } | 890 | } |
891 | |||
892 | if ((error = swsusp_swap_check())) { | ||
893 | printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try " | ||
894 | "swapon -a!\n"); | ||
895 | local_irq_enable(); | ||
896 | return error; | ||
897 | } | ||
898 | |||
900 | save_processor_state(); | 899 | save_processor_state(); |
901 | if ((error = swsusp_arch_suspend())) | 900 | if ((error = swsusp_arch_suspend())) |
902 | swsusp_free(); | 901 | printk("Error %d suspending\n", error); |
903 | /* Restore control flow magically appears here */ | 902 | /* Restore control flow magically appears here */ |
904 | restore_processor_state(); | 903 | restore_processor_state(); |
905 | BUG_ON (nr_copy_pages_check != nr_copy_pages); | 904 | BUG_ON (nr_copy_pages_check != nr_copy_pages); |
@@ -929,21 +928,6 @@ int swsusp_resume(void) | |||
929 | return error; | 928 | return error; |
930 | } | 929 | } |
931 | 930 | ||
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 | /** | 931 | /** |
948 | * On resume, for storing the PBE list and the image, | 932 | * On resume, for storing the PBE list and the image, |
949 | * we can only use memory pages that do not conflict with the pages | 933 | * we can only use memory pages that do not conflict with the pages |
@@ -973,7 +957,7 @@ static unsigned long get_usable_page(unsigned gfp_mask) | |||
973 | unsigned long m; | 957 | unsigned long m; |
974 | 958 | ||
975 | m = get_zeroed_page(gfp_mask); | 959 | m = get_zeroed_page(gfp_mask); |
976 | while (does_collide_order(m, 0)) { | 960 | while (!PageNosaveFree(virt_to_page(m))) { |
977 | eat_page((void *)m); | 961 | eat_page((void *)m); |
978 | m = get_zeroed_page(gfp_mask); | 962 | m = get_zeroed_page(gfp_mask); |
979 | if (!m) | 963 | if (!m) |
@@ -1045,7 +1029,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1045 | 1029 | ||
1046 | /* Set page flags */ | 1030 | /* Set page flags */ |
1047 | 1031 | ||
1048 | for_each_zone(zone) { | 1032 | for_each_zone (zone) { |
1049 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 1033 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) |
1050 | SetPageNosaveFree(pfn_to_page(zone_pfn + | 1034 | SetPageNosaveFree(pfn_to_page(zone_pfn + |
1051 | zone->zone_start_pfn)); | 1035 | zone->zone_start_pfn)); |
@@ -1061,7 +1045,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1061 | /* Relocate colliding pages */ | 1045 | /* Relocate colliding pages */ |
1062 | 1046 | ||
1063 | for_each_pb_page (pbpage, pblist) { | 1047 | for_each_pb_page (pbpage, pblist) { |
1064 | if (does_collide_order((unsigned long)pbpage, 0)) { | 1048 | if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) { |
1065 | m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); | 1049 | m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); |
1066 | if (!m) { | 1050 | if (!m) { |
1067 | error = -ENOMEM; | 1051 | error = -ENOMEM; |
@@ -1181,9 +1165,9 @@ static int bio_write_page(pgoff_t page_off, void * page) | |||
1181 | static const char * sanity_check(void) | 1165 | static const char * sanity_check(void) |
1182 | { | 1166 | { |
1183 | dump_info(); | 1167 | dump_info(); |
1184 | if(swsusp_info.version_code != LINUX_VERSION_CODE) | 1168 | if (swsusp_info.version_code != LINUX_VERSION_CODE) |
1185 | return "kernel version"; | 1169 | return "kernel version"; |
1186 | if(swsusp_info.num_physpages != num_physpages) | 1170 | if (swsusp_info.num_physpages != num_physpages) |
1187 | return "memory size"; | 1171 | return "memory size"; |
1188 | if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname)) | 1172 | if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname)) |
1189 | return "system type"; | 1173 | return "system type"; |
@@ -1193,8 +1177,10 @@ static const char * sanity_check(void) | |||
1193 | return "version"; | 1177 | return "version"; |
1194 | if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) | 1178 | if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) |
1195 | return "machine"; | 1179 | return "machine"; |
1180 | #if 0 | ||
1196 | if(swsusp_info.cpus != num_online_cpus()) | 1181 | if(swsusp_info.cpus != num_online_cpus()) |
1197 | return "number of cpus"; | 1182 | return "number of cpus"; |
1183 | #endif | ||
1198 | return NULL; | 1184 | return NULL; |
1199 | } | 1185 | } |
1200 | 1186 | ||
@@ -1369,16 +1355,6 @@ int swsusp_check(void) | |||
1369 | { | 1355 | { |
1370 | int error; | 1356 | int error; |
1371 | 1357 | ||
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); | 1358 | resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); |
1383 | if (!IS_ERR(resume_bdev)) { | 1359 | if (!IS_ERR(resume_bdev)) { |
1384 | set_blocksize(resume_bdev, PAGE_SIZE); | 1360 | set_blocksize(resume_bdev, PAGE_SIZE); |