From 42be9559071c84ffd64865680e012b0c8252c2c7 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 5 Jul 2018 18:41:13 -0700 Subject: [PATCH] arm64: mm/memblock: Update memory limit calculation The system RAM region would not be ideally contiguous from start to end of DRAM. Detect any offset/holes present in the DDR region and update the memory limit being set, so that the DRAM end address is aligned to the memory block size. This is a requirement for mem-offline framework to work properly. Change-Id: I97cb0cce70e7c414ae2d200a4a3f714d145c0e64 Signed-off-by: Sudarshan Rajagopalan Signed-off-by: Isaac J. Manjarres --- arch/arm64/mm/init.c | 16 ++++++++++++++-- include/linux/memblock.h | 1 + mm/memblock.c | 5 +++++ 3 files changed, 20 insertions(+), 2 deletions(-) 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;