[PATCH 4/4] powerpc/pseries: Move DRMEM processing out of numa.c

Michael Bringmann mwb at linux.vnet.ibm.com
Wed Nov 28 07:37:02 AEDT 2018


The implementation of the pseries-specific dynamic memory features
is currently implemented in several non-pseries-specific files.
This patch set moves the implementation of the device-tree parsing
code for the properties ibm,dynamic-memory, ibm,dynamic-memory-v2,
and its representation in the kernel into the platform-specific
directory to the Pseries features.

This patch refactors references to drmem features out of numa.c, so
that they can be moved to drmem.c.  Changes include exporting a few
support functions from numa.c via powerpc/include/asm/topology.h, and
the creation of platform function platform_parse_numa_properties that
any powerpc platform may implement.

Signed-off-by: Michael Bringmann <mwb at linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/topology.h    |   13 +
 arch/powerpc/mm/numa.c                 |  238 +++--------------------
 arch/powerpc/platforms/pseries/drmem.c |  330 ++++++++++++++++++++++++++++----
 3 files changed, 329 insertions(+), 252 deletions(-)

diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index a4a718d..0c1ad7e 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -135,5 +135,18 @@ static inline void shared_proc_topology_init(void) {}
 #endif
 #endif
 
+extern unsigned long numa_enforce_memory_limit(unsigned long start,
+						unsigned long size);
+extern void initialize_distance_lookup_table(int nid,
+					const __be32 *associativity);
+extern int fake_numa_create_new_node(unsigned long end_pfn,
+					unsigned int *nid);
+
+struct assoc_arrays {
+	u32     n_arrays;
+	u32     array_sz;
+	const __be32 *arrays;
+};
+
 #endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_TOPOLOGY_H */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 3a048e9..6c982df 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -39,7 +39,6 @@
 #include <asm/hvcall.h>
 #include <asm/setup.h>
 #include <asm/vdso.h>
-#include <asm/drmem.h>
 
 static int numa_enabled = 1;
 
@@ -87,8 +86,8 @@ static void __init setup_node_to_cpumask_map(void)
 	dbg("Node to cpumask map for %d nodes\n", nr_node_ids);
 }
 
-static int __init fake_numa_create_new_node(unsigned long end_pfn,
-						unsigned int *nid)
+int __init fake_numa_create_new_node(unsigned long end_pfn,
+					unsigned int *nid)
 {
 	unsigned long long mem;
 	char *p = cmdline;
@@ -194,7 +193,7 @@ int __node_distance(int a, int b)
 }
 EXPORT_SYMBOL(__node_distance);
 
-static void initialize_distance_lookup_table(int nid,
+void initialize_distance_lookup_table(int nid,
 		const __be32 *associativity)
 {
 	int i;
@@ -209,6 +208,7 @@ static void initialize_distance_lookup_table(int nid,
 		distance_lookup_table[nid][i] = of_read_number(entry, 1);
 	}
 }
+EXPORT_SYMBOL(initialize_distance_lookup_table);
 
 /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
  * info is found.
@@ -356,98 +356,6 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
 	of_node_put(memory);
 }
 
