diff options
Diffstat (limited to 'arch/x86/mm/numa.c')
| -rw-r--r-- | arch/x86/mm/numa.c | 80 | 
1 files changed, 71 insertions, 9 deletions
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 8bf93bae1f1..a32b706c401 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -211,9 +211,13 @@ static void __init setup_node_data(int nid, u64 start, u64 end)  	 */  	nd_pa = memblock_alloc_nid(nd_size, SMP_CACHE_BYTES, nid);  	if (!nd_pa) { -		pr_err("Cannot find %zu bytes in node %d\n", -		       nd_size, nid); -		return; +		nd_pa = __memblock_alloc_base(nd_size, SMP_CACHE_BYTES, +					      MEMBLOCK_ALLOC_ACCESSIBLE); +		if (!nd_pa) { +			pr_err("Cannot find %zu bytes in node %d\n", +			       nd_size, nid); +			return; +		}  	}  	nd = __va(nd_pa); @@ -487,7 +491,8 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)  	for (i = 0; i < mi->nr_blks; i++) {  		struct numa_memblk *mb = &mi->blk[i]; -		memblock_set_node(mb->start, mb->end - mb->start, mb->nid); +		memblock_set_node(mb->start, mb->end - mb->start, +				  &memblock.memory, mb->nid);  	}  	/* @@ -549,6 +554,41 @@ static void __init numa_init_array(void)  	}  } +static void __init numa_clear_kernel_node_hotplug(void) +{ +	int i, nid; +	nodemask_t numa_kernel_nodes = NODE_MASK_NONE; +	unsigned long start, end; +	struct memblock_region *r; + +	/* +	 * At this time, all memory regions reserved by memblock are +	 * used by the kernel. Set the nid in memblock.reserved will +	 * mark out all the nodes the kernel resides in. +	 */ +	for (i = 0; i < numa_meminfo.nr_blks; i++) { +		struct numa_memblk *mb = &numa_meminfo.blk[i]; +		memblock_set_node(mb->start, mb->end - mb->start, +				  &memblock.reserved, mb->nid); +	} + +	/* Mark all kernel nodes. */ +	for_each_memblock(reserved, r) +		node_set(r->nid, numa_kernel_nodes); + +	/* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */ +	for (i = 0; i < numa_meminfo.nr_blks; i++) { +		nid = numa_meminfo.blk[i].nid; +		if (!node_isset(nid, numa_kernel_nodes)) +			continue; + +		start = numa_meminfo.blk[i].start; +		end = numa_meminfo.blk[i].end; + +		memblock_clear_hotplug(start, end - start); +	} +} +  static int __init numa_init(int (*init_func)(void))  {  	int i; @@ -561,12 +601,28 @@ static int __init numa_init(int (*init_func)(void))  	nodes_clear(node_possible_map);  	nodes_clear(node_online_map);  	memset(&numa_meminfo, 0, sizeof(numa_meminfo)); -	WARN_ON(memblock_set_node(0, ULLONG_MAX, MAX_NUMNODES)); +	WARN_ON(memblock_set_node(0, ULLONG_MAX, &memblock.memory, +				  MAX_NUMNODES)); +	WARN_ON(memblock_set_node(0, ULLONG_MAX, &memblock.reserved, +				  MAX_NUMNODES)); +	/* In case that parsing SRAT failed. */ +	WARN_ON(memblock_clear_hotplug(0, ULLONG_MAX));  	numa_reset_distance();  	ret = init_func();  	if (ret < 0)  		return ret; + +	/* +	 * We reset memblock back to the top-down direction +	 * here because if we configured ACPI_NUMA, we have +	 * parsed SRAT in init_func(). It is ok to have the +	 * reset here even if we did't configure ACPI_NUMA +	 * or acpi numa init fails and fallbacks to dummy +	 * numa init. +	 */ +	memblock_set_bottom_up(false); +  	ret = numa_cleanup_meminfo(&numa_meminfo);  	if (ret < 0)  		return ret; @@ -586,6 +642,16 @@ static int __init numa_init(int (*init_func)(void))  			numa_clear_node(i);  	}  	numa_init_array(); + +	/* +	 * At very early time, the kernel have to use some memory such as +	 * loading the kernel image. We cannot prevent this anyway. So any +	 * node the kernel resides in should be un-hotpluggable. +	 * +	 * And when we come here, numa_init() won't fail. +	 */ +	numa_clear_kernel_node_hotplug(); +  	return 0;  } @@ -621,10 +687,6 @@ static int __init dummy_numa_init(void)  void __init x86_numa_init(void)  {  	if (!numa_off) { -#ifdef CONFIG_X86_NUMAQ -		if (!numa_init(numaq_numa_init)) -			return; -#endif  #ifdef CONFIG_ACPI_NUMA  		if (!numa_init(x86_acpi_numa_init))  			return;  | 
