diff options
| author | Arun KS <arunks@codeaurora.org> | 2017-09-15 13:52:00 +0530 |
|---|---|---|
| committer | Arun KS <arunks@codeaurora.org> | 2017-11-22 17:12:55 +0530 |
| commit | ea4e70e7d64e9598b4ddf6acb28363acbb8e6add (patch) | |
| tree | cf0a8fa1fecdf038be36624240e30521486096f9 | |
| parent | 2247011a9c93311ec6f73190e2080dffc55526bc (diff) | |
arm64: Honor limits set by bootloader
Introduce a varible to save bootloader enforced memory limits and
restricts adding beyond this boundary during a memory hotplug.
Change-Id: I28c100644b7287ec4625c4c018b5fffc865e2e72
Signed-off-by: Arun KS <arunks@codeaurora.org>
| -rw-r--r-- | arch/arm64/mm/init.c | 27 | ||||
| -rw-r--r-- | include/linux/memory_hotplug.h | 2 | ||||
| -rw-r--r-- | mm/memory_hotplug.c | 11 |
3 files changed, 35 insertions, 5 deletions
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 75d363be3f36..7fd74d55c68e 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -152,6 +152,7 @@ static void __init arm64_memory_present(void) #endif static phys_addr_t memory_limit = (phys_addr_t)ULLONG_MAX; +static phys_addr_t bootloader_memory_limit; /* * Limit the memory size that was specified via FDT. @@ -205,6 +206,11 @@ void __init arm64_memblock_init(void) * via the linear mapping. */ if (memory_limit != (phys_addr_t)ULLONG_MAX) { + /* + * Save bootloader imposed memory limit before we overwirte + * memblock. + */ + bootloader_memory_limit = memblock_end_of_DRAM(); memblock_enforce_memory_limit(memory_limit); memblock_add(__pa(_text), (u64)(_end - _text)); } @@ -607,4 +613,25 @@ int arch_remove_memory(u64 start, u64 size) } #endif /* CONFIG_MEMORY_HOTREMOVE */ +static int arm64_online_page(struct page *page) +{ + unsigned long target_pfn = page_to_pfn(page); + unsigned long limit = __phys_to_pfn(bootloader_memory_limit); + + if (target_pfn >= limit) + return -EINVAL; + + __online_page_set_limits(page); + __online_page_increment_counters(page); + __online_page_free(page); + + return 0; +} + +static int __init arm64_memory_hotplug_init(void) +{ + set_online_page_callback(&arm64_online_page); + return 0; +} +subsys_initcall(arm64_memory_hotplug_init); #endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 538488bd1d3d..ba23995e51b4 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -89,7 +89,7 @@ extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn, unsigned long *valid_start, unsigned long *valid_end); extern void __offline_isolated_pages(unsigned long, unsigned long); -typedef void (*online_page_callback_t)(struct page *page); +typedef int (*online_page_callback_t)(struct page *page); extern int set_online_page_callback(online_page_callback_t callback); extern int restore_online_page_callback(online_page_callback_t callback); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 2ad8a8888032..81957b076d66 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -45,7 +45,7 @@ * and restore_online_page_callback() for generic callback restore. */ -static void generic_online_page(struct page *page); +static int generic_online_page(struct page *page); static online_page_callback_t online_page_callback = generic_online_page; static DEFINE_MUTEX(online_page_callback_lock); @@ -857,11 +857,12 @@ void __online_page_free(struct page *page) } EXPORT_SYMBOL_GPL(__online_page_free); -static void generic_online_page(struct page *page) +static int generic_online_page(struct page *page) { __online_page_set_limits(page); __online_page_increment_counters(page); __online_page_free(page); + return 0; } static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, @@ -870,11 +871,13 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, unsigned long i; unsigned long onlined_pages = *(unsigned long *)arg; struct page *page; + int ret; if (PageReserved(pfn_to_page(start_pfn))) for (i = 0; i < nr_pages; i++) { page = pfn_to_page(start_pfn + i); - (*online_page_callback)(page); - onlined_pages++; + ret = (*online_page_callback)(page); + if (!ret) + onlined_pages++; } *(unsigned long *)arg = onlined_pages; return 0; |
