From e39b3da82e65da93934df483903464b2c3c3510a Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Fri, 27 Apr 2018 14:41:03 -0700 Subject: [PATCH] arm64: Override memory limit set by boot parameter To guarantee successful hot-plugging of memory blocks, these blocks should belong to ZONE_MOVABLE which has migratable pages. Linux kernel during boot initializes all the available memory blocks to ZONE_DMA and ZONE_NORMAL. Hence, boot the system with less memory whose percentage is given by mem-offline DT property 'mem-percent' and override any memory limit imposed by kernel boot params and let mem-offline driver initialize the remaining with ZONE_MOVABLE. The memory blocks in this zone are applicable for memory offlining. Change-Id: Ia7b804522fe9425101ee83d1ee354ed09483df13 Signed-off-by: Sudarshan Rajagopalan [swatsrid@codeaurora.org: Fix merge conflicts] Signed-off-by: Swathi Sridhar Signed-off-by: Isaac J. Manjarres --- arch/arm64/mm/init.c | 48 ++++++++++++++++++++++++++++++++++++++++ drivers/soc/qcom/Kconfig | 10 +++++++++ 2 files changed, 58 insertions(+) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 3184ceccc288..3710fb71b50b 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -259,6 +261,51 @@ EXPORT_SYMBOL(pfn_valid); static phys_addr_t memory_limit = PHYS_ADDR_MAX; phys_addr_t bootloader_memory_limit; +#ifdef CONFIG_OVERRIDE_MEMORY_LIMIT +static void __init update_memory_limit(void) +{ + unsigned long dt_root = of_get_flat_dt_root(); + unsigned long node, mp; + const char *p; + unsigned long long ram_sz, sz; + int ret; + + ram_sz = memblock_end_of_DRAM() - memblock_start_of_DRAM(); + 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"); + return; + } + p = of_get_flat_dt_prop(node, "mem-percent", NULL); + if (!p) { + pr_err("mem-offine: mem-percent property not found in FDT\n"); + return; + } + + ret = kstrtoul(p, 10, &mp); + if (ret) { + pr_err("mem-offine: kstrtoul failed\n"); + return; + } + + if (mp > 100) { + pr_err("mem-offine: Invalid mem-percent DT property\n"); + return; + } + sz = ram_sz - ((ram_sz * mp) / 100); + memory_limit = (phys_addr_t)sz; + memory_limit = ALIGN(memory_limit, MIN_MEMORY_BLOCK_SIZE); + + pr_notice("Memory limit set/overridden to %lldMB\n", + memory_limit >> 20); +} +#else +static void __init update_memory_limit(void) +{ + +} +#endif + /* * Limit the memory size that was specified via FDT. */ @@ -350,6 +397,7 @@ void __init arm64_memblock_init(void) memblock_remove(0, memstart_addr); } + update_memory_limit(); /* * Save bootloader imposed memory limit before we overwirte * memblock. diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 717163231ccd..67f6406240c8 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -66,6 +66,16 @@ config QCOM_GENI_SE driver is also used to manage the common aspects of multiple Serial Engines present in the QUP. +config OVERRIDE_MEMORY_LIMIT + bool "Override memory limit set by the kernel boot parameter" + depends on QCOM_MEM_OFFLINE + help + Override any memory limit set by the kernel boot parameter with + limit set by mem-offline dt entry so that memory offline framework + can initialize remaining memory with movable pages for memory + hot-plugging. + If unsure, say N + config QCOM_GLINK_SSR tristate "Qualcomm Glink SSR driver" depends on RPMSG