|
@@ -64,10 +64,8 @@ int in_suspend __nosavedata = 0;
|
|
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
|
unsigned int count_highmem_pages(void);
|
|
|
-int save_highmem(void);
|
|
|
int restore_highmem(void);
|
|
|
#else
|
|
|
-static inline int save_highmem(void) { return 0; }
|
|
|
static inline int restore_highmem(void) { return 0; }
|
|
|
static inline unsigned int count_highmem_pages(void) { return 0; }
|
|
|
#endif
|
|
@@ -184,7 +182,7 @@ static inline unsigned long __shrink_memory(long tmp)
|
|
|
|
|
|
int swsusp_shrink_memory(void)
|
|
|
{
|
|
|
- long size, tmp;
|
|
|
+ long tmp;
|
|
|
struct zone *zone;
|
|
|
unsigned long pages = 0;
|
|
|
unsigned int i = 0;
|
|
@@ -192,15 +190,27 @@ int swsusp_shrink_memory(void)
|
|
|
|
|
|
printk("Shrinking memory... ");
|
|
|
do {
|
|
|
- size = 2 * count_highmem_pages();
|
|
|
- size += size / 50 + count_data_pages() + PAGES_FOR_IO;
|
|
|
+ long size, highmem_size;
|
|
|
+
|
|
|
+ highmem_size = count_highmem_pages();
|
|
|
+ size = count_data_pages() + PAGES_FOR_IO;
|
|
|
tmp = size;
|
|
|
+ size += highmem_size;
|
|
|
for_each_zone (zone)
|
|
|
- if (!is_highmem(zone) && populated_zone(zone)) {
|
|
|
- tmp -= zone->free_pages;
|
|
|
- tmp += zone->lowmem_reserve[ZONE_NORMAL];
|
|
|
- tmp += snapshot_additional_pages(zone);
|
|
|
+ if (populated_zone(zone)) {
|
|
|
+ if (is_highmem(zone)) {
|
|
|
+ highmem_size -= zone->free_pages;
|
|
|
+ } else {
|
|
|
+ tmp -= zone->free_pages;
|
|
|
+ tmp += zone->lowmem_reserve[ZONE_NORMAL];
|
|
|
+ tmp += snapshot_additional_pages(zone);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ if (highmem_size < 0)
|
|
|
+ highmem_size = 0;
|
|
|
+
|
|
|
+ tmp += highmem_size;
|
|
|
if (tmp > 0) {
|
|
|
tmp = __shrink_memory(tmp);
|
|
|
if (!tmp)
|
|
@@ -223,6 +233,7 @@ int swsusp_suspend(void)
|
|
|
|
|
|
if ((error = arch_prepare_suspend()))
|
|
|
return error;
|
|
|
+
|
|
|
local_irq_disable();
|
|
|
/* At this point, device_suspend() has been called, but *not*
|
|
|
* device_power_down(). We *must* device_power_down() now.
|
|
@@ -235,18 +246,11 @@ int swsusp_suspend(void)
|
|
|
goto Enable_irqs;
|
|
|
}
|
|
|
|
|
|
- if ((error = save_highmem())) {
|
|
|
- printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
|
|
|
- goto Restore_highmem;
|
|
|
- }
|
|
|
-
|
|
|
save_processor_state();
|
|
|
if ((error = swsusp_arch_suspend()))
|
|
|
printk(KERN_ERR "Error %d suspending\n", error);
|
|
|
/* Restore control flow magically appears here */
|
|
|
restore_processor_state();
|
|
|
-Restore_highmem:
|
|
|
- restore_highmem();
|
|
|
/* NOTE: device_power_up() is just a resume() for devices
|
|
|
* that suspended with irqs off ... no overall powerup.
|
|
|
*/
|
|
@@ -268,18 +272,23 @@ int swsusp_resume(void)
|
|
|
printk(KERN_ERR "Some devices failed to power down, very bad\n");
|
|
|
/* We'll ignore saved state, but this gets preempt count (etc) right */
|
|
|
save_processor_state();
|
|
|
- error = swsusp_arch_resume();
|
|
|
- /* Code below is only ever reached in case of failure. Otherwise
|
|
|
- * execution continues at place where swsusp_arch_suspend was called
|
|
|
- */
|
|
|
- BUG_ON(!error);
|
|
|
+ error = restore_highmem();
|
|
|
+ if (!error) {
|
|
|
+ error = swsusp_arch_resume();
|
|
|
+ /* The code below is only ever reached in case of a failure.
|
|
|
+ * Otherwise execution continues at place where
|
|
|
+ * swsusp_arch_suspend() was called
|
|
|
+ */
|
|
|
+ BUG_ON(!error);
|
|
|
+ /* This call to restore_highmem() undos the previous one */
|
|
|
+ restore_highmem();
|
|
|
+ }
|
|
|
/* The only reason why swsusp_arch_resume() can fail is memory being
|
|
|
* very tight, so we have to free it as soon as we can to avoid
|
|
|
* subsequent failures
|
|
|
*/
|
|
|
swsusp_free();
|
|
|
restore_processor_state();
|
|
|
- restore_highmem();
|
|
|
touch_softlockup_watchdog();
|
|
|
device_power_up();
|
|
|
local_irq_enable();
|