mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-26 12:30:23 +09:00
ANDROID: arm64/mm: implement {populate/depopulate}_range_driver_managed
After certain memory blocks are offlined, some usecases require that the
page-table mappings are removed while still keeping the memblock device nodes,
memory resources and the memmap entries intact. This is to avoid the overhead
involved in using 'remove_memory' if the offlined blocks will be added/onlined
back into the system at later point. {populate/depopulate}_range_driver_managed
provide the abilty to drivers to tear-down and create page-table mappings of
memory blocks that its managing, without having to use 'remove_memory' and
friends for the purpose.
These functions does not interfere with mappings of boot memory or resources
that isn't owned by the driver.
Bug: 171907330
Change-Id: Ie11201334bd7438bf87f933ccc81814fa99162c4
Signed-off-by: Sudarshan Rajagopalan <sudaraja@codeaurora.org>
This commit is contained in:
committed by
Suren Baghdasaryan
parent
c7ba09ce6a
commit
1b4aca7d82
@@ -530,6 +530,13 @@ extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
|
||||
|
||||
extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
|
||||
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
extern int populate_range_driver_managed(u64 start, u64 size,
|
||||
const char *resource_name);
|
||||
extern int depopulate_range_driver_managed(u64 start, u64 size,
|
||||
const char *resource_name);
|
||||
#endif
|
||||
|
||||
static inline bool in_swapper_pgdir(void *addr)
|
||||
{
|
||||
return ((unsigned long)addr & PAGE_MASK) ==
|
||||
|
||||
@@ -1496,6 +1496,71 @@ void arch_remove_memory(int nid, u64 start, u64 size,
|
||||
__remove_pgd_mapping(swapper_pg_dir, __phys_to_virt(start), size);
|
||||
}
|
||||
|
||||
int check_range_driver_managed(u64 start, u64 size, const char *resource_name)
|
||||
{
|
||||
struct mem_section *ms;
|
||||
unsigned long pfn = __phys_to_pfn(start);
|
||||
unsigned long end_pfn = __phys_to_pfn(start + size);
|
||||
struct resource *res;
|
||||
unsigned long flags;
|
||||
|
||||
res = lookup_resource(&iomem_resource, start);
|
||||
if (!res) {
|
||||
pr_err("%s: couldn't find memory resource for start 0x%lx\n",
|
||||
__func__, start);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = res->flags;
|
||||
|
||||
if (!(flags & IORESOURCE_SYSRAM_DRIVER_MANAGED) ||
|
||||
strstr(resource_name, "System RAM (") != resource_name)
|
||||
return -EINVAL;
|
||||
|
||||
for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
|
||||
ms = __pfn_to_section(pfn);
|
||||
if (early_section(ms))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int populate_range_driver_managed(u64 start, u64 size,
|
||||
const char *resource_name)
|
||||
{
|
||||
unsigned long virt = (unsigned long)phys_to_virt(start);
|
||||
int flags = 0;
|
||||
|
||||
if (check_range_driver_managed(start, size, resource_name))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* When rodata_full is enabled, memory is mapped at page size granule,
|
||||
* as opposed to block mapping.
|
||||
*/
|
||||
if (rodata_full || debug_pagealloc_enabled())
|
||||
flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||||
|
||||
__create_pgd_mapping(init_mm.pgd, start, virt, size,
|
||||
PAGE_KERNEL, NULL, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(populate_range_driver_managed);
|
||||
|
||||
int depopulate_range_driver_managed(u64 start, u64 size,
|
||||
const char *resource_name)
|
||||
{
|
||||
if (check_range_driver_managed(start, size, resource_name))
|
||||
return -EINVAL;
|
||||
|
||||
unmap_hotplug_range(start, start + size, false, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(depopulate_range_driver_managed);
|
||||
|
||||
/*
|
||||
* This memory hotplug notifier helps prevent boot memory from being
|
||||
* inadvertently removed as it blocks pfn range offlining process in
|
||||
|
||||
Reference in New Issue
Block a user