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 */ |
