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); #ifdef CONFIG_MEMORY_HOTPLUG /* - * Validate the node associated with the memory section we are - * trying to add. - */ -int valid_hot_add_scn(int *nid, unsigned long start, u32 lmb_size, - unsigned long scn_addr) -{ - nodemask_t nodes; - - if (*nid < 0 || !node_online(*nid)) - *nid = any_online_node(NODE_MASK_ALL); - - if ((scn_addr >= start) && (scn_addr < (start + lmb_size))) { - nodes_setall(nodes); - while (NODE_DATA(*nid)->node_spanned_pages == 0) { - node_clear(*nid, nodes); - *nid = any_online_node(nodes); - } - - return 1; - } - - return 0; -} - -/* - * Find the node associated with a hot added memory section represented - * by the ibm,dynamic-reconfiguration-memory node. + * Find the node associated with a hot added memory section for + * memory represented in the device tree by the property + * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory. */ static int hot_add_drconf_scn_to_nid(struct device_node *memory, unsigned long scn_addr) { const u32 *dm; - unsigned int n, rc; + unsigned int drconf_cell_cnt, rc; unsigned long lmb_size; - int default_nid = any_online_node(NODE_MASK_ALL); - int nid; struct assoc_arrays aa; + int nid = -1; - n = of_get_drconf_memory(memory, &dm); - if (!n) - return default_nid;; + drconf_cell_cnt = of_get_drconf_memory(memory, &dm); + if (!drconf_cell_cnt) + return -1; lmb_size = of_get_lmb_size(memory); if (!lmb_size) - return default_nid; + return -1; rc = of_get_assoc_arrays(memory, &aa); if (rc) - return default_nid; + return -1; - for (; n != 0; --n) { + for (; drconf_cell_cnt != 0; --drconf_cell_cnt) { struct of_drconf_cell drmem; read_drconf_cell(&drmem, &dm); @@ -1073,15 +1048,57 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, || !(drmem.flags & DRCONF_MEM_ASSIGNED)) continue; + if ((scn_addr < drmem.base_addr) + || (scn_addr >= (drmem.base_addr + lmb_size))) + continue; + nid = of_drconf_to_nid_single(&drmem, &aa); + break; + } + + return nid; +} + +/* + * Find the node associated with a hot added memory section for memory + * represented in the device tree as a node (i.e. memory@XXXX) for + * each lmb. + */ +int hot_add_node_scn_to_nid(unsigned long scn_addr) +{ + struct device_node *memory = NULL; + int nid = -1; + + while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { + unsigned long start, size; + int ranges; + const unsigned int *memcell_buf; + unsigned int len; + + memcell_buf = of_get_property(memory, "reg", &len); + if (!memcell_buf || len <= 0) + continue; + + /* ranges in cell */ + ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); + + while (ranges--) { + start = read_n_cells(n_mem_addr_cells, &memcell_buf); + size = read_n_cells(n_mem_size_cells, &memcell_buf); + + if ((scn_addr < start) || (scn_addr >= (start + size))) + continue; + + nid = of_node_to_nid_single(memory); + break; + } - if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size, - scn_addr)) - return nid; + of_node_put(memory); + if (nid >= 0) + break; } - BUG(); /* section address should be found above */ - return 0; + return nid; } /* @@ -1092,7 +1109,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, int hot_add_scn_to_nid(unsigned long scn_addr) { struct device_node *memory = NULL; - int nid; + int nid, found = 0; if (!numa_enabled || (min_common_depth < 0)) return any_online_node(NODE_MASK_ALL); @@ -1101,35 +1118,25 @@ int hot_add_scn_to_nid(unsigned long scn_addr) if (memory) { nid = hot_add_drconf_scn_to_nid(memory, scn_addr); of_node_put(memory); - return nid; + } else { + nid = hot_add_node_scn_to_nid(scn_addr); } - while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { - unsigned long start, size; - int ranges; - const unsigned int *memcell_buf; - unsigned int len; - - memcell_buf = of_get_property(memory, "reg", &len); - if (!memcell_buf || len <= 0) - continue; + if (nid < 0 || !node_online(nid)) + nid = any_online_node(NODE_MASK_ALL); - /* ranges in cell */ - ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); -ha_new_range: - start = read_n_cells(n_mem_addr_cells, &memcell_buf); - size = read_n_cells(n_mem_size_cells, &memcell_buf); - nid = of_node_to_nid_single(memory); + if (NODE_DATA(nid)->node_spanned_pages) + return nid; - if (valid_hot_add_scn(&nid, start, size, scn_addr)) { - of_node_put(memory); - return nid; + for_each_online_node(nid) { + if (NODE_DATA(nid)->node_spanned_pages) { + found = 1; + break; } - - if (--ranges) /* process all ranges in cell */ - goto ha_new_range; } - BUG(); /* section address should be found above */ - return 0; + + BUG_ON(!found); + return nid; } + #endif /* CONFIG_MEMORY_HOTPLUG */ |