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>
This commit is contained in:
Sudarshan Rajagopalan
2021-12-07 13:14:46 -08:00
committed by Todd Kjos
parent 3654b006f0
commit 6cb6c8c42e
2 changed files with 76 additions and 0 deletions

View File

@@ -282,6 +282,7 @@ extern void try_offline_node(int nid);
extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages,
struct zone *zone, struct memory_group *group);
extern int remove_memory(u64 start, u64 size);
extern int remove_memory_subsection(u64 start, u64 size);
extern void __remove_memory(u64 start, u64 size);
extern int offline_and_remove_memory(u64 start, u64 size);
@@ -306,6 +307,7 @@ static inline void __remove_memory(u64 start, u64 size) {}
extern void __ref free_area_init_core_hotplug(struct pglist_data *pgdat);
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

@@ -1607,6 +1607,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%llx size 0x%llx 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, MEMBLOCK_NONE);
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%llx size 0x%llx\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
@@ -2320,6 +2360,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%llx size 0x%llx 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: [%llx, %llx) 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;