aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorMike Kravetz <kravetz@us.ibm.com>2005-12-05 15:06:42 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:51:57 -0500
commit237a0989e2902b7d43c4228a36d82f8691fb2118 (patch)
tree411b5e4978ac15ab283378610fef3941c880711a /arch/powerpc
parentb5666f70395016a55cc9d57826508b8a346398d0 (diff)
[PATCH] powerpc: numa placement for dynamically added memory
This 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(). Signed-off-by: Mike Kravetz <kravetz@us.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/mm/mem.c11
-rw-r--r--arch/powerpc/mm/numa.c57
2 files changed, 57 insertions, 11 deletions
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index ed6ed2e30dac..5e5bff5616a8 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -114,18 +114,17 @@ void online_page(struct page *page)
114 num_physpages++; 114 num_physpages++;
115} 115}
116 116
117/*
118 * This works only for the non-NUMA case. Later, we'll need a lookup
119 * to convert from real physical addresses to nid, that doesn't use
120 * pfn_to_nid().
121 */
122int __devinit add_memory(u64 start, u64 size) 117int __devinit add_memory(u64 start, u64 size)
123{ 118{
124 struct pglist_data *pgdata = NODE_DATA(0); 119 struct pglist_data *pgdata;
125 struct zone *zone; 120 struct zone *zone;
121 int nid;
126 unsigned long start_pfn = start >> PAGE_SHIFT; 122 unsigned long start_pfn = start >> PAGE_SHIFT;
127 unsigned long nr_pages = size >> PAGE_SHIFT; 123 unsigned long nr_pages = size >> PAGE_SHIFT;
128 124
125 nid = hot_add_scn_to_nid(start);
126 pgdata = NODE_DATA(nid);
127
129 start += KERNELBASE; 128 start += KERNELBASE;
130 create_section_mapping(start, start + size); 129 create_section_mapping(start, start + size);
131 130
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e812d3d0d6ae..40c99deb691b 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data);
37 37
38static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; 38static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
39static int min_common_depth; 39static int min_common_depth;
40static int n_mem_addr_cells, n_mem_size_cells;
40 41
41/* 42/*
42 * We need somewhere to store start/end/node for each region until we have 43 * We need somewhere to store start/end/node for each region until we have
@@ -267,7 +268,7 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
267 of_node_put(memory); 268 of_node_put(memory);
268} 269}
269 270
270static unsigned long __init read_n_cells(int n, unsigned int **buf) 271static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
271{ 272{
272 unsigned long result = 0; 273 unsigned long result = 0;
273 274
@@ -374,7 +375,6 @@ static int __init parse_numa_properties(void)
374{ 375{
375 struct device_node *cpu = NULL; 376 struct device_node *cpu = NULL;
376 struct device_node *memory = NULL; 377 struct device_node *memory = NULL;
377 int n_addr_cells, n_size_cells;
378 int max_domain; 378 int max_domain;
379 unsigned long i; 379 unsigned long i;
380 380
@@ -413,7 +413,7 @@ static int __init parse_numa_properties(void)
413 } 413 }
414 } 414 }
415 415
416 get_n_mem_cells(&n_addr_cells, &n_size_cells); 416 get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
417 memory = NULL; 417 memory = NULL;
418 while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { 418 while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
419 unsigned long start; 419 unsigned long start;
@@ -430,8 +430,8 @@ static int __init parse_numa_properties(void)
430 ranges = memory->n_addrs; 430 ranges = memory->n_addrs;
431new_range: 431new_range:
432 /* these are order-sensitive, and modify the buffer pointer */ 432 /* these are order-sensitive, and modify the buffer pointer */
433 start = read_n_cells(n_addr_cells, &memcell_buf); 433 start = read_n_cells(n_mem_addr_cells, &memcell_buf);
434 size = read_n_cells(n_size_cells, &memcell_buf); 434 size = read_n_cells(n_mem_size_cells, &memcell_buf);
435 435
436 numa_domain = of_node_numa_domain(memory); 436 numa_domain = of_node_numa_domain(memory);
437 437
@@ -717,3 +717,50 @@ static int __init early_numa(char *p)
717 return 0; 717 return 0;
718} 718}
719early_param("numa", early_numa); 719early_param("numa", early_numa);
720
721#ifdef CONFIG_MEMORY_HOTPLUG
722/*
723 * Find the node associated with a hot added memory section. Section
724 * corresponds to a SPARSEMEM section, not an LMB. It is assumed that
725 * sections are fully contained within a single LMB.
726 */
727int hot_add_scn_to_nid(unsigned long scn_addr)
728{
729 struct device_node *memory = NULL;
730
731 if (!numa_enabled || (min_common_depth < 0))
732 return 0;
733
734 while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
735 unsigned long start, size;
736 int numa_domain, ranges;
737 unsigned int *memcell_buf;
738 unsigned int len;
739
740 memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
741 if (!memcell_buf || len <= 0)
742 continue;
743
744 ranges = memory->n_addrs; /* ranges in cell */
745ha_new_range:
746 start = read_n_cells(n_mem_addr_cells, &memcell_buf);
747 size = read_n_cells(n_mem_size_cells, &memcell_buf);
748 numa_domain = of_node_numa_domain(memory);
749
750 /* Domains not present at boot default to 0 */
751 if (!node_online(numa_domain))
752 numa_domain = any_online_node(NODE_MASK_ALL);
753
754 if ((scn_addr >= start) && (scn_addr < (start + size))) {
755 of_node_put(memory);
756 return numa_domain;
757 }
758
759 if (--ranges) /* process all ranges in cell */
760 goto ha_new_range;
761 }
762
763 BUG(); /* section address should be found above */
764 return 0;
765}
766#endif /* CONFIG_MEMORY_HOTPLUG */