diff options
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/numa.c | 139 |
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. |
1018 | int 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 | */ |
1043 | 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, |
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 | */ | ||
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 | } | ||
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, | |||
1092 | int hot_add_scn_to_nid(unsigned long scn_addr) | 1109 | int 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; |
1119 | ha_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 */ |