Skip to content

Commit

Permalink
powerpc/pseries: Update numa association of hotplug memory add for dr…
Browse files Browse the repository at this point in the history
…conf memory

Update the association of a memory section with a numa node that
occurs during hotplug add of a memory section.  This adds a check in
the hot_add_scn_to_nid() routine for the
ibm,dynamic-reconfiguration-memory node in the device tree.  If
present the new hot_add_drconf_scn_to_nid() routine is invoked, which
can properly parse the ibm,dynamic-reconfiguration-memory node of the
device tree and make the proper numa node associations.

This also introduces the valid_hot_add_scn() routine as a helper
function for code that is common to the hot_add_scn_to_nid() and
hot_add_drconf_scn_to_nid() routines.

Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Nathan Fontenot authored and Paul Mackerras committed Jul 3, 2008
1 parent 8342681 commit 0db9360
Showing 1 changed file with 83 additions and 18 deletions.
101 changes: 83 additions & 18 deletions arch/powerpc/mm/numa.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,79 @@ static int __init early_numa(char *p)
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.
*/
static int hot_add_drconf_scn_to_nid(struct device_node *memory,
unsigned long scn_addr)
{
const u32 *dm;
unsigned int n, rc;
unsigned long lmb_size;
int default_nid = any_online_node(NODE_MASK_ALL);
int nid;
struct assoc_arrays aa;

n = of_get_drconf_memory(memory, &dm);
if (!n)
return default_nid;;

lmb_size = of_get_lmb_size(memory);
if (!lmb_size)
return default_nid;

rc = of_get_assoc_arrays(memory, &aa);
if (rc)
return default_nid;

for (; n != 0; --n) {
struct of_drconf_cell drmem;

read_drconf_cell(&drmem, &dm);

/* skip this block if it is reserved or not assigned to
* this partition */
if ((drmem.flags & DRCONF_MEM_RESERVED)
|| !(drmem.flags & DRCONF_MEM_ASSIGNED))
continue;

nid = of_drconf_to_nid_single(&drmem, &aa);

if (valid_hot_add_scn(&nid, drmem.base_addr, lmb_size,
scn_addr))
return nid;
}

BUG(); /* section address should be found above */
return 0;
}

/*
* Find the node associated with a hot added memory section. Section
* corresponds to a SPARSEMEM section, not an LMB. It is assumed that
Expand All @@ -908,12 +981,17 @@ early_param("numa", early_numa);
int hot_add_scn_to_nid(unsigned long scn_addr)
{
struct device_node *memory = NULL;
nodemask_t nodes;
int default_nid = any_online_node(NODE_MASK_ALL);
int nid;

if (!numa_enabled || (min_common_depth < 0))
return default_nid;
return any_online_node(NODE_MASK_ALL);

memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (memory) {
nid = hot_add_drconf_scn_to_nid(memory, scn_addr);
of_node_put(memory);
return nid;
}

while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
unsigned long start, size;
Expand All @@ -932,28 +1010,15 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
size = read_n_cells(n_mem_size_cells, &memcell_buf);
nid = of_node_to_nid_single(memory);

/* Domains not present at boot default to 0 */
if (nid < 0 || !node_online(nid))
nid = default_nid;

if ((scn_addr >= start) && (scn_addr < (start + size))) {
if (valid_hot_add_scn(&nid, start, size, scn_addr)) {
of_node_put(memory);
goto got_nid;
return nid;
}

if (--ranges) /* process all ranges in cell */
goto ha_new_range;
}
BUG(); /* section address should be found above */
return 0;

/* Temporary code to ensure that returned node is not empty */
got_nid:
nodes_setall(nodes);
while (NODE_DATA(nid)->node_spanned_pages == 0) {
node_clear(nid, nodes);
nid = any_online_node(nodes);
}
return nid;
}
#endif /* CONFIG_MEMORY_HOTPLUG */

0 comments on commit 0db9360

Please sign in to comment.