Commit e8eff5ac authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] Make swsusp avoid memory holes and reserved memory regions on x86_64

On x86_64 machines with more than 2 GB of RAM there are large memory gaps
(with no corresponding kernel virtual addresses) and reserved memory
regions between areas of usable physical RAM.  Moreover, if CONFIG_FLATMEM
is set, they appear within the normal zone.  swsusp should not try to save
them, so the corresponding page structs have to be marked as 'nosave'.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Cc: Mel Gorman <mel@csn.ul.ie>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent fb13a28b
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -297,6 +298,53 @@ void __init e820_reserve_resources(void) ...@@ -297,6 +298,53 @@ void __init e820_reserve_resources(void)
} }
} }
/* Mark pages corresponding to given address range as nosave */
static void __init
e820_mark_nosave_range(unsigned long start, unsigned long end)
{
unsigned long pfn, max_pfn;
if (start >= end)
return;
printk("Nosave address range: %016lx - %016lx\n", start, end);
max_pfn = end >> PAGE_SHIFT;
for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
if (pfn_valid(pfn))
SetPageNosave(pfn_to_page(pfn));
}
/*
* Find the ranges of physical addresses that do not correspond to
* e820 RAM areas and mark the corresponding pages as nosave for software
* suspend and suspend to RAM.
*
* This function requires the e820 map to be sorted and without any
* overlapping entries and assumes the first e820 area to be RAM.
*/
void __init e820_mark_nosave_regions(void)
{
int i;
unsigned long paddr;
paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
for (i = 1; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
if (paddr < ei->addr)
e820_mark_nosave_range(paddr,
round_up(ei->addr, PAGE_SIZE));
paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
if (ei->type != E820_RAM)
e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
paddr);
if (paddr >= (end_pfn << PAGE_SHIFT))
break;
}
}
/* /*
* Add a memory region to the kernel e820 map. * Add a memory region to the kernel e820 map.
*/ */
......
...@@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p)
*/ */
probe_roms(); probe_roms();
e820_reserve_resources(); e820_reserve_resources();
e820_mark_nosave_regions();
request_resource(&iomem_resource, &video_ram_resource); request_resource(&iomem_resource, &video_ram_resource);
......
...@@ -46,6 +46,7 @@ extern void setup_memory_region(void); ...@@ -46,6 +46,7 @@ extern void setup_memory_region(void);
extern void contig_e820_setup(void); extern void contig_e820_setup(void);
extern unsigned long e820_end_of_ram(void); extern unsigned long e820_end_of_ram(void);
extern void e820_reserve_resources(void); extern void e820_reserve_resources(void);
extern void e820_mark_nosave_regions(void);
extern void e820_print_map(char *who); extern void e820_print_map(char *who);
extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type); extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type); extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment