diff options
-rw-r--r-- | arch/powerpc/mm/numa.c | 101 |
1 files changed, 83 insertions, 18 deletions
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 39328da32edf..cf4bffba6f7c 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
@@ -901,6 +901,79 @@ early_param("numa", early_numa); | |||
901 | 901 | ||
902 | #ifdef CONFIG_MEMORY_HOTPLUG | 902 | #ifdef CONFIG_MEMORY_HOTPLUG |
903 | /* | 903 | /* |
904 | * Validate the node associated with the memory section we are | ||
905 | * trying to add. | ||
906 | */ | ||
907 | int valid_hot_add_scn(int *nid, unsigned long start, u32 lmb_size, | ||
908 | unsigned long scn_addr) | ||
909 | { | ||
910 | nodemask_t nodes; | ||
911 | |||
912 | if (*nid < 0 || !node_online(*nid)) | ||
913 | *nid = any_online_node(NODE_MASK_ALL); | ||
914 | |||
915 | if ((scn_addr >= start) && (scn_addr < (start + lmb_size))) { | ||
916 | nodes_setall(nodes); | ||
917 | while (NODE_DATA(*nid)->node_spanned_pages == 0) { | ||
918 | node_clear(*nid, nodes); | ||
919 | *nid = any_online_node(nodes); | ||
920 | } | ||
921 | |||
922 | return 1; | ||
923 | } | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | /* | ||
929 | * Find the node associated with a hot added memory section represented | ||
930 | * by the ibm,dynamic-reconfiguration-memory node. | ||
931 | */ | ||
932 | static int hot_add_drconf_scn_to_nid(struct device_node *memory, | ||
933 | unsigned long scn_addr) | ||
934 | { | ||
935 | const u32 *dm; | ||
936 | unsigned int n, rc; | ||
937 | unsigned long lmb_size; | ||
938 | int default_nid = any_online_node(NODE_MASK_ALL); | ||
939 | int nid; | ||
940 | struct assoc_arrays aa; | ||
941 | |||
942 | n = of_get_drconf_memory(memory, &dm); | ||
943 | if (!n) | ||
944 | return default_nid;; | ||
945 | |||
946 | lmb_size = of_get_lmb_size(memory); | ||
947 | if (!lmb_size) | ||
948 | return default_nid; | ||
949 | |||
950 | rc = of_get_assoc_arrays(memory, &aa); | ||
951 | if (rc) | ||
952 | return default_nid; | ||
953 | |||
954 | for (; n != 0; --n) { | ||
955 | struct of_drconf_cell drmem; | ||
956 | |||
957 | read_drconf_cell(&drmem, &dm); | ||
958 | |||
959 | /* skip this block if it is reserved or not assigned to | ||
960 | * this partition */ | ||
961 | if ((drmem.flags & DRCONF_MEM_RESERVED) | ||
962 | || !(drmem.flags & DRCONF_MEM_ASSIGNED)) | ||
963 | continue; | ||
964 | |||
965 | nid = of_drconf_to_nid_single(&drmem, &aa); | ||
966 | |||
967 | if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size, | ||
968 | scn_addr)) | ||
969 | return nid; | ||
970 | } | ||
971 | |||
972 | BUG(); /* section address should be found above */ | ||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | /* | ||
904 | * Find the node associated with a hot added memory section. Section | 977 | * Find the node associated with a hot added memory section. Section |
905 | * corresponds to a SPARSEMEM section, not an LMB. It is assumed that | 978 | * corresponds to a SPARSEMEM section, not an LMB. It is assumed that |
906 | * sections are fully contained within a single LMB. | 979 | * sections are fully contained within a single LMB. |
@@ -908,12 +981,17 @@ early_param("numa", early_numa); | |||
908 | int hot_add_scn_to_nid(unsigned long scn_addr) | 981 | int hot_add_scn_to_nid(unsigned long scn_addr) |
909 | { | 982 | { |
910 | struct device_node *memory = NULL; | 983 | struct device_node *memory = NULL; |
911 | nodemask_t nodes; | ||
912 | int default_nid = any_online_node(NODE_MASK_ALL); | ||
913 | int nid; | 984 | int nid; |
914 | 985 | ||
915 | if (!numa_enabled || (min_common_depth < 0)) | 986 | if (!numa_enabled || (min_common_depth < 0)) |
916 | return default_nid; | 987 | return any_online_node(NODE_MASK_ALL); |
988 | |||
989 | memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); | ||
990 | if (memory) { | ||
991 | nid = hot_add_drconf_scn_to_nid(memory, scn_addr); | ||
992 | of_node_put(memory); | ||
993 | return nid; | ||
994 | } | ||
917 | 995 | ||
918 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { | 996 | while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { |
919 | unsigned long start, size; | 997 | unsigned long start, size; |
@@ -932,13 +1010,9 @@ ha_new_range: | |||
932 | size = read_n_cells(n_mem_size_cells, &memcell_buf); | 1010 | size = read_n_cells(n_mem_size_cells, &memcell_buf); |
933 | nid = of_node_to_nid_single(memory); | 1011 | nid = of_node_to_nid_single(memory); |
934 | 1012 | ||
935 | /* Domains not present at boot default to 0 */ | 1013 | if (valid_hot_add_scn(&nid, start, size, scn_addr)) { |
936 | if (nid < 0 || !node_online(nid)) | ||
937 | nid = default_nid; | ||
938 | |||
939 | if ((scn_addr >= start) && (scn_addr < (start + size))) { | ||
940 | of_node_put(memory); | 1014 | of_node_put(memory); |
941 | goto got_nid; | 1015 | return nid; |
942 | } | 1016 | } |
943 | 1017 | ||
944 | if (--ranges) /* process all ranges in cell */ | 1018 | if (--ranges) /* process all ranges in cell */ |
@@ -946,14 +1020,5 @@ ha_new_range: | |||
946 | } | 1020 | } |
947 | BUG(); /* section address should be found above */ | 1021 | BUG(); /* section address should be found above */ |
948 | return 0; | 1022 | return 0; |
949 | |||
950 | /* Temporary code to ensure that returned node is not empty */ | ||
951 | got_nid: | ||
952 | nodes_setall(nodes); | ||
953 | while (NODE_DATA(nid)->node_spanned_pages == 0) { | ||
954 | node_clear(nid, nodes); | ||
955 | nid = any_online_node(nodes); | ||
956 | } | ||
957 | return nid; | ||
958 | } | 1023 | } |
959 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 1024 | #endif /* CONFIG_MEMORY_HOTPLUG */ |