diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 3710fb71b50b..20982031fad8 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -268,9 +269,10 @@ static void __init update_memory_limit(void) unsigned long node, mp; const char *p; unsigned long long ram_sz, sz; + phys_addr_t end_addr, addr_aligned, offset; int ret; - ram_sz = memblock_end_of_DRAM() - memblock_start_of_DRAM(); + ram_sz = memblock_phys_mem_size(); node = of_get_flat_dt_subnode_by_name(dt_root, "mem-offline"); if (node == -FDT_ERR_NOTFOUND) { pr_err("mem-offine node not found in FDT\n"); @@ -294,7 +296,17 @@ static void __init update_memory_limit(void) } sz = ram_sz - ((ram_sz * mp) / 100); memory_limit = (phys_addr_t)sz; - memory_limit = ALIGN(memory_limit, MIN_MEMORY_BLOCK_SIZE); + end_addr = memblock_max_addr(memory_limit); + addr_aligned = ALIGN(end_addr, MIN_MEMORY_BLOCK_SIZE); + offset = addr_aligned - end_addr; + + if (offset > MIN_MEMORY_BLOCK_SIZE / 2) { + addr_aligned = ALIGN_DOWN(end_addr, MIN_MEMORY_BLOCK_SIZE); + offset = end_addr - addr_aligned; + memory_limit -= offset; + } else { + memory_limit += offset; + } pr_notice("Memory limit set/overridden to %lldMB\n", memory_limit >> 20); diff --git a/include/linux/memblock.h b/include/linux/memblock.h index f491690d54c6..ead74b4b6725 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -441,6 +441,7 @@ phys_addr_t memblock_reserved_size(void); phys_addr_t memblock_mem_size(unsigned long limit_pfn); phys_addr_t memblock_start_of_DRAM(void); phys_addr_t memblock_end_of_DRAM(void); +phys_addr_t memblock_max_addr(phys_addr_t limit); void memblock_enforce_memory_limit(phys_addr_t memory_limit); void memblock_cap_memory_range(phys_addr_t base, phys_addr_t size); void memblock_mem_limit_remove_map(phys_addr_t limit); diff --git a/mm/memblock.c b/mm/memblock.c index c4b16cae2bc9..184d3636f85a 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1645,6 +1645,11 @@ static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) return max_addr; } +phys_addr_t __init_memblock memblock_max_addr(phys_addr_t limit) +{ + return __find_max_addr(limit); +} + void __init memblock_enforce_memory_limit(phys_addr_t limit) { phys_addr_t max_addr = PHYS_ADDR_MAX;