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
Signed-off-by: Sudarshan Rajagopalan <sudaraja@codeaurora.org>
This commit is contained in:
Sudarshan Rajagopalan
2021-01-06 20:13:14 -08:00
committed by Suren Baghdasaryan
parent d015c62003
commit 417ac617ea
2 changed files with 76 additions and 0 deletions

View File

@@ -314,6 +314,7 @@ static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
extern void try_offline_node(int nid);
extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
extern int remove_memory(int nid, u64 start, u64 size);
extern int remove_memory_subsection(int nid, u64 start, u64 size);
extern void __remove_memory(int nid, u64 start, u64 size);
extern int offline_and_remove_memory(int nid, u64 start, u64 size);
@@ -340,6 +341,7 @@ extern void clear_zone_contiguous(struct zone *zone);
extern void __ref free_area_init_core_hotplug(int nid);
extern int __add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory_subsection(int nid, u64 start, u64 size);
extern int add_memory_resource(int nid, struct resource *resource,
mhp_t mhp_flags);
extern int add_memory_driver_managed(int nid, u64 start, u64 size,

View File

@@ -1131,6 +1131,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, &params);
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
@@ -1788,6 +1828,40 @@ int remove_memory(int nid, u64 start, u64 size)
}
EXPORT_SYMBOL_GPL(remove_memory);
int remove_memory_subsection(int nid, u64 start, u64 size)
{
if (size == memory_block_size_bytes())
return remove_memory(nid, 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(nid, 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);
/*
* Try to offline and remove a memory block. Might take a long time to
* finish in case memory is still in use. Primarily useful for memory devices