[RFC] MIPS: Communicate reserved memblock regions to the page allocator

From: Justin Chen <hidden>
Date: 2016-11-03 23:01:34
Subsystem: mips, the rest · Maintainers: Thomas Bogendoerfer, Linus Torvalds

Reserved memblock regions were not being communicated to the page allocator.
Our systems use memblock to reserve memory regions to not be used by linux.
The regions of reserved memory in memblock do not seem to be communicated to
the page allocator.

Their are two regions we are concerned with lowmem (region < max_low_pfn) and
highmem (max_low_pfn < region < max_pfn).

Lowmem is managed by bootmem. Reserved memblock regions were already communicated
to bootmem, however in bootmem only regions in lowmem are valid. When trying to
reserve_bootmem regions higher then lowmem the kernel crashes. Fixed this problem
by checking memblock reserved regions before reserving them in bootmem.

Highmem is freed by mem_init_free_highmem(). Memblock reserved regions were being
freed without coordinating with memblock. Fixed this problem by checking with
memblock before freeing pages.

Signed-off-by: Justin Chen <redacted>
---
 arch/mips/kernel/setup.c | 21 +++++++++++++++------
 arch/mips/mm/init.c      |  3 ++-
 2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 6e63a62..9e2330d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -695,15 +695,24 @@ static void __init arch_mem_init(char **cmdline_p)
 	plat_swiotlb_setup();
 	paging_init();
 
-	dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
-	/* Tell bootmem about cma reserved memblock section */
-	for_each_memblock(reserved, reg)
-		if (reg->size != 0)
-			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-
 #ifdef CONFIG_BRCMSTB_MEMORY_API
 	brcmstb_memory_init();
 #endif
+
+	dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
+	/* Tell bootmem about reserved memory blocks in memblock */
+	for_each_memblock(reserved, reg) {
+		if (reg->size != 0)
+			continue;
+		/*
+		 * Bootmem does not have knowledge of high mem, however memblock
+		 * does. Make sure the regions we are reserving reside in bootmem
+		 * range. Bootmem range is anything < max_low_pfn.
+		 */
+		if ((reg->base < PFN_PHYS(max_low_pfn)) &&
+		    ((reg->base + reg->size) <= PFN_PHYS(max_low_pfn)))
+			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+	}
 }
 
 static void __init resource_init(void)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index faa5c98..b17ebf3 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -30,6 +30,7 @@
 #include <linux/hardirq.h>
 #include <linux/gfp.h>
 #include <linux/kcore.h>
+#include <linux/memblock.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/bootinfo.h>
@@ -323,7 +324,7 @@ static inline void mem_init_free_highmem(void)
 	for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
 		struct page *page = pfn_to_page(tmp);
 
-		if (!page_is_ram(tmp))
+		if (!page_is_ram(tmp) || memblock_is_reserved(PFN_PHYS(tmp)))
 			SetPageReserved(page);
 		else
 			free_highmem_page(page);
-- 
2.10.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help