aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/mm/numa.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/mm/numa.c')
-rw-r--r--arch/ppc64/mm/numa.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index 5c603ba982310..ea862ec643d3a 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -285,6 +285,35 @@ static int cpu_numa_callback(struct notifier_block *nfb,
return ret;
}
+/*
+ * Check and possibly modify a memory region to enforce the memory limit.
+ *
+ * Returns the size the region should have to enforce the memory limit.
+ * This will either be the original value of size, a truncated value,
+ * or zero. If the returned value of size is 0 the region should be
+ * discarded as it lies wholy above the memory limit.
+ */
+static unsigned long __init numa_enforce_memory_limit(unsigned long start, unsigned long size)
+{
+ /*
+ * We use lmb_end_of_DRAM() in here instead of memory_limit because
+ * we've already adjusted it for the limit and it takes care of
+ * having memory holes below the limit.
+ */
+ extern unsigned long memory_limit;
+
+ if (! memory_limit)
+ return size;
+
+ if (start + size <= lmb_end_of_DRAM())
+ return size;
+
+ if (start >= lmb_end_of_DRAM())
+ return 0;
+
+ return lmb_end_of_DRAM() - start;
+}
+
static int __init parse_numa_properties(void)
{
struct device_node *cpu = NULL;
@@ -373,6 +402,13 @@ new_range:
if (max_domain < numa_domain)
max_domain = numa_domain;
+ if (! (size = numa_enforce_memory_limit(start, size))) {
+ if (--ranges)
+ goto new_range;
+ else
+ continue;
+ }
+
/*
* Initialize new node struct, or add to an existing one.
*/
@@ -405,8 +441,7 @@ new_range:
numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
numa_domain;
- ranges--;
- if (ranges)
+ if (--ranges)
goto new_range;
}
@@ -614,8 +649,11 @@ new_range:
if (numa_domain != nid)
continue;
- dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
- free_bootmem_node(NODE_DATA(nid), mem_start, mem_size);
+ mem_size = numa_enforce_memory_limit(mem_start, mem_size);
+ if (mem_size) {
+ dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
+ free_bootmem_node(NODE_DATA(nid), mem_start, mem_size);
+ }
if (--ranges) /* process all ranges in cell */
goto new_range;