Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b6a3be1 authored by Liam Mark's avatar Liam Mark Committed by Ashwini Muduganti
Browse files

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: default avatarLiam Mark <lmark@codeaurora.org>
parent 3865afec
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -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.

@@ -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>;
  };
+2 −2
Original line number Diff line number Diff line
@@ -40,8 +40,8 @@

	mem-offline {
		compatible = "qcom,mem-offline";
		/* 1 Gb out of 6 Gb*/
		mem-percent = "17";
		offline-sizes = <0x1 0x40000000 0x0 0x40000000>,
				<0x1 0xc0000000 0x0 0x80000000>;
		granule = <512>;
		mboxes = <&qmp_aop 0>;
	};
+39 −14
Original line number Diff line number Diff line
@@ -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");
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -485,7 +485,7 @@ static ssize_t show_allocated_bytes(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);
+9 −3
Original line number Diff line number Diff line
@@ -196,8 +196,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;
@@ -369,10 +369,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())