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>
This commit is contained in:
parent
7b7bf499f7
commit
40f7bfe4f1
1 changed files with 5 additions and 4 deletions
|
@ -763,15 +763,12 @@ static void __init sanity_check_meminfo(void)
|
||||||
{
|
{
|
||||||
int i, j, highmem = 0;
|
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++) {
|
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
|
||||||
struct membank *bank = &meminfo.bank[j];
|
struct membank *bank = &meminfo.bank[j];
|
||||||
*bank = meminfo.bank[i];
|
*bank = meminfo.bank[i];
|
||||||
|
|
||||||
#ifdef CONFIG_HIGHMEM
|
#ifdef CONFIG_HIGHMEM
|
||||||
if (__va(bank->start) > vmalloc_min ||
|
if (__va(bank->start) >= vmalloc_min ||
|
||||||
__va(bank->start) < (void *)PAGE_OFFSET)
|
__va(bank->start) < (void *)PAGE_OFFSET)
|
||||||
highmem = 1;
|
highmem = 1;
|
||||||
|
|
||||||
|
@ -829,6 +826,9 @@ static void __init sanity_check_meminfo(void)
|
||||||
bank->size = newsize;
|
bank->size = newsize;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (!bank->highmem && bank->start + bank->size > lowmem_limit)
|
||||||
|
lowmem_limit = bank->start + bank->size;
|
||||||
|
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_HIGHMEM
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
@ -852,6 +852,7 @@ static void __init sanity_check_meminfo(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
meminfo.nr_banks = j;
|
meminfo.nr_banks = j;
|
||||||
|
memblock_set_current_limit(lowmem_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void prepare_page_table(void)
|
static inline void prepare_page_table(void)
|
||||||
|
|
Loading…
Reference in a new issue