-static unsigned long read_n_cells(int n, const __be32 **buf)
-{
-	unsigned long result = 0;
-
-	while (n--) {
-		result = (result << 32) | of_read_number(*buf, 1);
-		(*buf)++;
-	}
-	return result;
-}
-
-struct assoc_arrays {
-	u32	n_arrays;
-	u32	array_sz;
-	const __be32 *arrays;
-};
-
-/*
- * Retrieve and validate the list of associativity arrays for drconf
- * memory from the ibm,associativity-lookup-arrays property of the
- * device tree..
- *
- * The layout of the ibm,associativity-lookup-arrays property is a number N
- * indicating the number of associativity arrays, followed by a number M
- * indicating the size of each associativity array, followed by a list
- * of N associativity arrays.
- */
-static int of_get_assoc_arrays(struct assoc_arrays *aa)
-{
-	struct device_node *memory;
-	const __be32 *prop;
-	u32 len;
-
-	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
-	if (!memory)
-		return -1;
-
-	prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len);
-	if (!prop || len < 2 * sizeof(unsigned int)) {
-		of_node_put(memory);
-		return -1;
-	}
-
-	aa->n_arrays = of_read_number(prop++, 1);
-	aa->array_sz = of_read_number(prop++, 1);
-
-	of_node_put(memory);
-
-	/* Now that we know the number of arrays and size of each array,
-	 * revalidate the size of the property read in.
-	 */
-	if (len < (aa->n_arrays * aa->array_sz + 2) * sizeof(unsigned int))
-		return -1;
-
-	aa->arrays = prop;
-	return 0;
-}
-
-/*
- * This is like of_node_to_nid_single() for memory represented in the
- * ibm,dynamic-reconfiguration-memory node.
- */
-static int of_drconf_to_nid_single(struct drmem_lmb *lmb)
-{
-	struct assoc_arrays aa = { .arrays = NULL };
-	int default_nid = 0;
-	int nid = default_nid;
-	int rc, index;
-
-	rc = of_get_assoc_arrays(&aa);
-	if (rc)
-		return default_nid;
-
-	if (min_common_depth > 0 && min_common_depth <= aa.array_sz &&
-	    !(lmb->flags & DRCONF_MEM_AI_INVALID) &&
-	    lmb->aa_index < aa.n_arrays) {
-		index = lmb->aa_index * aa.array_sz + min_common_depth - 1;
-		nid = of_read_number(&aa.arrays[index], 1);
-
-		if (nid == 0xffff || nid >= MAX_NUMNODES)
-			nid = default_nid;
-
-		if (nid > 0) {
-			index = lmb->aa_index * aa.array_sz;
-			initialize_distance_lookup_table(nid,
-							&aa.arrays[index]);
-		}
-	}
-
-	return nid;
-}
-
 /*
  * Figure out to which domain a cpu belongs and stick it there.
  * Return the id of the domain used.
@@ -536,7 +444,7 @@ static int ppc_numa_cpu_dead(unsigned int cpu)
  * or zero. If the returned value of size is 0 the region should be
  * discarded as it lies wholly above the memory limit.
  */
-static unsigned long __init numa_enforce_memory_limit(unsigned long start,
+unsigned long __init numa_enforce_memory_limit(unsigned long start,
 						      unsigned long size)
 {
 	/*
@@ -555,67 +463,20 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
 	return memblock_end_of_DRAM() - start;
 }
 
-/*
- * Reads the counter for a given entry in
- * linux,drconf-usable-memory property
- */
-static inline int __init read_usm_ranges(const __be32 **usm)
+static inline unsigned long read_n_cells(int n, const __be32 **buf)
 {
-	/*
-	 * For each lmb in ibm,dynamic-memory a corresponding
-	 * entry in linux,drconf-usable-memory property contains
-	 * a counter followed by that many (base, size) duple.
-	 * read the counter from linux,drconf-usable-memory
-	 */
-	return read_n_cells(n_mem_size_cells, usm);
-}
-
-/*
- * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
- * node.  This assumes n_mem_{addr,size}_cells have been set.
- */
-static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
-					const __be32 **usm)
-{
-	unsigned int ranges, is_kexec_kdump = 0;
-	unsigned long base, size, sz;
-	int nid;
-
-	/*
-	 * Skip this block if the reserved bit is set in flags (0x80)
-	 * or if the block is not assigned to this partition (0x8)
-	 */
-	if ((lmb->flags & DRCONF_MEM_RESERVED)
-	    || !(lmb->flags & DRCONF_MEM_ASSIGNED))
-		return;
-
-	if (*usm)
-		is_kexec_kdump = 1;
-
-	base = lmb->base_addr;
-	size = drmem_lmb_size();
-	ranges = 1;
+	unsigned long result = 0;
 
-	if (is_kexec_kdump) {
-		ranges = read_usm_ranges(usm);
-		if (!ranges) /* there are no (base, size) duple */
-			return;
+	while (n--) {
+		result = (result << 32) | of_read_number(*buf, 1);
+		(*buf)++;
 	}
+	return result;
+}
 
-	do {
-		if (is_kexec_kdump) {
-			base = read_n_cells(n_mem_addr_cells, usm);
-			size = read_n_cells(n_mem_size_cells, usm);
-		}
-
-		nid = of_drconf_to_nid_single(lmb);
-		fake_numa_create_new_node(((base + size) >> PAGE_SHIFT),
-					  &nid);
-		node_set_online(nid);
-		sz = numa_enforce_memory_limit(base, size);
-		if (sz)
-			memblock_set_node(base, sz, &memblock.memory, nid);
-	} while (--ranges);
+int __weak platform_parse_numa_properties(int min_common_depth)
+{
+	return min_common_depth;
 }
 
 static int __init parse_numa_properties(void)
@@ -704,16 +565,7 @@ static int __init parse_numa_properties(void)
 			goto new_range;
 	}
 
-	/*
-	 * Now do the same thing for each MEMBLOCK listed in the
-	 * ibm,dynamic-memory property in the
-	 * ibm,dynamic-reconfiguration-memory node.
-	 */
-	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
-	if (memory) {
-		walk_drmem_lmbs(memory, numa_setup_drmem_lmb);
-		of_node_put(memory);
-	}
+	min_common_depth = platform_parse_numa_properties(min_common_depth);
 
 	return 0;
 }
