Loading Documentation/devicetree/bindings/arm/msm/memory-offline.txt +24 −4 Original line number Diff line number Diff line Loading @@ -16,9 +16,28 @@ see the memory hotplug documentation (Documentation/memory-hotplug.txt). Required properties: - compatible: "qcom,mem-offline" - granule: The minimum granule size in mega-bytes for memory onlining/offlining. - mem-percent: Percentage of the DDR which will support being onlined/offlined. The system will round down the value to align with the minimum offlinable granule size supported by DDR. - offline-sizes: Array of offlinable memory region sizes to apply to targets based on their DDR size. Each entry in the array is a pair of sizes, where the first size in the pair is the minimum amount of DDR required in the system in bytes, and the second item in the pair is the size of the offlinable region in bytes which will be applied to the system. The offlinable memory region size from the entry where the minimum amount of DDR required in the system is closest, but not greater, than the amount of DDR in the system will be applied. If there are no entries with a minimum amount of DDR required that is less than the amount of DDR in the system then no offlinable region will be created. For example, in the following configuration: offline-sizes = <0x1 0x40000000 0x0 0x40000000>, <0x1 0xc0000000 0x0 0x80000000>; On a 4GB target no offlinable region will be created. On a 6GB target a 1GB offlinable region will be created. On an 8GB target a 2GB offlinable region will be created. On a 12GB target a 2GB offlinable region will be created. - mboxes: Reference to the mailbox used by the driver to make requests to online/offline memory. Loading @@ -26,6 +45,7 @@ Example: mem-offline { compatible = "qcom,mem-offline"; granule = <512>; mem-percent = "35"; offline-sizes = <0x1 0x40000000 0x0 0x40000000>, <0x1 0xc0000000 0x0 0x80000000>; mboxes = <&qmp_aop 0>; }; arch/arm64/mm/init.c +39 −14 Original line number Diff line number Diff line Loading @@ -324,11 +324,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"); Loading @@ -336,23 +338,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; } ret = kstrtoul(p, 10, &mp); if (ret) { pr_err("mem-offine: kstrtoul failed\n"); 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; } if (mp > 100) { pr_err("mem-offine: Invalid mem-percent DT property\n"); if (offline_sz == 0) { pr_info("mem-offline: no memory to offline for DDR size:%llu\n", ram_sz); 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); Loading drivers/base/memory.c +1 −1 Original line number Diff line number Diff line Loading @@ -487,7 +487,7 @@ static ssize_t allocated_bytes_show(struct device *dev, &NODE_DATA(numa_node_id())->node_zones[ZONE_MOVABLE]; unsigned long used, block_sz = get_memory_block_size(); 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); Loading drivers/soc/qcom/mem-offline.c +9 −3 Original line number Diff line number Diff line Loading @@ -188,8 +188,8 @@ static int mem_online_remaining_blocks(void) start_section_nr = pfn_to_section_nr(memblock_end_pfn); end_section_nr = pfn_to_section_nr(ram_end_pfn); if (start_section_nr == end_section_nr) { pr_err("mem-offline: System booted with no zone movable memory blocks. Cannot perform memory offlining\n"); if (start_section_nr >= end_section_nr) { pr_info("mem-offline: System booted with no zone movable memory blocks. Cannot perform memory offlining\n"); return -EINVAL; } for (memblock = start_section_nr; memblock <= end_section_nr; Loading Loading @@ -361,10 +361,16 @@ static struct notifier_block hotplug_memory_callback_nb = { static int mem_offline_driver_probe(struct platform_device *pdev) { int ret; if (mem_parse_dt(pdev)) return -ENODEV; if (mem_online_remaining_blocks()) ret = mem_online_remaining_blocks(); if (ret < 0) return -ENODEV; if (ret > 0) pr_err("mem-offline: !!ERROR!! Auto onlining some memory blocks failed. System could run with less RAM\n"); if (mem_sysfs_init()) Loading Loading
Documentation/devicetree/bindings/arm/msm/memory-offline.txt +24 −4 Original line number Diff line number Diff line Loading @@ -16,9 +16,28 @@ see the memory hotplug documentation (Documentation/memory-hotplug.txt). Required properties: - compatible: "qcom,mem-offline" - granule: The minimum granule size in mega-bytes for memory onlining/offlining. - mem-percent: Percentage of the DDR which will support being onlined/offlined. The system will round down the value to align with the minimum offlinable granule size supported by DDR. - offline-sizes: Array of offlinable memory region sizes to apply to targets based on their DDR size. Each entry in the array is a pair of sizes, where the first size in the pair is the minimum amount of DDR required in the system in bytes, and the second item in the pair is the size of the offlinable region in bytes which will be applied to the system. The offlinable memory region size from the entry where the minimum amount of DDR required in the system is closest, but not greater, than the amount of DDR in the system will be applied. If there are no entries with a minimum amount of DDR required that is less than the amount of DDR in the system then no offlinable region will be created. For example, in the following configuration: offline-sizes = <0x1 0x40000000 0x0 0x40000000>, <0x1 0xc0000000 0x0 0x80000000>; On a 4GB target no offlinable region will be created. On a 6GB target a 1GB offlinable region will be created. On an 8GB target a 2GB offlinable region will be created. On a 12GB target a 2GB offlinable region will be created. - mboxes: Reference to the mailbox used by the driver to make requests to online/offline memory. Loading @@ -26,6 +45,7 @@ Example: mem-offline { compatible = "qcom,mem-offline"; granule = <512>; mem-percent = "35"; offline-sizes = <0x1 0x40000000 0x0 0x40000000>, <0x1 0xc0000000 0x0 0x80000000>; mboxes = <&qmp_aop 0>; };
arch/arm64/mm/init.c +39 −14 Original line number Diff line number Diff line Loading @@ -324,11 +324,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"); Loading @@ -336,23 +338,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; } ret = kstrtoul(p, 10, &mp); if (ret) { pr_err("mem-offine: kstrtoul failed\n"); 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; } if (mp > 100) { pr_err("mem-offine: Invalid mem-percent DT property\n"); if (offline_sz == 0) { pr_info("mem-offline: no memory to offline for DDR size:%llu\n", ram_sz); 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); Loading
drivers/base/memory.c +1 −1 Original line number Diff line number Diff line Loading @@ -487,7 +487,7 @@ static ssize_t allocated_bytes_show(struct device *dev, &NODE_DATA(numa_node_id())->node_zones[ZONE_MOVABLE]; unsigned long used, block_sz = get_memory_block_size(); 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); Loading
drivers/soc/qcom/mem-offline.c +9 −3 Original line number Diff line number Diff line Loading @@ -188,8 +188,8 @@ static int mem_online_remaining_blocks(void) start_section_nr = pfn_to_section_nr(memblock_end_pfn); end_section_nr = pfn_to_section_nr(ram_end_pfn); if (start_section_nr == end_section_nr) { pr_err("mem-offline: System booted with no zone movable memory blocks. Cannot perform memory offlining\n"); if (start_section_nr >= end_section_nr) { pr_info("mem-offline: System booted with no zone movable memory blocks. Cannot perform memory offlining\n"); return -EINVAL; } for (memblock = start_section_nr; memblock <= end_section_nr; Loading Loading @@ -361,10 +361,16 @@ static struct notifier_block hotplug_memory_callback_nb = { static int mem_offline_driver_probe(struct platform_device *pdev) { int ret; if (mem_parse_dt(pdev)) return -ENODEV; if (mem_online_remaining_blocks()) ret = mem_online_remaining_blocks(); if (ret < 0) return -ENODEV; if (ret > 0) pr_err("mem-offline: !!ERROR!! Auto onlining some memory blocks failed. System could run with less RAM\n"); if (mem_sysfs_init()) Loading