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:

committed by
Suren Baghdasaryan

parent
d015c62003
commit
417ac617ea
@@ -314,6 +314,7 @@ static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
|
|||||||
extern void try_offline_node(int nid);
|
extern void try_offline_node(int nid);
|
||||||
extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
|
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(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 void __remove_memory(int nid, u64 start, u64 size);
|
||||||
extern int offline_and_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 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(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,
|
extern int add_memory_resource(int nid, struct resource *resource,
|
||||||
mhp_t mhp_flags);
|
mhp_t mhp_flags);
|
||||||
extern int add_memory_driver_managed(int nid, u64 start, u64 size,
|
extern int add_memory_driver_managed(int nid, u64 start, u64 size,
|
||||||
|
@@ -1131,6 +1131,46 @@ int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(add_memory);
|
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
|
* Add special, driver-managed memory to the system as system RAM. Such
|
||||||
* memory is not exposed via the raw firmware-provided memmap as system
|
* 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);
|
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
|
* 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
|
* finish in case memory is still in use. Primarily useful for memory devices
|
||||||
|
Reference in New Issue
Block a user