From 40f7bfe4f1c2761abeceb3b2b9dc1feec3c47ed9 Mon Sep 17 00:00:00 2001
From: Will Deacon <will.deacon@arm.com>
Date: Thu, 19 May 2011 13:22:48 +0100
Subject: [PATCH] ARM: 6914/1: sparsemem: fix highmem detection when using
 SPARSEMEM

sanity_check_meminfo walks over the registered memory banks and attempts
to split banks across lowmem and highmem when they would otherwise
overlap with the vmalloc space.

When SPARSEMEM is used, there are two potential problems that occur
when the virtual address of the start of a bank is equal to vmalloc_min.

 1.) The end of lowmem is calculated as __pa(vmalloc_min - 1) + 1.
     In the above scenario, this will give the end address of the
     previous bank, rather than the actual bank we are interested in.
     This value is later used as the memblock limit and artificially
     restricts the total amount of available memory.

 2.) The checks to determine whether or not a bank belongs to highmem
     or not only check if __va(bank->start) is greater or less than
     vmalloc_min. In the case that it is equal, the bank is incorrectly
     treated as lowmem, which hoses the vmalloc area.

This patch fixes these two problems by checking whether the virtual
start address of a bank is >= vmalloc_min and then calculating
lowmem_end by finding the virtual end address of the highest lowmem
bank.

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/mmu.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 08a92368d9d3..9d9e736c2b4f 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -763,15 +763,12 @@ static void __init sanity_check_meminfo(void)
 {
 	int i, j, highmem = 0;
 
-	lowmem_limit = __pa(vmalloc_min - 1) + 1;
-	memblock_set_current_limit(lowmem_limit);
-
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
 		*bank = meminfo.bank[i];
 
 #ifdef CONFIG_HIGHMEM
-		if (__va(bank->start) > vmalloc_min ||
+		if (__va(bank->start) >= vmalloc_min ||
 		    __va(bank->start) < (void *)PAGE_OFFSET)
 			highmem = 1;
 
@@ -829,6 +826,9 @@ static void __init sanity_check_meminfo(void)
 			bank->size = newsize;
 		}
 #endif
+		if (!bank->highmem && bank->start + bank->size > lowmem_limit)
+			lowmem_limit = bank->start + bank->size;
+
 		j++;
 	}
 #ifdef CONFIG_HIGHMEM
@@ -852,6 +852,7 @@ static void __init sanity_check_meminfo(void)
 	}
 #endif
 	meminfo.nr_banks = j;
+	memblock_set_current_limit(lowmem_limit);
 }
 
 static inline void prepare_page_table(void)
-- 
2.34.1