diff options
Diffstat (limited to 'arch/powerpc/mm/numa.c')
-rw-r--r-- | arch/powerpc/mm/numa.c | 139 |
1 files changed, 111 insertions, 28 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index ba7a3055a9fc..2863a912bcd0 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 |
@@ -254,32 +255,20 @@ static int __init find_min_common_depth(void) | |||
254 | return depth; | 255 | return depth; |
255 | } | 256 | } |
256 | 257 | ||
257 | static int __init get_mem_addr_cells(void) | 258 | static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) |
258 | { | 259 | { |
259 | struct device_node *memory = NULL; | 260 | struct device_node *memory = NULL; |
260 | int rc; | ||
261 | 261 | ||
262 | memory = of_find_node_by_type(memory, "memory"); | 262 | memory = of_find_node_by_type(memory, "memory"); |
263 | if (!memory) | 263 | if (!memory) |
264 | return 0; /* it won't matter */ | 264 | panic("numa.c: No memory nodes found!"); |
265 | 265 | ||
266 | rc = prom_n_addr_cells(memory); | 266 | *n_addr_cells = prom_n_addr_cells(memory); |
267 | return rc; | 267 | *n_size_cells = prom_n_size_cells(memory); |
268 | of_node_put(memory); | ||
268 | } | 269 | } |
269 | 270 | ||
270 | static int __init get_mem_size_cells(void) | 271 | static unsigned long __devinit read_n_cells(int n, unsigned int **buf) |
271 | { | ||
272 | struct device_node *memory = NULL; | ||
273 | int rc; | ||
274 | |||
275 | memory = of_find_node_by_type(memory, "memory"); | ||
276 | if (!memory) | ||
277 | return 0; /* it won't matter */ | ||
278 | rc = prom_n_size_cells(memory); | ||
279 | return rc; | ||
280 | } | ||
281 | |||
282 | static unsigned long __init read_n_cells(int n, unsigned int **buf) | ||
283 | { | 272 | { |
284 | unsigned long result = 0; | 273 | unsigned long result = 0; |
285 | 274 | ||
@@ -386,7 +375,6 @@ static int __init parse_numa_properties(void) | |||
386 | { | 375 | { |
387 | struct device_node *cpu = NULL; | 376 | struct device_node *cpu = NULL; |
388 | struct device_node *memory = NULL; | 377 | struct device_node *memory = NULL; |
389 | int addr_cells, size_cells; | ||
390 | int max_domain; | 378 | int max_domain; |
391 | unsigned long i; | 379 | unsigned long i; |
392 | 380 | ||
@@ -425,8 +413,7 @@ static int __init parse_numa_properties(void) | |||
425 | } | 413 | } |
426 | } | 414 | } |
427 | 415 | ||
428 | addr_cells = get_mem_addr_cells(); | 416 | get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); |
429 | size_cells = get_mem_size_cells(); | ||
430 | memory = NULL; | 417 | memory = NULL; |
431 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { | 418 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { |
432 | unsigned long start; | 419 | unsigned long start; |
@@ -436,15 +423,21 @@ static int __init parse_numa_properties(void) | |||
436 | unsigned int *memcell_buf; | 423 | unsigned int *memcell_buf; |
437 | unsigned int len; | 424 | unsigned int len; |
438 | 425 | ||
439 | memcell_buf = (unsigned int *)get_property(memory, "reg", &len); | 426 | memcell_buf = (unsigned int *)get_property(memory, |
427 | "linux,usable-memory", &len); | ||
428 | if (!memcell_buf || len <= 0) | ||
429 | memcell_buf = | ||
430 | (unsigned int *)get_property(memory, "reg", | ||
431 | &len); | ||
440 | if (!memcell_buf || len <= 0) | 432 | if (!memcell_buf || len <= 0) |
441 | continue; | 433 | continue; |
442 | 434 | ||
443 | ranges = memory->n_addrs; | 435 | /* ranges in cell */ |
436 | ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); | ||
444 | new_range: | 437 | new_range: |
445 | /* these are order-sensitive, and modify the buffer pointer */ | 438 | /* these are order-sensitive, and modify the buffer pointer */ |
446 | start = read_n_cells(addr_cells, &memcell_buf); | 439 | start = read_n_cells(n_mem_addr_cells, &memcell_buf); |
447 | size = read_n_cells(size_cells, &memcell_buf); | 440 | size = read_n_cells(n_mem_size_cells, &memcell_buf); |
448 | 441 | ||
449 | numa_domain = of_node_numa_domain(memory); | 442 | numa_domain = of_node_numa_domain(memory); |
450 | 443 | ||
@@ -497,7 +490,41 @@ static void __init setup_nonnuma(void) | |||
497 | node_set_online(0); | 490 | node_set_online(0); |
498 | } | 491 | } |
499 | 492 | ||
500 | static void __init dump_numa_topology(void) | 493 | void __init dump_numa_cpu_topology(void) |
494 | { | ||
495 | unsigned int node; | ||
496 | unsigned int cpu, count; | ||
497 | |||
498 | if (min_common_depth == -1 || !numa_enabled) | ||
499 | return; | ||
500 | |||
501 | for_each_online_node(node) { | ||
502 | printk(KERN_INFO "Node %d CPUs:", node); | ||
503 | |||
504 | count = 0; | ||
505 | /* | ||
506 | * If we used a CPU iterator here we would miss printing | ||
507 | * the holes in the cpumap. | ||
508 | */ | ||
509 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
510 | if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { | ||
511 | if (count == 0) | ||
512 | printk(" %u", cpu); | ||
513 | ++count; | ||
514 | } else { | ||
515 | if (count > 1) | ||
516 | printk("-%u", cpu - 1); | ||
517 | count = 0; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | if (count > 1) | ||
522 | printk("-%u", NR_CPUS - 1); | ||
523 | printk("\n"); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | static void __init dump_numa_memory_topology(void) | ||
501 | { | 528 | { |
502 | unsigned int node; | 529 | unsigned int node; |
503 | unsigned int count; | 530 | unsigned int count; |
@@ -529,7 +556,6 @@ static void __init dump_numa_topology(void) | |||
529 | printk("-0x%lx", i); | 556 | printk("-0x%lx", i); |
530 | printk("\n"); | 557 | printk("\n"); |
531 | } | 558 | } |
532 | return; | ||
533 | } | 559 | } |
534 | 560 | ||
535 | /* | 561 | /* |
@@ -591,7 +617,7 @@ void __init do_init_bootmem(void) | |||
591 | if (parse_numa_properties()) | 617 | if (parse_numa_properties()) |
592 | setup_nonnuma(); | 618 | setup_nonnuma(); |
593 | else | 619 | else |
594 | dump_numa_topology(); | 620 | dump_numa_memory_topology(); |
595 | 621 | ||
596 | register_cpu_notifier(&ppc64_numa_nb); | 622 | register_cpu_notifier(&ppc64_numa_nb); |
597 | 623 | ||
@@ -730,3 +756,60 @@ static int __init early_numa(char *p) | |||
730 | return 0; | 756 | return 0; |
731 | } | 757 | } |
732 | early_param("numa", early_numa); | 758 | early_param("numa", early_numa); |
759 | |||
760 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
761 | /* | ||
762 | * Find the node associated with a hot added memory section. Section | ||
763 | * corresponds to a SPARSEMEM section, not an LMB. It is assumed that | ||
764 | * sections are fully contained within a single LMB. | ||
765 | */ | ||
766 | int hot_add_scn_to_nid(unsigned long scn_addr) | ||
767 | { | ||
768 | struct device_node *memory = NULL; | ||
769 | nodemask_t nodes; | ||
770 | int numa_domain = 0; | ||
771 | |||
772 | if (!numa_enabled || (min_common_depth < 0)) | ||
773 | return numa_domain; | ||
774 | |||
775 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { | ||
776 | unsigned long start, size; | ||
777 | int ranges; | ||
778 | unsigned int *memcell_buf; | ||
779 | unsigned int len; | ||
780 | |||
781 | memcell_buf = (unsigned int *)get_property(memory, "reg", &len); | ||
782 | if (!memcell_buf || len <= 0) | ||
783 | continue; | ||
784 | |||
785 | /* ranges in cell */ | ||
786 | ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); | ||
787 | ha_new_range: | ||
788 | start = read_n_cells(n_mem_addr_cells, &memcell_buf); | ||
789 | size = read_n_cells(n_mem_size_cells, &memcell_buf); | ||
790 | numa_domain = of_node_numa_domain(memory); | ||
791 | |||
792 | /* Domains not present at boot default to 0 */ | ||
793 | if (!node_online(numa_domain)) | ||
794 | numa_domain = any_online_node(NODE_MASK_ALL); | ||
795 | |||
796 | if ((scn_addr >= start) && (scn_addr < (start + size))) { | ||
797 | of_node_put(memory); | ||
798 | goto got_numa_domain; | ||
799 | } | ||
800 | |||
801 | if (--ranges) /* process all ranges in cell */ | ||
802 | goto ha_new_range; | ||
803 | } | ||
804 | BUG(); /* section address should be found above */ | ||
805 | |||
806 | /* Temporary code to ensure that returned node is not empty */ | ||
807 | got_numa_domain: | ||
808 | nodes_setall(nodes); | ||
809 | while (NODE_DATA(numa_domain)->node_spanned_pages == 0) { | ||
810 | node_clear(numa_domain, nodes); | ||
811 | numa_domain = any_online_node(nodes); | ||
812 | } | ||
813 | return numa_domain; | ||
814 | } | ||
815 | #endif /* CONFIG_MEMORY_HOTPLUG */ | ||