diff options
Diffstat (limited to 'arch/powerpc/mm/numa.c')
-rw-r--r-- | arch/powerpc/mm/numa.c | 174 |
1 files changed, 76 insertions, 98 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5ac08b8ab654..9047145095aa 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
@@ -158,35 +158,6 @@ static void unmap_cpu_from_node(unsigned long cpu) | |||
158 | } | 158 | } |
159 | #endif /* CONFIG_HOTPLUG_CPU */ | 159 | #endif /* CONFIG_HOTPLUG_CPU */ |
160 | 160 | ||
161 | static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) | ||
162 | { | ||
163 | unsigned int hw_cpuid = get_hard_smp_processor_id(cpu); | ||
164 | struct device_node *cpu_node = NULL; | ||
165 | const unsigned int *interrupt_server, *reg; | ||
166 | int len; | ||
167 | |||
168 | while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) { | ||
169 | /* Try interrupt server first */ | ||
170 | interrupt_server = of_get_property(cpu_node, | ||
171 | "ibm,ppc-interrupt-server#s", &len); | ||
172 | |||
173 | len = len / sizeof(u32); | ||
174 | |||
175 | if (interrupt_server && (len > 0)) { | ||
176 | while (len--) { | ||
177 | if (interrupt_server[len] == hw_cpuid) | ||
178 | return cpu_node; | ||
179 | } | ||
180 | } else { | ||
181 | reg = of_get_property(cpu_node, "reg", &len); | ||
182 | if (reg && (len > 0) && (reg[0] == hw_cpuid)) | ||
183 | return cpu_node; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return NULL; | ||
188 | } | ||
189 | |||
190 | /* must hold reference to node during call */ | 161 | /* must hold reference to node during call */ |
191 | static const int *of_get_associativity(struct device_node *dev) | 162 | static const int *of_get_associativity(struct device_node *dev) |
192 | { | 163 | { |
@@ -290,7 +261,7 @@ static int __init find_min_common_depth(void) | |||
290 | ref_points = of_get_property(rtas_root, | 261 | ref_points = of_get_property(rtas_root, |
291 | "ibm,associativity-reference-points", &len); | 262 | "ibm,associativity-reference-points", &len); |
292 | 263 | ||
293 | if ((len >= 1) && ref_points) { | 264 | if ((len >= 2 * sizeof(unsigned int)) && ref_points) { |
294 | depth = ref_points[1]; | 265 | depth = ref_points[1]; |
295 | } else { | 266 | } else { |
296 | dbg("NUMA: ibm,associativity-reference-points not found.\n"); | 267 | dbg("NUMA: ibm,associativity-reference-points not found.\n"); |
@@ -470,7 +441,7 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem, | |||
470 | static int __cpuinit numa_setup_cpu(unsigned long lcpu) | 441 | static int __cpuinit numa_setup_cpu(unsigned long lcpu) |
471 | { | 442 | { |
472 | int nid = 0; | 443 | int nid = 0; |
473 | struct device_node *cpu = find_cpu_node(lcpu); | 444 | struct device_node *cpu = of_get_cpu_node(lcpu, NULL); |
474 | 445 | ||
475 | if (!cpu) { | 446 | if (!cpu) { |
476 | WARN_ON(1); | 447 | WARN_ON(1); |
@@ -652,7 +623,7 @@ static int __init parse_numa_properties(void) | |||
652 | for_each_present_cpu(i) { | 623 | for_each_present_cpu(i) { |
653 | int nid; | 624 | int nid; |
654 | 625 | ||
655 | cpu = find_cpu_node(i); | 626 | cpu = of_get_cpu_node(i, NULL); |
656 | BUG_ON(!cpu); | 627 | BUG_ON(!cpu); |
657 | nid = of_node_to_nid_single(cpu); | 628 | nid = of_node_to_nid_single(cpu); |
658 | of_node_put(cpu); | 629 | of_node_put(cpu); |
@@ -1041,57 +1012,32 @@ early_param("numa", early_numa); | |||
1041 | 1012 | ||
1042 | #ifdef CONFIG_MEMORY_HOTPLUG | 1013 | #ifdef CONFIG_MEMORY_HOTPLUG |
1043 | /* | 1014 | /* |
1044 | * Validate the node associated with the memory section we are | 1015 | * Find the node associated with a hot added memory section for |
1045 | * trying to add. | 1016 | * memory represented in the device tree by the property |
1046 | */ | 1017 | * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory. |
1047 | int valid_hot_add_scn(int *nid, unsigned long start, u32 lmb_size, | ||
1048 | unsigned long scn_addr) | ||
1049 | { | ||
1050 | nodemask_t nodes; | ||
1051 | |||
1052 | if (*nid < 0 || !node_online(*nid)) | ||
1053 | *nid = any_online_node(NODE_MASK_ALL); | ||
1054 | |||
1055 | if ((scn_addr >= start) && (scn_addr < (start + lmb_size))) { | ||
1056 | nodes_setall(nodes); | ||
1057 | while (NODE_DATA(*nid)->node_spanned_pages == 0) { | ||
1058 | node_clear(*nid, nodes); | ||
1059 | *nid = any_online_node(nodes); | ||
1060 | } | ||
1061 | |||
1062 | return 1; | ||
1063 | } | ||
1064 | |||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | /* | ||
1069 | * Find the node associated with a hot added memory section represented | ||
1070 | * by the ibm,dynamic-reconfiguration-memory node. | ||
1071 | */ | 1018 | */ |
1072 | static int hot_add_drconf_scn_to_nid(struct device_node *memory, | 1019 | static int hot_add_drconf_scn_to_nid(struct device_node *memory, |
1073 | unsigned long scn_addr) | 1020 | unsigned long scn_addr) |
1074 | { | 1021 | { |
1075 | const u32 *dm; | 1022 | const u32 *dm; |
1076 | unsigned int n, rc; | 1023 | unsigned int drconf_cell_cnt, rc; |
1077 | unsigned long lmb_size; | 1024 | unsigned long lmb_size; |
1078 | int default_nid = any_online_node(NODE_MASK_ALL); | ||
1079 | int nid; | ||
1080 | struct assoc_arrays aa; | 1025 | struct assoc_arrays aa; |
1026 | int nid = -1; | ||
1081 | 1027 | ||
1082 | n = of_get_drconf_memory(memory, &dm); | 1028 | drconf_cell_cnt = of_get_drconf_memory(memory, &dm); |
1083 | if (!n) | 1029 | if (!drconf_cell_cnt) |
1084 | return default_nid;; | 1030 | return -1; |
1085 | 1031 | ||
1086 | lmb_size = of_get_lmb_size(memory); | 1032 | lmb_size = of_get_lmb_size(memory); |
1087 | if (!lmb_size) | 1033 | if (!lmb_size) |
1088 | return default_nid; | 1034 | return -1; |
1089 | 1035 | ||
1090 | rc = of_get_assoc_arrays(memory, &aa); | 1036 | rc = of_get_assoc_arrays(memory, &aa); |
1091 | if (rc) | 1037 | if (rc) |
1092 | return default_nid; | 1038 | return -1; |
1093 | 1039 | ||
1094 | for (; n != 0; --n) { | 1040 | for (; drconf_cell_cnt != 0; --drconf_cell_cnt) { |
1095 | struct of_drconf_cell drmem; | 1041 | struct of_drconf_cell drmem; |
1096 | 1042 | ||
1097 | read_drconf_cell(&drmem, &dm); | 1043 | read_drconf_cell(&drmem, &dm); |
@@ -1102,15 +1048,57 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, | |||
1102 | || !(drmem.flags & DRCONF_MEM_ASSIGNED)) | 1048 | || !(drmem.flags & DRCONF_MEM_ASSIGNED)) |
1103 | continue; | 1049 | continue; |
1104 | 1050 | ||
1051 | if ((scn_addr < drmem.base_addr) | ||
1052 | || (scn_addr >= (drmem.base_addr + lmb_size))) | ||
1053 | continue; | ||
1054 | |||
1105 | nid = of_drconf_to_nid_single(&drmem, &aa); | 1055 | nid = of_drconf_to_nid_single(&drmem, &aa); |
1056 | break; | ||
1057 | } | ||
1058 | |||
1059 | return nid; | ||
1060 | } | ||
1106 | 1061 | ||
1107 | if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size, | 1062 | /* |
1108 | scn_addr)) | 1063 | * Find the node associated with a hot added memory section for memory |
1109 | return nid; | 1064 | * represented in the device tree as a node (i.e. memory@XXXX) for |
1065 | * each lmb. | ||
1066 | */ | ||
1067 | int hot_add_node_scn_to_nid(unsigned long scn_addr) | ||
1068 | { | ||
1069 | struct device_node *memory = NULL; | ||
1070 | int nid = -1; | ||
1071 | |||
1072 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { | ||
1073 | unsigned long start, size; | ||
1074 | int ranges; | ||
1075 | const unsigned int *memcell_buf; | ||
1076 | unsigned int len; | ||
1077 | |||
1078 | memcell_buf = of_get_property(memory, "reg", &len); | ||
1079 | if (!memcell_buf || len <= 0) | ||
1080 | continue; | ||
1081 | |||
1082 | /* ranges in cell */ | ||
1083 | ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); | ||
1084 | |||
1085 | while (ranges--) { | ||
1086 | start = read_n_cells(n_mem_addr_cells, &memcell_buf); | ||
1087 | size = read_n_cells(n_mem_size_cells, &memcell_buf); | ||
1088 | |||
1089 | if ((scn_addr < start) || (scn_addr >= (start + size))) | ||
1090 | continue; | ||
1091 | |||
1092 | nid = of_node_to_nid_single(memory); | ||
1093 | break; | ||
1094 | } | ||
1095 | |||
1096 | of_node_put(memory); | ||
1097 | if (nid >= 0) | ||
1098 | break; | ||
1110 | } | 1099 | } |
1111 | 1100 | ||
1112 | BUG(); /* section address should be found above */ | 1101 | return nid; |
1113 | return 0; | ||
1114 | } | 1102 | } |
1115 | 1103 | ||
1116 | /* | 1104 | /* |
@@ -1121,7 +1109,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, | |||
1121 | int hot_add_scn_to_nid(unsigned long scn_addr) | 1109 | int hot_add_scn_to_nid(unsigned long scn_addr) |
1122 | { | 1110 | { |
1123 | struct device_node *memory = NULL; | 1111 | struct device_node *memory = NULL; |
1124 | int nid; | 1112 | int nid, found = 0; |
1125 | 1113 | ||
1126 | if (!numa_enabled || (min_common_depth < 0)) | 1114 | if (!numa_enabled || (min_common_depth < 0)) |
1127 | return any_online_node(NODE_MASK_ALL); | 1115 | return any_online_node(NODE_MASK_ALL); |
@@ -1130,35 +1118,25 @@ int hot_add_scn_to_nid(unsigned long scn_addr) | |||
1130 | if (memory) { | 1118 | if (memory) { |
1131 | nid = hot_add_drconf_scn_to_nid(memory, scn_addr); | 1119 | nid = hot_add_drconf_scn_to_nid(memory, scn_addr); |
1132 | of_node_put(memory); | 1120 | of_node_put(memory); |
1133 | return nid; | 1121 | } else { |
1122 | nid = hot_add_node_scn_to_nid(scn_addr); | ||
1134 | } | 1123 | } |
1135 | 1124 | ||
1136 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { | 1125 | if (nid < 0 || !node_online(nid)) |
1137 | unsigned long start, size; | 1126 | nid = any_online_node(NODE_MASK_ALL); |
1138 | int ranges; | ||
1139 | const unsigned int *memcell_buf; | ||
1140 | unsigned int len; | ||
1141 | |||
1142 | memcell_buf = of_get_property(memory, "reg", &len); | ||
1143 | if (!memcell_buf || len <= 0) | ||
1144 | continue; | ||
1145 | 1127 | ||
1146 | /* ranges in cell */ | 1128 | if (NODE_DATA(nid)->node_spanned_pages) |
1147 | ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); | 1129 | return nid; |
1148 | ha_new_range: | ||
1149 | start = read_n_cells(n_mem_addr_cells, &memcell_buf); | ||
1150 | size = read_n_cells(n_mem_size_cells, &memcell_buf); | ||
1151 | nid = of_node_to_nid_single(memory); | ||
1152 | 1130 | ||
1153 | if (valid_hot_add_scn(&nid, start, size, scn_addr)) { | 1131 | for_each_online_node(nid) { |
1154 | of_node_put(memory); | 1132 | if (NODE_DATA(nid)->node_spanned_pages) { |
1155 | return nid; | 1133 | found = 1; |
1134 | break; | ||
1156 | } | 1135 | } |
1157 | |||
1158 | if (--ranges) /* process all ranges in cell */ | ||
1159 | goto ha_new_range; | ||
1160 | } | 1136 | } |
1161 | BUG(); /* section address should be found above */ | 1137 | |
1162 | return 0; | 1138 | BUG_ON(!found); |
1139 | return nid; | ||
1163 | } | 1140 | } |
1141 | |||
1164 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 1142 | #endif /* CONFIG_MEMORY_HOTPLUG */ |