aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-09-26 02:32:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:58 -0400
commite8eff5ac294e12531c4195e0c15a222d3c9015e5 (patch)
treed63a3f26e506c3468e071377fec7aa9944f24764
parentfb13a28b0f5ada60861868c4fa48a12bd0cb8dea (diff)
[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: 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>
-rw-r--r--arch/x86_64/kernel/e820.c48
-rw-r--r--arch/x86_64/kernel/setup.c1
-rw-r--r--include/asm-x86_64/e820.h1
3 files changed, 50 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index d6d7f731f6f0..708a3cd9a27e 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -16,6 +16,7 @@
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/kexec.h> 17#include <linux/kexec.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/mm.h>
19 20
20#include <asm/pgtable.h> 21#include <asm/pgtable.h>
21#include <asm/page.h> 22#include <asm/page.h>
@@ -297,6 +298,53 @@ void __init e820_reserve_resources(void)
297 } 298 }
298} 299}
299 300
301/* Mark pages corresponding to given address range as nosave */
302static void __init
303e820_mark_nosave_range(unsigned long start, unsigned long end)
304{
305 unsigned long pfn, max_pfn;
306
307 if (start >= end)
308 return;
309
310 printk("Nosave address range: %016lx - %016lx\n", start, end);
311 max_pfn = end >> PAGE_SHIFT;
312 for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
313 if (pfn_valid(pfn))
314 SetPageNosave(pfn_to_page(pfn));
315}
316
317/*
318 * Find the ranges of physical addresses that do not correspond to
319 * e820 RAM areas and mark the corresponding pages as nosave for software
320 * suspend and suspend to RAM.
321 *
322 * This function requires the e820 map to be sorted and without any
323 * overlapping entries and assumes the first e820 area to be RAM.
324 */
325void __init e820_mark_nosave_regions(void)
326{
327 int i;
328 unsigned long paddr;
329
330 paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
331 for (i = 1; i < e820.nr_map; i++) {
332 struct e820entry *ei = &e820.map[i];
333
334 if (paddr < ei->addr)
335 e820_mark_nosave_range(paddr,
336 round_up(ei->addr, PAGE_SIZE));
337
338 paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
339 if (ei->type != E820_RAM)
340 e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
341 paddr);
342
343 if (paddr >= (end_pfn << PAGE_SHIFT))
344 break;
345 }
346}
347
300/* 348/*
301 * Add a memory region to the kernel e820 map. 349 * Add a memory region to the kernel e820 map.
302 */ 350 */
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 34afad704824..4b39f0da17f3 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p)
689 */ 689 */
690 probe_roms(); 690 probe_roms();
691 e820_reserve_resources(); 691 e820_reserve_resources();
692 e820_mark_nosave_regions();
692 693
693 request_resource(&iomem_resource, &video_ram_resource); 694 request_resource(&iomem_resource, &video_ram_resource);
694 695
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
index 670a3388e70a..f65674832318 100644
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -46,6 +46,7 @@ extern void setup_memory_region(void);
46extern void contig_e820_setup(void); 46extern void contig_e820_setup(void);
47extern unsigned long e820_end_of_ram(void); 47extern unsigned long e820_end_of_ram(void);
48extern void e820_reserve_resources(void); 48extern void e820_reserve_resources(void);
49extern void e820_mark_nosave_regions(void);
49extern void e820_print_map(char *who); 50extern void e820_print_map(char *who);
50extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type); 51extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
51extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type); 52extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);