summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun KS <arunks@codeaurora.org>2017-09-15 13:52:00 +0530
committerArun KS <arunks@codeaurora.org>2017-11-22 17:12:55 +0530
commitea4e70e7d64e9598b4ddf6acb28363acbb8e6add (patch)
treecf0a8fa1fecdf038be36624240e30521486096f9
parent2247011a9c93311ec6f73190e2080dffc55526bc (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.c27
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--mm/memory_hotplug.c11
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;