aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/numa.c139
1 files changed, 73 insertions, 66 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 0507faa65478..9047145095aa 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1012,57 +1012,32 @@ early_param("numa", early_numa);
1012 1012
1013#ifdef CONFIG_MEMORY_HOTPLUG 1013#ifdef CONFIG_MEMORY_HOTPLUG
1014/* 1014/*
1015 * Validate the node associated with the memory section we are 1015 * Find the node associated with a hot added memory section for
1016 * trying to add. 1016 * memory represented in the device tree by the property
1017 */ 1017 * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory.
1018int valid_hot_add_scn(int *nid, unsigned long start, u32 lmb_size,
1019 unsigned long scn_addr)
1020{
1021 nodemask_t nodes;
1022
1023 if (*nid < 0 || !node_online(*nid))
1024 *nid = any_online_node(NODE_MASK_ALL);
1025
1026 if ((scn_addr >= start) && (scn_addr < (start + lmb_size))) {
1027 nodes_setall(nodes);
1028 while (NODE_DATA(*nid)->node_spanned_pages == 0) {
1029 node_clear(*nid, nodes);
1030 *nid = any_online_node(nodes);
1031 }
1032
1033 return 1;
1034 }
1035
1036 return 0;
1037}
1038
1039/*
1040 * Find the node associated with a hot added memory section represented
1041 * by the ibm,dynamic-reconfiguration-memory node.
1042 */ 1018 */
1043static int hot_add_drconf_scn_to_nid(struct device_node *memory, 1019static int hot_add_drconf_scn_to_nid(struct device_node *memory,
1044 unsigned long scn_addr) 1020 unsigned long scn_addr)
1045{ 1021{
1046 const u32 *dm; 1022 const u32 *dm;
1047 unsigned int n, rc; 1023 unsigned int drconf_cell_cnt, rc;
1048 unsigned long lmb_size; 1024 unsigned long lmb_size;
1049 int default_nid = any_online_node(NODE_MASK_ALL);
1050 int nid;
1051 struct assoc_arrays aa; 1025 struct assoc_arrays aa;
1026 int nid = -1;
1052 1027
1053 n = of_get_drconf_memory(memory, &dm); 1028 drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
1054 if (!n) 1029 if (!drconf_cell_cnt)
1055 return default_nid;; 1030 return -1;
1056 1031
1057 lmb_size = of_get_lmb_size(memory); 1032 lmb_size = of_get_lmb_size(memory);
1058 if (!lmb_size) 1033 if (!lmb_size)
1059 return default_nid; 1034 return -1;
1060 1035
1061 rc = of_get_assoc_arrays(memory, &aa); 1036 rc = of_get_assoc_arrays(memory, &aa);
1062 if (rc) 1037 if (rc)
1063 return default_nid; 1038 return -1;
1064 1039
1065 for (; n != 0; --n) { 1040 for (; drconf_cell_cnt != 0; --drconf_cell_cnt) {
1066 struct of_drconf_cell drmem; 1041 struct of_drconf_cell drmem;
1067 1042
1068 read_drconf_cell(&drmem, &dm); 1043 read_drconf_cell(&drmem, &dm);
@@ -1073,15 +1048,57 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
1073 || !(drmem.flags & DRCONF_MEM_ASSIGNED)) 1048 || !(drmem.flags & DRCONF_MEM_ASSIGNED))
1074 continue; 1049 continue;
1075 1050
1051 if ((scn_addr < drmem.base_addr)
1052 || (scn_addr >= (drmem.base_addr + lmb_size)))
1053 continue;
1054
1076 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}
1061
1062/*
1063 * Find the node associated with a hot added memory section for memory
1064 * represented in the device tree as a node (i.e. memory@XXXX) for
1065 * each lmb.
1066 */
1067int 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 }
1077 1095
1078 if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size, 1096 of_node_put(memory);
1079 scn_addr)) 1097 if (nid >= 0)
1080 return nid; 1098 break;
1081 } 1099 }
1082 1100
1083 BUG(); /* section address should be found above */ 1101 return nid;
1084 return 0;
1085} 1102}
1086 1103
1087/* 1104/*
@@ -1092,7 +1109,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
1092int hot_add_scn_to_nid(unsigned long scn_addr) 1109int hot_add_scn_to_nid(unsigned long scn_addr)
1093{ 1110{
1094 struct device_node *memory = NULL; 1111 struct device_node *memory = NULL;
1095 int nid; 1112 int nid, found = 0;
1096 1113
1097 if (!numa_enabled || (min_common_depth < 0)) 1114 if (!numa_enabled || (min_common_depth < 0))
1098 return any_online_node(NODE_MASK_ALL); 1115 return any_online_node(NODE_MASK_ALL);
@@ -1101,35 +1118,25 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
1101 if (memory) { 1118 if (memory) {
1102 nid = hot_add_drconf_scn_to_nid(memory, scn_addr); 1119 nid = hot_add_drconf_scn_to_nid(memory, scn_addr);
1103 of_node_put(memory); 1120 of_node_put(memory);
1104 return nid; 1121 } else {
1122 nid = hot_add_node_scn_to_nid(scn_addr);
1105 } 1123 }
1106 1124
1107 while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { 1125 if (nid < 0 || !node_online(nid))
1108 unsigned long start, size; 1126 nid = any_online_node(NODE_MASK_ALL);
1109 int ranges;
1110 const unsigned int *memcell_buf;
1111 unsigned int len;
1112
1113 memcell_buf = of_get_property(memory, "reg", &len);
1114 if (!memcell_buf || len <= 0)
1115 continue;
1116 1127
1117 /* ranges in cell */ 1128 if (NODE_DATA(nid)->node_spanned_pages)
1118 ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); 1129 return nid;
1119ha_new_range:
1120 start = read_n_cells(n_mem_addr_cells, &memcell_buf);
1121 size = read_n_cells(n_mem_size_cells, &memcell_buf);
1122 nid = of_node_to_nid_single(memory);
1123 1130
1124 if (valid_hot_add_scn(&nid, start, size, scn_addr)) { 1131 for_each_online_node(nid) {
1125 of_node_put(memory); 1132 if (NODE_DATA(nid)->node_spanned_pages) {
1126 return nid; 1133 found = 1;
1134 break;
1127 } 1135 }
1128
1129 if (--ranges) /* process all ranges in cell */
1130 goto ha_new_range;
1131 } 1136 }
1132 BUG(); /* section address should be found above */ 1137
1133 return 0; 1138 BUG_ON(!found);
1139 return nid;
1134} 1140}
1141
1135#endif /* CONFIG_MEMORY_HOTPLUG */ 1142#endif /* CONFIG_MEMORY_HOTPLUG */