aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/numa.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm/numa.c')
-rw-r--r--arch/powerpc/mm/numa.c106
1 files changed, 97 insertions, 9 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 078d3e00a616..30a42e24bf14 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -31,6 +31,8 @@
31#include <asm/sparsemem.h> 31#include <asm/sparsemem.h>
32#include <asm/prom.h> 32#include <asm/prom.h>
33#include <asm/smp.h> 33#include <asm/smp.h>
34#include <asm/cputhreads.h>
35#include <asm/topology.h>
34#include <asm/firmware.h> 36#include <asm/firmware.h>
35#include <asm/paca.h> 37#include <asm/paca.h>
36#include <asm/hvcall.h> 38#include <asm/hvcall.h>
@@ -152,9 +154,22 @@ static void __init get_node_active_region(unsigned long pfn,
152 } 154 }
153} 155}
154 156
155static void map_cpu_to_node(int cpu, int node) 157static void reset_numa_cpu_lookup_table(void)
158{
159 unsigned int cpu;
160
161 for_each_possible_cpu(cpu)
162 numa_cpu_lookup_table[cpu] = -1;
163}
164
165static void update_numa_cpu_lookup_table(unsigned int cpu, int node)
156{ 166{
157 numa_cpu_lookup_table[cpu] = node; 167 numa_cpu_lookup_table[cpu] = node;
168}
169
170static void map_cpu_to_node(int cpu, int node)
171{
172 update_numa_cpu_lookup_table(cpu, node);
158 173
159 dbg("adding cpu %d to node %d\n", cpu, node); 174 dbg("adding cpu %d to node %d\n", cpu, node);
160 175
@@ -522,11 +537,24 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
522 */ 537 */
523static int numa_setup_cpu(unsigned long lcpu) 538static int numa_setup_cpu(unsigned long lcpu)
524{ 539{
525 int nid = 0; 540 int nid;
526 struct device_node *cpu = of_get_cpu_node(lcpu, NULL); 541 struct device_node *cpu;
542
543 /*
544 * If a valid cpu-to-node mapping is already available, use it
545 * directly instead of querying the firmware, since it represents
546 * the most recent mapping notified to us by the platform (eg: VPHN).
547 */
548 if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) {
549 map_cpu_to_node(lcpu, nid);
550 return nid;
551 }
552
553 cpu = of_get_cpu_node(lcpu, NULL);
527 554
528 if (!cpu) { 555 if (!cpu) {
529 WARN_ON(1); 556 WARN_ON(1);
557 nid = 0;
530 goto out; 558 goto out;
531 } 559 }
532 560
@@ -542,16 +570,38 @@ out:
542 return nid; 570 return nid;
543} 571}
544 572
573static void verify_cpu_node_mapping(int cpu, int node)
574{
575 int base, sibling, i;
576
577 /* Verify that all the threads in the core belong to the same node */
578 base = cpu_first_thread_sibling(cpu);
579
580 for (i = 0; i < threads_per_core; i++) {
581 sibling = base + i;
582
583 if (sibling == cpu || cpu_is_offline(sibling))
584 continue;
585
586 if (cpu_to_node(sibling) != node) {
587 WARN(1, "CPU thread siblings %d and %d don't belong"
588 " to the same node!\n", cpu, sibling);
589 break;
590 }
591 }
592}
593
545static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action, 594static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action,
546 void *hcpu) 595 void *hcpu)
547{ 596{
548 unsigned long lcpu = (unsigned long)hcpu; 597 unsigned long lcpu = (unsigned long)hcpu;
549 int ret = NOTIFY_DONE; 598 int ret = NOTIFY_DONE, nid;
550 599
551 switch (action) { 600 switch (action) {
552 case CPU_UP_PREPARE: 601 case CPU_UP_PREPARE:
553 case CPU_UP_PREPARE_FROZEN: 602 case CPU_UP_PREPARE_FROZEN:
554 numa_setup_cpu(lcpu); 603 nid = numa_setup_cpu(lcpu);
604 verify_cpu_node_mapping((int)lcpu, nid);
555 ret = NOTIFY_OK; 605 ret = NOTIFY_OK;
556 break; 606 break;
557#ifdef CONFIG_HOTPLUG_CPU 607#ifdef CONFIG_HOTPLUG_CPU
@@ -670,7 +720,8 @@ static void __init parse_drconf_memory(struct device_node *memory)
670 node_set_online(nid); 720 node_set_online(nid);
671 sz = numa_enforce_memory_limit(base, size); 721 sz = numa_enforce_memory_limit(base, size);
672 if (sz) 722 if (sz)
673 memblock_set_node(base, sz, nid); 723 memblock_set_node(base, sz,
724 &memblock.memory, nid);
674 } while (--ranges); 725 } while (--ranges);
675 } 726 }
676} 727}
@@ -760,7 +811,7 @@ new_range:
760 continue; 811 continue;
761 } 812 }
762 813
763 memblock_set_node(start, size, nid); 814 memblock_set_node(start, size, &memblock.memory, nid);
764 815
765 if (--ranges) 816 if (--ranges)
766 goto new_range; 817 goto new_range;
@@ -797,7 +848,8 @@ static void __init setup_nonnuma(void)
797 848
798 fake_numa_create_new_node(end_pfn, &nid); 849 fake_numa_create_new_node(end_pfn, &nid);
799 memblock_set_node(PFN_PHYS(start_pfn), 850 memblock_set_node(PFN_PHYS(start_pfn),
800 PFN_PHYS(end_pfn - start_pfn), nid); 851 PFN_PHYS(end_pfn - start_pfn),
852 &memblock.memory, nid);
801 node_set_online(nid); 853 node_set_online(nid);
802 } 854 }
803} 855}
@@ -1067,6 +1119,7 @@ void __init do_init_bootmem(void)
1067 */ 1119 */
1068 setup_node_to_cpumask_map(); 1120 setup_node_to_cpumask_map();
1069 1121
1122 reset_numa_cpu_lookup_table();
1070 register_cpu_notifier(&ppc64_numa_nb); 1123 register_cpu_notifier(&ppc64_numa_nb);
1071 cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, 1124 cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE,
1072 (void *)(unsigned long)boot_cpuid); 1125 (void *)(unsigned long)boot_cpuid);
@@ -1445,6 +1498,33 @@ static int update_cpu_topology(void *data)
1445 return 0; 1498 return 0;
1446} 1499}
1447 1500
1501static int update_lookup_table(void *data)
1502{
1503 struct topology_update_data *update;
1504
1505 if (!data)
1506 return -EINVAL;
1507
1508 /*
1509 * Upon topology update, the numa-cpu lookup table needs to be updated
1510 * for all threads in the core, including offline CPUs, to ensure that
1511 * future hotplug operations respect the cpu-to-node associativity
1512 * properly.
1513 */
1514 for (update = data; update; update = update->next) {
1515 int nid, base, j;
1516
1517 nid = update->new_nid;
1518 base = cpu_first_thread_sibling(update->cpu);
1519
1520 for (j = 0; j < threads_per_core; j++) {
1521 update_numa_cpu_lookup_table(base + j, nid);
1522 }
1523 }
1524
1525 return 0;
1526}
1527
1448/* 1528/*
1449 * Update the node maps and sysfs entries for each cpu whose home node 1529 * Update the node maps and sysfs entries for each cpu whose home node
1450 * has changed. Returns 1 when the topology has changed, and 0 otherwise. 1530 * has changed. Returns 1 when the topology has changed, and 0 otherwise.
@@ -1513,6 +1593,14 @@ int arch_update_cpu_topology(void)
1513 1593
1514 stop_machine(update_cpu_topology, &updates[0], &updated_cpus); 1594 stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
1515 1595
1596 /*
1597 * Update the numa-cpu lookup table with the new mappings, even for
1598 * offline CPUs. It is best to perform this update from the stop-
1599 * machine context.
1600 */
1601 stop_machine(update_lookup_table, &updates[0],
1602 cpumask_of(raw_smp_processor_id()));
1603
1516 for (ud = &updates[0]; ud; ud = ud->next) { 1604 for (ud = &updates[0]; ud; ud = ud->next) {
1517 unregister_cpu_under_node(ud->cpu, ud->old_nid); 1605 unregister_cpu_under_node(ud->cpu, ud->old_nid);
1518 register_cpu_under_node(ud->cpu, ud->new_nid); 1606 register_cpu_under_node(ud->cpu, ud->new_nid);
@@ -1697,7 +1785,7 @@ static const struct file_operations topology_ops = {
1697static int topology_update_init(void) 1785static int topology_update_init(void)
1698{ 1786{
1699 start_topology_update(); 1787 start_topology_update();
1700 proc_create("powerpc/topology_updates", 644, NULL, &topology_ops); 1788 proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops);
1701 1789
1702 return 0; 1790 return 0;
1703} 1791}