[PATCH] powerpc: numa placement for dynamically added memory
This places dynamically added memory within the appropriate numa node. A new routine hot_add_scn_to_nid() replicates most of the memory scanning code in parse_numa_properties(). Signed-off-by: Mike Kravetz <kravetz@us.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
committed by
Paul Mackerras
parent
b5666f7039
commit
237a0989e2
@@ -114,18 +114,17 @@ void online_page(struct page *page)
|
|||||||
num_physpages++;
|
num_physpages++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This works only for the non-NUMA case. Later, we'll need a lookup
|
|
||||||
* to convert from real physical addresses to nid, that doesn't use
|
|
||||||
* pfn_to_nid().
|
|
||||||
*/
|
|
||||||
int __devinit add_memory(u64 start, u64 size)
|
int __devinit add_memory(u64 start, u64 size)
|
||||||
{
|
{
|
||||||
struct pglist_data *pgdata = NODE_DATA(0);
|
struct pglist_data *pgdata;
|
||||||
struct zone *zone;
|
struct zone *zone;
|
||||||
|
int nid;
|
||||||
unsigned long start_pfn = start >> PAGE_SHIFT;
|
unsigned long start_pfn = start >> PAGE_SHIFT;
|
||||||
unsigned long nr_pages = size >> PAGE_SHIFT;
|
unsigned long nr_pages = size >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
nid = hot_add_scn_to_nid(start);
|
||||||
|
pgdata = NODE_DATA(nid);
|
||||||
|
|
||||||
start += KERNELBASE;
|
start += KERNELBASE;
|
||||||
create_section_mapping(start, start + size);
|
create_section_mapping(start, start + size);
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data);
|
|||||||
|
|
||||||
static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
|
static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
|
||||||
static int min_common_depth;
|
static int min_common_depth;
|
||||||
|
static int n_mem_addr_cells, n_mem_size_cells;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need somewhere to store start/end/node for each region until we have
|
* We need somewhere to store start/end/node for each region until we have
|
||||||
@@ -267,7 +268,7 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
|
|||||||
of_node_put(memory);
|
of_node_put(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long __init read_n_cells(int n, unsigned int **buf)
|
static unsigned long __devinit read_n_cells(int n, unsigned int **buf)
|
||||||
{
|
{
|
||||||
unsigned long result = 0;
|
unsigned long result = 0;
|
||||||
|
|
||||||
@@ -374,7 +375,6 @@ static int __init parse_numa_properties(void)
|
|||||||
{
|
{
|
||||||
struct device_node *cpu = NULL;
|
struct device_node *cpu = NULL;
|
||||||
struct device_node *memory = NULL;
|
struct device_node *memory = NULL;
|
||||||
int n_addr_cells, n_size_cells;
|
|
||||||
int max_domain;
|
int max_domain;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ static int __init parse_numa_properties(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_n_mem_cells(&n_addr_cells, &n_size_cells);
|
get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
|
while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
|
||||||
unsigned long start;
|
unsigned long start;
|
||||||
@@ -430,8 +430,8 @@ static int __init parse_numa_properties(void)
|
|||||||
ranges = memory->n_addrs;
|
ranges = memory->n_addrs;
|
||||||
new_range:
|
new_range:
|
||||||
/* these are order-sensitive, and modify the buffer pointer */
|
/* these are order-sensitive, and modify the buffer pointer */
|
||||||
start = read_n_cells(n_addr_cells, &memcell_buf);
|
start = read_n_cells(n_mem_addr_cells, &memcell_buf);
|
||||||
size = read_n_cells(n_size_cells, &memcell_buf);
|
size = read_n_cells(n_mem_size_cells, &memcell_buf);
|
||||||
|
|
||||||
numa_domain = of_node_numa_domain(memory);
|
numa_domain = of_node_numa_domain(memory);
|
||||||
|
|
||||||
@@ -717,3 +717,50 @@ static int __init early_numa(char *p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
early_param("numa", early_numa);
|
early_param("numa", early_numa);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||||
|
/*
|
||||||
|
* Find the node associated with a hot added memory section. Section
|
||||||
|
* corresponds to a SPARSEMEM section, not an LMB. It is assumed that
|
||||||
|
* sections are fully contained within a single LMB.
|
||||||
|
*/
|
||||||
|
int hot_add_scn_to_nid(unsigned long scn_addr)
|
||||||
|
{
|
||||||
|
struct device_node *memory = NULL;
|
||||||
|
|
||||||
|
if (!numa_enabled || (min_common_depth < 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
|
||||||
|
unsigned long start, size;
|
||||||
|
int numa_domain, ranges;
|
||||||
|
unsigned int *memcell_buf;
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
|
||||||
|
if (!memcell_buf || len <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ranges = memory->n_addrs; /* ranges in cell */
|
||||||
|
ha_new_range:
|
||||||
|
start = read_n_cells(n_mem_addr_cells, &memcell_buf);
|
||||||
|
size = read_n_cells(n_mem_size_cells, &memcell_buf);
|
||||||
|
numa_domain = of_node_numa_domain(memory);
|
||||||
|
|
||||||
|
/* Domains not present at boot default to 0 */
|
||||||
|
if (!node_online(numa_domain))
|
||||||
|
numa_domain = any_online_node(NODE_MASK_ALL);
|
||||||
|
|
||||||
|
if ((scn_addr >= start) && (scn_addr < (start + size))) {
|
||||||
|
of_node_put(memory);
|
||||||
|
return numa_domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--ranges) /* process all ranges in cell */
|
||||||
|
goto ha_new_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG(); /* section address should be found above */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MEMORY_HOTPLUG */
|
||||||
|
@@ -13,6 +13,14 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||||
extern void create_section_mapping(unsigned long start, unsigned long end);
|
extern void create_section_mapping(unsigned long start, unsigned long end);
|
||||||
|
#ifdef CONFIG_NUMA
|
||||||
|
extern int hot_add_scn_to_nid(unsigned long scn_addr);
|
||||||
|
#else
|
||||||
|
static inline int hot_add_scn_to_nid(unsigned long scn_addr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NUMA */
|
||||||
#endif /* CONFIG_MEMORY_HOTPLUG */
|
#endif /* CONFIG_MEMORY_HOTPLUG */
|
||||||
|
|
||||||
#endif /* CONFIG_SPARSEMEM */
|
#endif /* CONFIG_SPARSEMEM */
|
||||||
|
Reference in New Issue
Block a user