From 1f1fb52ed29aa026a6e63b169259f4b7532efce0 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 28 Sep 2018 11:28:55 -0700 Subject: [PATCH] soc: qcom: mem-offline: Set offlinable region based on minimum DDR sizes Currently we use a percentage property value to determine the amount of offlinable memory in the system. However a percentage property doesn't support accurately configuring the offlinable region sizes on targets with different amounts of DDR. For example it is not possible to configure the system such that 4GB targets won't have any offlinable region, 6GB targets will have a 1GB offlinable region and 8GB targets having a 3GB offlinable region without creating a separate DT files for each target. Many customers want to be able to support different DDR sizes without creating separate DT files for each target. Replace the mem-percent property with an offline-sizes property which contains an array of offlinable memory region sizes to apply to targets based on their DDR size. Change-Id: I93210beec153ca0179c0087ce98afd4dfc22ea02 Signed-off-by: Liam Mark Signed-off-by: Isaac J. Manjarres --- arch/arm64/mm/init.c | 53 +++++++++++++++++++++++++++++++------------ drivers/base/memory.c | 2 +- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 03b857e34b60..a91f9963a4b9 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -266,11 +266,13 @@ phys_addr_t bootloader_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 node; unsigned long long ram_sz, sz; phys_addr_t end_addr, addr_aligned, offset; - int ret; + int len; + const __be32 *prop; + phys_addr_t min_ddr_sz = 0, offline_sz = 0; + int t_len = (2 * dt_root_size_cells) * sizeof(__be32); ram_sz = memblock_phys_mem_size(); node = of_get_flat_dt_subnode_by_name(dt_root, "mem-offline"); @@ -278,23 +280,46 @@ static void __init update_memory_limit(void) 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"); + + prop = of_get_flat_dt_prop(node, "offline-sizes", &len); + if (prop) { + if (len % t_len != 0) { + pr_err("mem-offline: invalid offline-sizes property\n"); + return; + } + + while (len > 0) { + phys_addr_t tmp_min_ddr_sz = dt_mem_next_cell( + dt_root_addr_cells, + &prop); + phys_addr_t tmp_offline_sz = dt_mem_next_cell( + dt_root_size_cells, + &prop); + + if (tmp_min_ddr_sz < ram_sz && + tmp_min_ddr_sz > min_ddr_sz) { + if (tmp_offline_sz < ram_sz) { + min_ddr_sz = tmp_min_ddr_sz; + offline_sz = tmp_offline_sz; + } else { + pr_info("mem-offline: invalid offline size:%pa\n", + &tmp_offline_sz); + } + } + len -= t_len; + } + } else { + pr_err("mem-offine: offline-sizes property not found in DT\n"); return; } - ret = kstrtoul(p, 10, &mp); - if (ret) { - pr_err("mem-offine: kstrtoul failed\n"); + if (offline_sz == 0) { + pr_info("mem-offline: no memory to offline for DDR size:%llu\n", + ram_sz); return; } - if (mp > 100) { - pr_err("mem-offine: Invalid mem-percent DT property\n"); - return; - } - sz = ram_sz - ((ram_sz * mp) / 100); + sz = ram_sz - offline_sz; memory_limit = (phys_addr_t)sz; end_addr = memblock_max_addr(memory_limit); addr_aligned = ALIGN(end_addr, MIN_MEMORY_BLOCK_SIZE); diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 5e8e268b0cd2..a0d5491afdb9 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -473,7 +473,7 @@ static ssize_t allocated_bytes_show(struct device *dev, &NODE_DATA(numa_node_id())->node_zones[ZONE_MOVABLE]; unsigned long used, block_sz = memory_block_size_bytes(); - if (mem->state != MEM_ONLINE) + if (!populated_zone(movable_zone) || mem->state != MEM_ONLINE) return snprintf(buf, 100, "0\n"); block_id = base_memory_block_id(mem->start_section_nr);