diff options
author | Mike Kravetz <kravetz@us.ibm.com> | 2005-12-05 15:06:42 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:51:57 -0500 |
commit | 237a0989e2902b7d43c4228a36d82f8691fb2118 (patch) | |
tree | 411b5e4978ac15ab283378610fef3941c880711a | |
parent | b5666f70395016a55cc9d57826508b8a346398d0 (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>
-rw-r--r-- | arch/powerpc/mm/mem.c | 11 | ||||
-rw-r--r-- | arch/powerpc/mm/numa.c | 57 | ||||
-rw-r--r-- | include/asm-powerpc/sparsemem.h | 8 |
3 files changed, 65 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 | */ | ||
122 | int __devinit add_memory(u64 start, u64 size) | 117 | int __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 | ||
38 | static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; | 38 | static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; |
39 | static int min_common_depth; | 39 | static int min_common_depth; |
40 | static 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 | ||
270 | static unsigned long __init read_n_cells(int n, unsigned int **buf) | 271 | static 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; |
431 | new_range: | 431 | new_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 | } |
719 | early_param("numa", early_numa); | 719 | early_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 | */ | ||
727 | int 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 */ | ||
745 | ha_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 */ | ||
diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h index ba1b34fdb967..c3f17d442f7d 100644 --- a/include/asm-powerpc/sparsemem.h +++ b/include/asm-powerpc/sparsemem.h | |||
@@ -13,6 +13,14 @@ | |||
13 | 13 | ||
14 | #ifdef CONFIG_MEMORY_HOTPLUG | 14 | #ifdef CONFIG_MEMORY_HOTPLUG |
15 | extern void create_section_mapping(unsigned long start, unsigned long end); | 15 | extern void create_section_mapping(unsigned long start, unsigned long end); |
16 | #ifdef CONFIG_NUMA | ||
17 | extern int hot_add_scn_to_nid(unsigned long scn_addr); | ||
18 | #else | ||
19 | static inline int hot_add_scn_to_nid(unsigned long scn_addr) | ||
20 | { | ||
21 | return 0; | ||
22 | } | ||
23 | #endif /* CONFIG_NUMA */ | ||
16 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 24 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
17 | 25 | ||
18 | #endif /* CONFIG_SPARSEMEM */ | 26 | #endif /* CONFIG_SPARSEMEM */ |