@@ -922,37 +774,6 @@ static int __init early_topology_updates(char *p)
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
- * Find the node associated with a hot added memory section for
- * memory represented in the device tree by the property
- * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
- */
-static int hot_add_drconf_scn_to_nid(unsigned long scn_addr)
-{
-	struct drmem_lmb *lmb;
-	unsigned long lmb_size;
-	int nid = -1;
-
-	lmb_size = drmem_lmb_size();
-
-	for_each_drmem_lmb(lmb) {
-		/* skip this block if it is reserved or not assigned to
-		 * this partition */
-		if ((lmb->flags & DRCONF_MEM_RESERVED)
-		    || !(lmb->flags & DRCONF_MEM_ASSIGNED))
-			continue;
-
-		if ((scn_addr < lmb->base_addr)
-		    || (scn_addr >= (lmb->base_addr + lmb_size)))
-			continue;
-
-		nid = of_drconf_to_nid_single(lmb);
-		break;
-	}
-
-	return nid;
-}
-
-/*
  * Find the node associated with a hot added memory section for memory
  * represented in the device tree as a node (i.e. memory at XXXX) for
  * each memblock.
@@ -995,6 +816,11 @@ static int hot_add_node_scn_to_nid(unsigned long scn_addr)
 	return nid;
 }
 
+int __weak platform_hot_add_scn_to_nid(unsigned long scn_addr)
+{
+	return NUMA_NO_NODE;
+}
+
 /*
  * Find the node associated with a hot added memory section.  Section
  * corresponds to a SPARSEMEM section, not an MEMBLOCK.  It is assumed that
@@ -1002,17 +828,14 @@ static int hot_add_node_scn_to_nid(unsigned long scn_addr)
  */
 int hot_add_scn_to_nid(unsigned long scn_addr)
 {
-	struct device_node *memory = NULL;
 	int nid;
 
 	if (!numa_enabled || (min_common_depth < 0))
 		return first_online_node;
 
-	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
-	if (memory) {
-		nid = hot_add_drconf_scn_to_nid(scn_addr);
-		of_node_put(memory);
-	} else {
+	nid = platform_hot_add_scn_to_nid(scn_addr);
+	if (nid != NUMA_NO_NODE)
+	{
 		nid = hot_add_node_scn_to_nid(scn_addr);
 	}
 
@@ -1022,9 +845,13 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
 	return nid;
 }
 
+u64 __weak platform_hot_add_drconf_memory_max(void)
+{
+	return 0;
+}
+
 static u64 hot_add_drconf_memory_max(void)
 {
-	struct device_node *memory = NULL;
 	struct device_node *dn = NULL;
 	const __be64 *lrdr = NULL;
 
@@ -1036,12 +863,7 @@ static u64 hot_add_drconf_memory_max(void)
 			return be64_to_cpup(lrdr);
 	}
 
-	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
-	if (memory) {
-		of_node_put(memory);
-		return drmem_lmb_memory_max();
-	}
-	return 0;
+	return platform_hot_add_drconf_memory_max();
 }
 
 /*
diff --git a/arch/powerpc/platforms/pseries/drmem.c b/arch/powerpc/platforms/pseries/drmem.c
index ccb0d3b..01ac651 100644
--- a/arch/powerpc/platforms/pseries/drmem.c
+++ b/arch/powerpc/platforms/pseries/drmem.c
@@ -16,8 +16,8 @@
 #include <linux/of_fdt.h>
 #include <linux/memblock.h>
 #include <asm/prom.h>
+#include <asm/iommu.h>
 #include <asm/drmem.h>
-#include <asm/platform.h>
 
 static struct drmem_lmb_info __drmem_info;
 struct drmem_lmb_info *drmem_info = &__drmem_info;
@@ -297,6 +297,76 @@ void __init walk_drmem_lmbs_early(unsigned long node,
 	memblock_dump_all();
 }
 
+/*
+ * Interpret the ibm dynamic reconfiguration memory LMBs.
+ * This contains a list of memory blocks along with NUMA affinity
+ * information.
+ */
+static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
+					const __be32 **usm)
+{
+	u64 base, size;
+	int is_kexec_kdump = 0, rngs;
+
+	base = lmb->base_addr;
+	size = drmem_lmb_size();
+	rngs = 1;
+
+	/*
+	 * Skip this block if the reserved bit is set in flags
+	 * or if the block is not assigned to this partition.
+	 */
+	if ((lmb->flags & DRCONF_MEM_RESERVED) ||
+	    !(lmb->flags & DRCONF_MEM_ASSIGNED))
+		return;
+
+	if (*usm)
+		is_kexec_kdump = 1;
+
+	if (is_kexec_kdump) {
+		/*
+		 * For each memblock in ibm,dynamic-memory, a
+		 * corresponding entry in linux,drconf-usable-memory
+		 * property contains a counter 'p' followed by 'p'
+		 * (base, size) duple. Now read the counter from
+		 * linux,drconf-usable-memory property
+		 */
+		rngs = dt_mem_next_cell(dt_root_size_cells, usm);
+		if (!rngs) /* there are no (base, size) duple */
+			return;
+	}
+
+	do {
+		if (is_kexec_kdump) {
+			base = dt_mem_next_cell(dt_root_addr_cells, usm);
+			size = dt_mem_next_cell(dt_root_size_cells, usm);
+		}
+
+		if (iommu_is_off) {
+			if (base >= 0x80000000ul)
+				continue;
+			if ((base + size) > 0x80000000ul)
+				size = 0x80000000ul - base;
+		}
+
+		pr_debug("Adding: %llx -> %llx\n", base, size);
+		if (validate_mem_limit(base, &size))
+			memblock_add(base, size);
+	} while (--rngs);
+}
+
+int __init platform_early_init_dt_scan_memory_ppc(unsigned long node,
+                                                const char *uname,
+                                                int depth, void *data)
+{
+        if (depth == 1 &&
+            strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) {
+                walk_drmem_lmbs_early(node, early_init_drmem_lmb);
+                return 0;
+        }
+
+	return -ENODEV;
+}
 #endif
 
 static int __init init_drmem_lmb_size(struct device_node *dn)
