|
@@ -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>
|
|
@@ -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.
|
|
|
*/
|