Skip to content

Commit

Permalink
[PATCH] Make swsusp avoid memory holes and reserved memory regions on…
Browse files Browse the repository at this point in the history
… 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: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Mel Gorman <mel@csn.ul.ie>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Rafael J. Wysocki authored and Linus Torvalds committed Sep 26, 2006
1 parent fb13a28 commit e8eff5a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
48 changes: 48 additions & 0 deletions arch/x86_64/kernel/e820.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/mm.h>

#include <asm/pgtable.h>
#include <asm/page.h>
Expand Down Expand Up @@ -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.
*/
Expand Down
1 change: 1 addition & 0 deletions arch/x86_64/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p)
*/
probe_roms();
e820_reserve_resources();
e820_mark_nosave_regions();

request_resource(&iomem_resource, &video_ram_resource);

Expand Down
1 change: 1 addition & 0 deletions include/asm-x86_64/e820.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern void setup_memory_region(void);
extern void contig_e820_setup(void);
extern unsigned long e820_end_of_ram(void);
extern void e820_reserve_resources(void);
extern void e820_mark_nosave_regions(void);
extern void e820_print_map(char *who);
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);
Expand Down

0 comments on commit e8eff5a

Please sign in to comment.