@@ -447,74 +517,246 @@ static int __init drmem_init(void)
 }
 late_initcall(drmem_init);
 
+/*
+ * Retrieve and validate the list of associativity arrays for drconf
+ * memory from the ibm,associativity-lookup-arrays property of the
+ * device tree..
+ *
+ * The layout of the ibm,associativity-lookup-arrays property is a number N
+ * indicating the number of associativity arrays, followed by a number M
+ * indicating the size of each associativity array, followed by a list
+ * of N associativity arrays.
+ */
+static int of_get_assoc_arrays(struct assoc_arrays *aa)
+{
+	struct device_node *memory;
+	const __be32 *prop;
+	u32 len;
+
+	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+	if (!memory)
+		return -1;
+
+	prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len);
+	if (!prop || len < 2 * sizeof(unsigned int)) {
+		of_node_put(memory);
+		return -1;
+	}
+
+	aa->n_arrays = of_read_number(prop++, 1);
+	aa->array_sz = of_read_number(prop++, 1);
+
+	of_node_put(memory);
+
+	/* Now that we know the number of arrays and size of each array,
+	 * revalidate the size of the property read in.
+	 */
+	if (len < (aa->n_arrays * aa->array_sz + 2) * sizeof(unsigned int))
+		return -1;
+
+	aa->arrays = prop;
+	return 0;
+}
+
+static int current_min_common_depth;
+static int n_mem_addr_cells, n_mem_size_cells;
 
 /*
- * Interpret the ibm dynamic reconfiguration memory LMBs.
- * This contains a list of memory blocks along with NUMA affinity
- * information.
+ * This is like numa.c:of_node_to_nid_single() for memory represented
+ * in the ibm,dynamic-reconfiguration-memory node.
  */
