aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swsusp.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-12-06 23:34:18 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:27 -0500
commit8357376d3df21b7d6f857931a57ac50da9c66e26 (patch)
treedaf2c369e9b79d24c1666323b3ae75189e482a4a /kernel/power/swsusp.c
parentbf73bae6ba0dc4bd4f1e570feb34a06b72725af6 (diff)
[PATCH] swsusp: Improve handling of highmem
Currently swsusp saves the contents of highmem pages by copying them to the normal zone which is quite inefficient (eg. it requires two normal pages to be used for saving one highmem page). This may be improved by using highmem for saving the contents of saveable highmem pages. Namely, during the suspend phase of the suspend-resume cycle we try to allocate as many free highmem pages as there are saveable highmem pages. If there are not enough highmem image pages to store the contents of all of the saveable highmem pages, some of them will be stored in the "normal" memory. Next, we allocate as many free "normal" pages as needed to store the (remaining) image data. We use a memory bitmap to mark the allocated free pages (ie. highmem as well as "normal" image pages). Now, we use another memory bitmap to mark all of the saveable pages (highmem as well as "normal") and the contents of the saveable pages are copied into the image pages. Then, the second bitmap is used to save the pfns corresponding to the saveable pages and the first one is used to save their data. During the resume phase the pfns of the pages that were saveable during the suspend are loaded from the image and used to mark the "unsafe" page frames. Next, we try to allocate as many free highmem page frames as to load all of the image data that had been in the highmem before the suspend and we allocate so many free "normal" page frames that the total number of allocated free pages (highmem and "normal") is equal to the size of the image. While doing this we have to make sure that there will be some extra free "normal" and "safe" page frames for two lists of PBEs constructed later. Now, the image data are loaded, if possible, into their "original" page frames. The image data that cannot be written into their "original" page frames are loaded into "safe" page frames and their "original" kernel virtual addresses, as well as the addresses of the "safe" pages containing their copies, are stored in one of two lists of PBEs. One list of PBEs is for the copies of "normal" suspend pages (ie. "normal" pages that were saveable during the suspend) and it is used in the same way as previously (ie. by the architecture-dependent parts of swsusp). The other list of PBEs is for the copies of highmem suspend pages. The pages in this list are restored (in a reversible way) right before the arch-dependent code is called. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r--kernel/power/swsusp.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 4147a756a8c7..68de5c1dbd78 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -64,10 +64,8 @@ int in_suspend __nosavedata = 0;
64 64
65#ifdef CONFIG_HIGHMEM 65#ifdef CONFIG_HIGHMEM
66unsigned int count_highmem_pages(void); 66unsigned int count_highmem_pages(void);
67int save_highmem(void);
68int restore_highmem(void); 67int restore_highmem(void);
69#else 68#else
70static inline int save_highmem(void) { return 0; }
71static inline int restore_highmem(void) { return 0; } 69static inline int restore_highmem(void) { return 0; }
72static inline unsigned int count_highmem_pages(void) { return 0; } 70static inline unsigned int count_highmem_pages(void) { return 0; }
73#endif 71#endif
@@ -184,7 +182,7 @@ static inline unsigned long __shrink_memory(long tmp)
184 182
185int swsusp_shrink_memory(void) 183int swsusp_shrink_memory(void)
186{ 184{
187 long size, tmp; 185 long tmp;
188 struct zone *zone; 186 struct zone *zone;
189 unsigned long pages = 0; 187 unsigned long pages = 0;
190 unsigned int i = 0; 188 unsigned int i = 0;
@@ -192,15 +190,27 @@ int swsusp_shrink_memory(void)
192 190
193 printk("Shrinking memory... "); 191 printk("Shrinking memory... ");
194 do { 192 do {
195 size = 2 * count_highmem_pages(); 193 long size, highmem_size;
196 size += size / 50 + count_data_pages() + PAGES_FOR_IO; 194
195 highmem_size = count_highmem_pages();
196 size = count_data_pages() + PAGES_FOR_IO;
197 tmp = size; 197 tmp = size;
198 size += highmem_size;
198 for_each_zone (zone) 199 for_each_zone (zone)
199 if (!is_highmem(zone) && populated_zone(zone)) { 200 if (populated_zone(zone)) {
200 tmp -= zone->free_pages; 201 if (is_highmem(zone)) {
201 tmp += zone->lowmem_reserve[ZONE_NORMAL]; 202 highmem_size -= zone->free_pages;
202 tmp += snapshot_additional_pages(zone); 203 } else {
204 tmp -= zone->free_pages;
205 tmp += zone->lowmem_reserve[ZONE_NORMAL];
206 tmp += snapshot_additional_pages(zone);
207 }
203 } 208 }
209
210 if (highmem_size < 0)
211 highmem_size = 0;
212
213 tmp += highmem_size;
204 if (tmp > 0) { 214 if (tmp > 0) {
205 tmp = __shrink_memory(tmp); 215 tmp = __shrink_memory(tmp);
206 if (!tmp) 216 if (!tmp)
@@ -223,6 +233,7 @@ int swsusp_suspend(void)
223 233
224 if ((error = arch_prepare_suspend())) 234 if ((error = arch_prepare_suspend()))
225 return error; 235 return error;
236
226 local_irq_disable(); 237 local_irq_disable();
227 /* At this point, device_suspend() has been called, but *not* 238 /* At this point, device_suspend() has been called, but *not*
228 * device_power_down(). We *must* device_power_down() now. 239 * device_power_down(). We *must* device_power_down() now.
@@ -235,18 +246,11 @@ int swsusp_suspend(void)
235 goto Enable_irqs; 246 goto Enable_irqs;
236 } 247 }
237 248
238 if ((error = save_highmem())) {
239 printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
240 goto Restore_highmem;
241 }
242
243 save_processor_state(); 249 save_processor_state();
244 if ((error = swsusp_arch_suspend())) 250 if ((error = swsusp_arch_suspend()))
245 printk(KERN_ERR "Error %d suspending\n", error); 251 printk(KERN_ERR "Error %d suspending\n", error);
246 /* Restore control flow magically appears here */ 252 /* Restore control flow magically appears here */
247 restore_processor_state(); 253 restore_processor_state();
248Restore_highmem:
249 restore_highmem();
250 /* NOTE: device_power_up() is just a resume() for devices 254 /* NOTE: device_power_up() is just a resume() for devices
251 * that suspended with irqs off ... no overall powerup. 255 * that suspended with irqs off ... no overall powerup.
252 */ 256 */
@@ -268,18 +272,23 @@ int swsusp_resume(void)
268 printk(KERN_ERR "Some devices failed to power down, very bad\n"); 272 printk(KERN_ERR "Some devices failed to power down, very bad\n");
269 /* We'll ignore saved state, but this gets preempt count (etc) right */ 273 /* We'll ignore saved state, but this gets preempt count (etc) right */
270 save_processor_state(); 274 save_processor_state();
271 error = swsusp_arch_resume(); 275 error = restore_highmem();
272 /* Code below is only ever reached in case of failure. Otherwise 276 if (!error) {
273 * execution continues at place where swsusp_arch_suspend was called 277 error = swsusp_arch_resume();
274 */ 278 /* The code below is only ever reached in case of a failure.
275 BUG_ON(!error); 279 * Otherwise execution continues at place where
280 * swsusp_arch_suspend() was called
281 */
282 BUG_ON(!error);
283 /* This call to restore_highmem() undos the previous one */
284 restore_highmem();
285 }
276 /* The only reason why swsusp_arch_resume() can fail is memory being 286 /* The only reason why swsusp_arch_resume() can fail is memory being
277 * very tight, so we have to free it as soon as we can to avoid 287 * very tight, so we have to free it as soon as we can to avoid
278 * subsequent failures 288 * subsequent failures
279 */ 289 */
280 swsusp_free(); 290 swsusp_free();
281 restore_processor_state(); 291 restore_processor_state();
282 restore_highmem();
283 touch_softlockup_watchdog(); 292 touch_softlockup_watchdog();
284 device_power_up(); 293 device_power_up();
285 local_irq_enable(); 294 local_irq_enable();