ANDROID: mm/memory_hotplug: implement {add/remove}_memory_subsection
Memory hotplugging is allowed only for multiples of section sizes.
Section size could be huge (ex. 1GB for arm64 targets) thus limiting
to add/remove lower chunks of memory. This patch allows drivers to add
memory of subsection sizes which are then added to memblock. This does
not create a separate memblock device nodes for newly added subsections
until the whole of the memblock section is added.
Bug: 170460867
Change-Id: I15749b5320340cba4d526e7ddb26a9cd6029c690
[quic_sudaraja: remove nid argument from remove_memory_subsection]
Signed-off-by: Sudarshan Rajagopalan <quic_sudaraja@quicinc.com>
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 9fd0be3..a23cb84 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1490,6 +1490,46 @@ int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags)
}
EXPORT_SYMBOL_GPL(add_memory);
+int add_memory_subsection(int nid, u64 start, u64 size)
+{
+ struct mhp_params params = { .pgprot = PAGE_KERNEL };
+ struct resource *res;
+ int ret;
+
+ if (size == memory_block_size_bytes())
+ return add_memory(nid, start, size, MHP_NONE);
+
+ if (!IS_ALIGNED(start, SUBSECTION_SIZE) ||
+ !IS_ALIGNED(size, SUBSECTION_SIZE)) {
+ pr_err("%s: start 0x%lx size 0x%lx not aligned to subsection size\n",
+ __func__, start, size);
+ return -EINVAL;
+ }
+
+ res = register_memory_resource(start, size, "System RAM");
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ mem_hotplug_begin();
+
+ nid = memory_add_physaddr_to_nid(start);
+
+ if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
+ memblock_add_node(start, size, nid);
+
+ ret = arch_add_memory(nid, start, size, ¶ms);
+ if (ret) {
+ if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
+ memblock_remove(start, size);
+ pr_err("%s failed to add subsection start 0x%lx size 0x%lx\n",
+ __func__, start, size);
+ }
+ mem_hotplug_done();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(add_memory_subsection);
+
/*
* Add special, driver-managed memory to the system as system RAM. Such
* memory is not exposed via the raw firmware-provided memmap as system
@@ -2253,6 +2293,40 @@ int remove_memory(u64 start, u64 size)
}
EXPORT_SYMBOL_GPL(remove_memory);
+int remove_memory_subsection(u64 start, u64 size)
+{
+ if (size == memory_block_size_bytes())
+ return remove_memory(start, size);
+
+ if (!IS_ALIGNED(start, SUBSECTION_SIZE) ||
+ !IS_ALIGNED(size, SUBSECTION_SIZE)) {
+ pr_err("%s: start 0x%lx size 0x%lx not aligned to subsection size\n",
+ __func__, start, size);
+ return -EINVAL;
+ }
+
+ mem_hotplug_begin();
+
+ if (test_pages_isolated(start, start + size, MEMORY_OFFLINE)) {
+ pr_err("%s: [%lx, %lx) PFNs are not isolated\n",
+ __func__, start, start + size);
+ mem_hotplug_done();
+ return -EBUSY;
+ }
+
+ arch_remove_memory(start, size, NULL);
+
+ if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
+ memblock_remove(start, size);
+
+ release_mem_region_adjustable(start, size);
+
+ mem_hotplug_done();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(remove_memory_subsection);
+
static int try_offline_memory_block(struct memory_block *mem, void *arg)
{
uint8_t online_type = MMOP_ONLINE_KERNEL;