-static void __init early_init_drmem_lmb(struct drmem_lmb *lmb,
-					const __be32 **usm)
+static int of_drconf_to_nid_single(struct drmem_lmb *lmb)
 {
-	u64 base, size;
-	int is_kexec_kdump = 0, rngs;
+	struct assoc_arrays aa = { .arrays = NULL };
+	int default_nid = 0;
+	int nid = default_nid;
+	int rc, index;
+
+	rc = of_get_assoc_arrays(&aa);
+	if (rc)
+		return default_nid;
+
+	if (current_min_common_depth > 0 && current_min_common_depth <= aa.array_sz &&
+	    !(lmb->flags & DRCONF_MEM_AI_INVALID) &&
+	    lmb->aa_index < aa.n_arrays) {
+		index = lmb->aa_index * aa.array_sz + current_min_common_depth - 1;
+		nid = of_read_number(&aa.arrays[index], 1);
+
+		if (nid == 0xffff || nid >= MAX_NUMNODES)
+			nid = default_nid;
+
+		if (nid > 0) {
+			index = lmb->aa_index * aa.array_sz;
+			initialize_distance_lookup_table(nid,
+							&aa.arrays[index]);
+		}
+	}
 
-	base = lmb->base_addr;
-	size = drmem_lmb_size();
-	rngs = 1;
+	return nid;
+}
 
+static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
+{
+	struct device_node *memory = NULL;
+
+	memory = of_find_node_by_type(memory, "memory");
+	if (!memory)
+		panic("numa.c: No memory nodes found!");
+
+	*n_addr_cells = of_n_addr_cells(memory);
+	*n_size_cells = of_n_size_cells(memory);
+	of_node_put(memory);
+}
+
+static inline unsigned long read_n_cells(int n, const __be32 **buf)
+{
+        unsigned long result = 0;
+
+        while (n--) {
+                result = (result << 32) | of_read_number(*buf, 1);
+                (*buf)++;
+        }
+        return result;
+}
+
+/*
+ * Reads the counter for a given entry in
+ * linux,drconf-usable-memory property
+ */
+static inline int __init read_usm_ranges(const __be32 **usm)
+{
 	/*
-	 * Skip this block if the reserved bit is set in flags
-	 * or if the block is not assigned to this partition.
+	 * For each lmb in ibm,dynamic-memory a corresponding
+	 * entry in linux,drconf-usable-memory property contains
+	 * a counter followed by that many (base, size) duple.
+	 * read the counter from linux,drconf-usable-memory
 	 */
-	if ((lmb->flags & DRCONF_MEM_RESERVED) ||
-	    !(lmb->flags & DRCONF_MEM_ASSIGNED))
+	return read_n_cells(n_mem_size_cells, usm);
+}
+
+/*
+ * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
+ * node.  This assumes n_mem_{addr,size}_cells have been set.
+ */
+static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
+					const __be32 **usm)
+{
+	unsigned int ranges, is_kexec_kdump = 0;
+	unsigned long base, size, sz;
+	int nid;
+
+	/*
+	 * Skip this block if the reserved bit is set in flags (0x80)
+	 * or if the block is not assigned to this partition (0x8)
+	 */
+	if ((lmb->flags & DRCONF_MEM_RESERVED)
+	    || !(lmb->flags & DRCONF_MEM_ASSIGNED))
 		return;
 
 	if (*usm)
 		is_kexec_kdump = 1;
 
+	base = lmb->base_addr;
+	size = drmem_lmb_size();
+	ranges = 1;
+
 	if (is_kexec_kdump) {
-		/*
-		 * For each memblock in ibm,dynamic-memory, a
-		 * corresponding entry in linux,drconf-usable-memory
-		 * property contains a counter 'p' followed by 'p'
-		 * (base, size) duple. Now read the counter from
-		 * linux,drconf-usable-memory property
-		 */
-		rngs = dt_mem_next_cell(dt_root_size_cells, usm);
-		if (!rngs) /* there are no (base, size) duple */
+		ranges = read_usm_ranges(usm);
+		if (!ranges) /* there are no (base, size) duple */
 			return;
 	}
 
+        get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
+
 	do {
 		if (is_kexec_kdump) {
-			base = dt_mem_next_cell(dt_root_addr_cells, usm);
-			size = dt_mem_next_cell(dt_root_size_cells, usm);
+			base = read_n_cells(n_mem_addr_cells, usm);
+			size = read_n_cells(n_mem_size_cells, usm);
 		}
 
-		if (iommu_is_off) {
-			if (base >= 0x80000000ul)
-				continue;
-			if ((base + size) > 0x80000000ul)
-				size = 0x80000000ul - base;
-		}
+		nid = of_drconf_to_nid_single(lmb);
+		fake_numa_create_new_node(((base + size) >> PAGE_SHIFT),
+					  &nid);
+		node_set_online(nid);
+		sz = numa_enforce_memory_limit(base, size);
+		if (sz)
+			memblock_set_node(base, sz, &memblock.memory, nid);
+	} while (--ranges);
+}
 
