|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/poison.h>
|
|
|
#include <linux/initrd.h>
|
|
|
#include <linux/export.h>
|
|
|
+#include <linux/cma.h>
|
|
|
#include <linux/gfp.h>
|
|
|
#include <linux/memblock.h>
|
|
|
#include <asm/processor.h>
|
|
@@ -167,6 +168,58 @@ unsigned long memory_block_size_bytes(void)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
|
|
+
|
|
|
+#ifdef CONFIG_CMA
|
|
|
+
|
|
|
+/* Prevent memory blocks which contain cma regions from going offline */
|
|
|
+
|
|
|
+struct s390_cma_mem_data {
|
|
|
+ unsigned long start;
|
|
|
+ unsigned long end;
|
|
|
+};
|
|
|
+
|
|
|
+static int s390_cma_check_range(struct cma *cma, void *data)
|
|
|
+{
|
|
|
+ struct s390_cma_mem_data *mem_data;
|
|
|
+ unsigned long start, end;
|
|
|
+
|
|
|
+ mem_data = data;
|
|
|
+ start = cma_get_base(cma);
|
|
|
+ end = start + cma_get_size(cma);
|
|
|
+ if (end < mem_data->start)
|
|
|
+ return 0;
|
|
|
+ if (start >= mem_data->end)
|
|
|
+ return 0;
|
|
|
+ return -EBUSY;
|
|
|
+}
|
|
|
+
|
|
|
+static int s390_cma_mem_notifier(struct notifier_block *nb,
|
|
|
+ unsigned long action, void *data)
|
|
|
+{
|
|
|
+ struct s390_cma_mem_data mem_data;
|
|
|
+ struct memory_notify *arg;
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ arg = data;
|
|
|
+ mem_data.start = arg->start_pfn << PAGE_SHIFT;
|
|
|
+ mem_data.end = mem_data.start + (arg->nr_pages << PAGE_SHIFT);
|
|
|
+ if (action == MEM_GOING_OFFLINE)
|
|
|
+ rc = cma_for_each_area(s390_cma_check_range, &mem_data);
|
|
|
+ return notifier_from_errno(rc);
|
|
|
+}
|
|
|
+
|
|
|
+static struct notifier_block s390_cma_mem_nb = {
|
|
|
+ .notifier_call = s390_cma_mem_notifier,
|
|
|
+};
|
|
|
+
|
|
|
+static int __init s390_cma_mem_init(void)
|
|
|
+{
|
|
|
+ return register_memory_notifier(&s390_cma_mem_nb);
|
|
|
+}
|
|
|
+device_initcall(s390_cma_mem_init);
|
|
|
+
|
|
|
+#endif /* CONFIG_CMA */
|
|
|
+
|
|
|
int arch_add_memory(int nid, u64 start, u64 size, bool want_memblock)
|
|
|
{
|
|
|
unsigned long start_pfn = PFN_DOWN(start);
|