free_memmap() and sparsemem

Catalin Marinas catalin.marinas at
Wed Sep 9 06:57:35 EDT 2009

Hi Russell,

I haven't followed the full thread on omap and memory holes but I got an
issue on RealView PBX with sparsemem enabled (patches not pushed yet for
mainline). Basically I'm using this configuration:

256MB @ 0x00000000 -> PAGE_OFFSET
512MB @ 0x20000000 -> PAGE_OFFSET + 0x10000000
256MB @ 0x80000000 -> PAGE_OFFSET + 0x20000000

I could only use two banks (the second at 0x70000000) but I need the
first 256MB for DMA (since Linux only accepts DMA zone to be at the
bottom). The phys_to_virt/virt_to_phys macros were modified to provide a
contiguous translation to virtual addresses.

Anyway, the free_memmap() called from free_unused_memmap_node()
shouldn't actually do much with sparsemem because the way the page
arrays are structured. In theory, start_pg and end_pg should be the same
but because the start_pfn passed to this function doesn't belong to any
node, it gets some random values for start_pg. The patch below solved
the problem for me:

Fix the start_pg value in free_memmap()

From: Catalin Marinas <catalin.marinas at>

If sparsemem is enabled, the start_pfn passed to the free_memmap()
function corresponds to an area of memory not known to the kernel and
pfn_to_page returns a wrong value. The (start_pfn - 1), however, is
known to the kernel.

Signed-off-by: Catalin Marinas <catalin.marinas at>
 arch/arm/mm/init.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 82c4b42..b0423b7 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -419,7 +419,7 @@ free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
 	 * Convert start_pfn/end_pfn to a struct page pointer.
-	start_pg = pfn_to_page(start_pfn);
+	start_pg = pfn_to_page(start_pfn - 1) + 1;
 	end_pg = pfn_to_page(end_pfn);


More information about the linux-arm-kernel mailing list