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:
Sudarshan Rajagopalan
2021-01-06 18:53:58 -08:00
committed by Suren Baghdasaryan
parent c7ba09ce6a
commit 1b4aca7d82
2 changed files with 72 additions and 0 deletions

View File

@@ -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) ==

View File

@@ -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