-		DBG("Adding: %llx -> %llx\n", base, size);
-		if (validate_mem_limit(base, &size))
-			memblock_add(base, size);
-	} while (--rngs);
+int __init platform_parse_numa_properties(int min_common_depth)
+{
+	struct device_node *memory;
+
+	/*
+	 * Now do the same thing for each MEMBLOCK listed in the
+	 * ibm,dynamic-memory property in the
+	 * ibm,dynamic-reconfiguration-memory node.
+	 */
+	current_min_common_depth = min_common_depth;
+	memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+	if (memory) {
+		walk_drmem_lmbs(memory, numa_setup_drmem_lmb);
+		of_node_put(memory);
+	}
+	return current_min_common_depth;
 }
 
-int __init platform_early_init_dt_scan_memory_ppc(unsigned long node,
-						const char *uname,
-						int depth, void *data)
+u64 platform_hot_add_drconf_memory_max(void)
 {
-	if (depth == 1 &&
-	    strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) {
-		walk_drmem_lmbs_early(node, early_init_drmem_lmb);
-		return 0;
+        struct device_node *memory = NULL;
+
+        memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+        if (memory) {
+                of_node_put(memory);
+                return drmem_lmb_memory_max();
+        }
+        return 0;
+}
+
+
+/*
+ * Find the node associated with a hot added memory section for
+ * memory represented in the device tree by the property
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
+ */
+static int hot_add_drconf_scn_to_nid(unsigned long scn_addr)
+{
+	struct drmem_lmb *lmb;
+	unsigned long lmb_size;
+	int nid = -1;
+
+	lmb_size = drmem_lmb_size();
+
+	for_each_drmem_lmb(lmb) {
+		/* skip this block if it is reserved or not assigned to
+		 * this partition */
+		if ((lmb->flags & DRCONF_MEM_RESERVED)
+		    || !(lmb->flags & DRCONF_MEM_ASSIGNED))
+			continue;
+
+		if ((scn_addr < lmb->base_addr)
+		    || (scn_addr >= (lmb->base_addr + lmb_size)))
+			continue;
+
+		nid = of_drconf_to_nid_single(lmb);
+		break;
 	}
 
-	return -ENODEV;
+	return nid;
+}
+
+int platform_hot_add_scn_to_nid(unsigned long scn_addr)
+{
+        struct device_node *memory = NULL;
+	int nid;
+
+        memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+        if (memory) {
+                nid = hot_add_drconf_scn_to_nid(scn_addr);
+                of_node_put(memory);
+		return nid;
+        } else {
+		return NUMA_NO_NODE;
+	}
 }



More information about the Linuxppc-dev mailing list