[PATCH] numa placement for dynamically added memory
Mike Kravetz
kravetz at us.ibm.com
Fri Dec 2 12:28:39 EST 2005
This patch places dynamically added memory within the appropriate
numa node. A new routine hot_add_scn_to_nid() replicates most of
the memory scanning code in parse_numa_properties().
I'd appreciate it if Anton or Nathan could take a look. I seem
to break something every time I touch numa.c.
This patch depends on the patch I sent yesterday that hits numa.c
http://ozlabs.org/pipermail/linuxppc64-dev/2005-December/006923.html
Signed-off-by: Mike Kravetz <kravetz at us.ibm.com>
diff -Naupr linux-2.6.15-rc4.dep/arch/powerpc/mm/mem.c linux-2.6.15-rc4.work/arch/powerpc/mm/mem.c
--- linux-2.6.15-rc4.dep/arch/powerpc/mm/mem.c 2005-12-01 06:25:15.000000000 +0000
+++ linux-2.6.15-rc4.work/arch/powerpc/mm/mem.c 2005-12-02 00:11:19.000000000 +0000
@@ -121,11 +121,15 @@ void online_page(struct page *page)
*/
int __devinit add_memory(u64 start, u64 size)
{
- struct pglist_data *pgdata = NODE_DATA(0);
+ struct pglist_data *pgdata;
struct zone *zone;
+ int nid;
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
+ nid = hot_add_scn_to_nid(start);
+ pgdata = NODE_DATA(nid);
+
start += KERNELBASE;
create_section_mapping(start, start + size);
diff -Naupr linux-2.6.15-rc4.dep/arch/powerpc/mm/numa.c linux-2.6.15-rc4.work/arch/powerpc/mm/numa.c
--- linux-2.6.15-rc4.dep/arch/powerpc/mm/numa.c 2005-12-01 19:46:21.000000000 +0000
+++ linux-2.6.15-rc4.work/arch/powerpc/mm/numa.c 2005-12-02 00:11:19.000000000 +0000
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data);
static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
static int min_common_depth;
+static int n_mem_addr_cells, n_mem_size_cells;
/*
* We need somewhere to store start/end/node for each region until we have
@@ -267,7 +268,11 @@ static void __init get_n_mem_cells(int *
of_node_put(memory);
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+static unsigned long read_n_cells(int n, unsigned int **buf)
+#else
static unsigned long __init read_n_cells(int n, unsigned int **buf)
+#endif
{
unsigned long result = 0;
@@ -374,7 +379,6 @@ static int __init parse_numa_properties(
{
struct device_node *cpu = NULL;
struct device_node *memory = NULL;
- int n_addr_cells, n_size_cells;
int max_domain;
unsigned long i;
@@ -413,7 +417,7 @@ static int __init parse_numa_properties(
}
}
- get_n_mem_cells(&n_addr_cells, &n_size_cells);
+ get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
memory = NULL;
while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
unsigned long start;
@@ -430,8 +434,8 @@ static int __init parse_numa_properties(
ranges = memory->n_addrs;
new_range:
/* these are order-sensitive, and modify the buffer pointer */
- start = read_n_cells(n_addr_cells, &memcell_buf);
- size = read_n_cells(n_size_cells, &memcell_buf);
+ start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+ size = read_n_cells(n_mem_size_cells, &memcell_buf);
numa_domain = of_node_numa_domain(memory);
@@ -717,3 +721,50 @@ static int __init early_numa(char *p)
return 0;
}
early_param("numa", early_numa);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Find the node associated with a hot added memory section. Section
+ * corresponds to a SPARSEMEM section, not an LMB. It is assumed that
+ * sections are fully contained within a single LMB.
+ */
+int hot_add_scn_to_nid(unsigned long scn_addr)
+{
+ struct device_node *memory = NULL;
+
+ if (!numa_enabled || (min_common_depth < 0))
+ return 0;
+
+ while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+ unsigned long start, size;
+ int numa_domain, ranges;
+ unsigned int *memcell_buf;
+ unsigned int len;
+
+ memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+ if (!memcell_buf || len <= 0)
+ continue;
+
+ ranges = memory->n_addrs; /* ranges in cell */
+ha_new_range:
+ start = read_n_cells(n_mem_addr_cells, &memcell_buf);
+ size = read_n_cells(n_mem_size_cells, &memcell_buf);
+ numa_domain = of_node_numa_domain(memory);
+
+ /* Domains not present at boot default to 0 */
+ if (!node_online(numa_domain))
+ numa_domain = 0;
+
+ if ((scn_addr >= start) && (scn_addr < (start + size))) {
+ of_node_put(memory);
+ return numa_domain;
+ }
+
+ if (--ranges) /* process all ranges in cell */
+ goto ha_new_range;
+ }
+
+ BUG(); /* section address should be found above */
+ return 0;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
diff -Naupr linux-2.6.15-rc4.dep/include/asm-powerpc/sparsemem.h linux-2.6.15-rc4.work/include/asm-powerpc/sparsemem.h
--- linux-2.6.15-rc4.dep/include/asm-powerpc/sparsemem.h 2005-12-01 06:25:15.000000000 +0000
+++ linux-2.6.15-rc4.work/include/asm-powerpc/sparsemem.h 2005-12-01 19:57:03.000000000 +0000
@@ -13,6 +13,11 @@
#ifdef CONFIG_MEMORY_HOTPLUG
extern void create_section_mapping(unsigned long start, unsigned long end);
+#ifdef CONFIG_NUMA
+extern int hot_add_scn_to_nid(unsigned long scn_addr);
+#else
+#define hot_add_scn_to_nid(scn_addr) (0)
+#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
#endif /* CONFIG_SPARSEMEM */
More information about the Linuxppc64-dev
mailing list