xref: /linux/mm/numa_memblks.c (revision 3e9e952bb3139ad1e08f3e1960239c2988ab90c9)
187482708SMike Rapoport (Microsoft) // SPDX-License-Identifier: GPL-2.0-or-later
287482708SMike Rapoport (Microsoft) 
387482708SMike Rapoport (Microsoft) #include <linux/array_size.h>
487482708SMike Rapoport (Microsoft) #include <linux/sort.h>
587482708SMike Rapoport (Microsoft) #include <linux/printk.h>
687482708SMike Rapoport (Microsoft) #include <linux/memblock.h>
787482708SMike Rapoport (Microsoft) #include <linux/numa.h>
887482708SMike Rapoport (Microsoft) #include <linux/numa_memblks.h>
987482708SMike Rapoport (Microsoft) 
10f46c26f1SBen Dooks #include <asm/numa.h>
11f46c26f1SBen Dooks 
1263db8170SBruno Faccini int numa_distance_cnt;
1375f9d4ccSMike Rapoport (Microsoft) static u8 *numa_distance;
1475f9d4ccSMike Rapoport (Microsoft) 
1587482708SMike Rapoport (Microsoft) nodemask_t numa_nodes_parsed __initdata;
1687482708SMike Rapoport (Microsoft) 
17317ef459SMike Rapoport (Microsoft) static struct numa_meminfo numa_meminfo __initdata_or_meminfo;
18317ef459SMike Rapoport (Microsoft) static struct numa_meminfo numa_reserved_meminfo __initdata_or_meminfo;
19317ef459SMike Rapoport (Microsoft) 
20317ef459SMike Rapoport (Microsoft) /*
21317ef459SMike Rapoport (Microsoft)  * Set nodes, which have memory in @mi, in *@nodemask.
22317ef459SMike Rapoport (Microsoft)  */
numa_nodemask_from_meminfo(nodemask_t * nodemask,const struct numa_meminfo * mi)23317ef459SMike Rapoport (Microsoft) static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
24317ef459SMike Rapoport (Microsoft) 					      const struct numa_meminfo *mi)
25317ef459SMike Rapoport (Microsoft) {
26317ef459SMike Rapoport (Microsoft) 	int i;
27317ef459SMike Rapoport (Microsoft) 
28317ef459SMike Rapoport (Microsoft) 	for (i = 0; i < ARRAY_SIZE(mi->blk); i++)
29317ef459SMike Rapoport (Microsoft) 		if (mi->blk[i].start != mi->blk[i].end &&
30317ef459SMike Rapoport (Microsoft) 		    mi->blk[i].nid != NUMA_NO_NODE)
31317ef459SMike Rapoport (Microsoft) 			node_set(mi->blk[i].nid, *nodemask);
32317ef459SMike Rapoport (Microsoft) }
3387482708SMike Rapoport (Microsoft) 
3475f9d4ccSMike Rapoport (Microsoft) /**
3575f9d4ccSMike Rapoport (Microsoft)  * numa_reset_distance - Reset NUMA distance table
3675f9d4ccSMike Rapoport (Microsoft)  *
3775f9d4ccSMike Rapoport (Microsoft)  * The current table is freed.  The next numa_set_distance() call will
3875f9d4ccSMike Rapoport (Microsoft)  * create a new one.
3975f9d4ccSMike Rapoport (Microsoft)  */
numa_reset_distance(void)4075f9d4ccSMike Rapoport (Microsoft) void __init numa_reset_distance(void)
4175f9d4ccSMike Rapoport (Microsoft) {
4275f9d4ccSMike Rapoport (Microsoft) 	size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
4375f9d4ccSMike Rapoport (Microsoft) 
4475f9d4ccSMike Rapoport (Microsoft) 	/* numa_distance could be 1LU marking allocation failure, test cnt */
4575f9d4ccSMike Rapoport (Microsoft) 	if (numa_distance_cnt)
4675f9d4ccSMike Rapoport (Microsoft) 		memblock_free(numa_distance, size);
4775f9d4ccSMike Rapoport (Microsoft) 	numa_distance_cnt = 0;
4875f9d4ccSMike Rapoport (Microsoft) 	numa_distance = NULL;	/* enable table creation */
4975f9d4ccSMike Rapoport (Microsoft) }
5075f9d4ccSMike Rapoport (Microsoft) 
numa_alloc_distance(void)5175f9d4ccSMike Rapoport (Microsoft) static int __init numa_alloc_distance(void)
5275f9d4ccSMike Rapoport (Microsoft) {
5375f9d4ccSMike Rapoport (Microsoft) 	nodemask_t nodes_parsed;
5475f9d4ccSMike Rapoport (Microsoft) 	size_t size;
5575f9d4ccSMike Rapoport (Microsoft) 	int i, j, cnt = 0;
5675f9d4ccSMike Rapoport (Microsoft) 
5775f9d4ccSMike Rapoport (Microsoft) 	/* size the new table and allocate it */
5875f9d4ccSMike Rapoport (Microsoft) 	nodes_parsed = numa_nodes_parsed;
5975f9d4ccSMike Rapoport (Microsoft) 	numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
6075f9d4ccSMike Rapoport (Microsoft) 
6175f9d4ccSMike Rapoport (Microsoft) 	for_each_node_mask(i, nodes_parsed)
6275f9d4ccSMike Rapoport (Microsoft) 		cnt = i;
6375f9d4ccSMike Rapoport (Microsoft) 	cnt++;
6475f9d4ccSMike Rapoport (Microsoft) 	size = cnt * cnt * sizeof(numa_distance[0]);
6575f9d4ccSMike Rapoport (Microsoft) 
6675f9d4ccSMike Rapoport (Microsoft) 	numa_distance = memblock_alloc(size, PAGE_SIZE);
6775f9d4ccSMike Rapoport (Microsoft) 	if (!numa_distance) {
6875f9d4ccSMike Rapoport (Microsoft) 		pr_warn("Warning: can't allocate distance table!\n");
6975f9d4ccSMike Rapoport (Microsoft) 		/* don't retry until explicitly reset */
7075f9d4ccSMike Rapoport (Microsoft) 		numa_distance = (void *)1LU;
7175f9d4ccSMike Rapoport (Microsoft) 		return -ENOMEM;
7275f9d4ccSMike Rapoport (Microsoft) 	}
7375f9d4ccSMike Rapoport (Microsoft) 
7475f9d4ccSMike Rapoport (Microsoft) 	numa_distance_cnt = cnt;
7575f9d4ccSMike Rapoport (Microsoft) 
7675f9d4ccSMike Rapoport (Microsoft) 	/* fill with the default distances */
7775f9d4ccSMike Rapoport (Microsoft) 	for (i = 0; i < cnt; i++)
7875f9d4ccSMike Rapoport (Microsoft) 		for (j = 0; j < cnt; j++)
7975f9d4ccSMike Rapoport (Microsoft) 			numa_distance[i * cnt + j] = i == j ?
8075f9d4ccSMike Rapoport (Microsoft) 				LOCAL_DISTANCE : REMOTE_DISTANCE;
81d045c315SPratyush Brahma 	pr_debug("NUMA: Initialized distance table, cnt=%d\n", cnt);
8275f9d4ccSMike Rapoport (Microsoft) 
8375f9d4ccSMike Rapoport (Microsoft) 	return 0;
8475f9d4ccSMike Rapoport (Microsoft) }
8575f9d4ccSMike Rapoport (Microsoft) 
8675f9d4ccSMike Rapoport (Microsoft) /**
8775f9d4ccSMike Rapoport (Microsoft)  * numa_set_distance - Set NUMA distance from one NUMA to another
8875f9d4ccSMike Rapoport (Microsoft)  * @from: the 'from' node to set distance
8975f9d4ccSMike Rapoport (Microsoft)  * @to: the 'to'  node to set distance
9075f9d4ccSMike Rapoport (Microsoft)  * @distance: NUMA distance
9175f9d4ccSMike Rapoport (Microsoft)  *
9275f9d4ccSMike Rapoport (Microsoft)  * Set the distance from node @from to @to to @distance.  If distance table
9375f9d4ccSMike Rapoport (Microsoft)  * doesn't exist, one which is large enough to accommodate all the currently
9475f9d4ccSMike Rapoport (Microsoft)  * known nodes will be created.
9575f9d4ccSMike Rapoport (Microsoft)  *
9675f9d4ccSMike Rapoport (Microsoft)  * If such table cannot be allocated, a warning is printed and further
9775f9d4ccSMike Rapoport (Microsoft)  * calls are ignored until the distance table is reset with
9875f9d4ccSMike Rapoport (Microsoft)  * numa_reset_distance().
9975f9d4ccSMike Rapoport (Microsoft)  *
10075f9d4ccSMike Rapoport (Microsoft)  * If @from or @to is higher than the highest known node or lower than zero
10175f9d4ccSMike Rapoport (Microsoft)  * at the time of table creation or @distance doesn't make sense, the call
10275f9d4ccSMike Rapoport (Microsoft)  * is ignored.
10375f9d4ccSMike Rapoport (Microsoft)  * This is to allow simplification of specific NUMA config implementations.
10475f9d4ccSMike Rapoport (Microsoft)  */
numa_set_distance(int from,int to,int distance)10575f9d4ccSMike Rapoport (Microsoft) void __init numa_set_distance(int from, int to, int distance)
10675f9d4ccSMike Rapoport (Microsoft) {
10775f9d4ccSMike Rapoport (Microsoft) 	if (!numa_distance && numa_alloc_distance() < 0)
10875f9d4ccSMike Rapoport (Microsoft) 		return;
10975f9d4ccSMike Rapoport (Microsoft) 
11075f9d4ccSMike Rapoport (Microsoft) 	if (from >= numa_distance_cnt || to >= numa_distance_cnt ||
11175f9d4ccSMike Rapoport (Microsoft) 			from < 0 || to < 0) {
11275f9d4ccSMike Rapoport (Microsoft) 		pr_warn_once("Warning: node ids are out of bound, from=%d to=%d distance=%d\n",
11375f9d4ccSMike Rapoport (Microsoft) 			     from, to, distance);
11475f9d4ccSMike Rapoport (Microsoft) 		return;
11575f9d4ccSMike Rapoport (Microsoft) 	}
11675f9d4ccSMike Rapoport (Microsoft) 
11775f9d4ccSMike Rapoport (Microsoft) 	if ((u8)distance != distance ||
11875f9d4ccSMike Rapoport (Microsoft) 	    (from == to && distance != LOCAL_DISTANCE)) {
11975f9d4ccSMike Rapoport (Microsoft) 		pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
12075f9d4ccSMike Rapoport (Microsoft) 			     from, to, distance);
12175f9d4ccSMike Rapoport (Microsoft) 		return;
12275f9d4ccSMike Rapoport (Microsoft) 	}
12375f9d4ccSMike Rapoport (Microsoft) 
12475f9d4ccSMike Rapoport (Microsoft) 	numa_distance[from * numa_distance_cnt + to] = distance;
12575f9d4ccSMike Rapoport (Microsoft) }
12675f9d4ccSMike Rapoport (Microsoft) 
__node_distance(int from,int to)12775f9d4ccSMike Rapoport (Microsoft) int __node_distance(int from, int to)
12875f9d4ccSMike Rapoport (Microsoft) {
12975f9d4ccSMike Rapoport (Microsoft) 	if (from >= numa_distance_cnt || to >= numa_distance_cnt)
13075f9d4ccSMike Rapoport (Microsoft) 		return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
13175f9d4ccSMike Rapoport (Microsoft) 	return numa_distance[from * numa_distance_cnt + to];
13275f9d4ccSMike Rapoport (Microsoft) }
13375f9d4ccSMike Rapoport (Microsoft) EXPORT_SYMBOL(__node_distance);
13475f9d4ccSMike Rapoport (Microsoft) 
numa_add_memblk_to(int nid,u64 start,u64 end,struct numa_meminfo * mi)13587482708SMike Rapoport (Microsoft) static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
13687482708SMike Rapoport (Microsoft) 				     struct numa_meminfo *mi)
13787482708SMike Rapoport (Microsoft) {
13887482708SMike Rapoport (Microsoft) 	/* ignore zero length blks */
13987482708SMike Rapoport (Microsoft) 	if (start == end)
14087482708SMike Rapoport (Microsoft) 		return 0;
14187482708SMike Rapoport (Microsoft) 
14287482708SMike Rapoport (Microsoft) 	/* whine about and ignore invalid blks */
14387482708SMike Rapoport (Microsoft) 	if (start > end || nid < 0 || nid >= MAX_NUMNODES) {
14487482708SMike Rapoport (Microsoft) 		pr_warn("Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n",
14587482708SMike Rapoport (Microsoft) 			nid, start, end - 1);
14687482708SMike Rapoport (Microsoft) 		return 0;
14787482708SMike Rapoport (Microsoft) 	}
14887482708SMike Rapoport (Microsoft) 
14987482708SMike Rapoport (Microsoft) 	if (mi->nr_blks >= NR_NODE_MEMBLKS) {
15087482708SMike Rapoport (Microsoft) 		pr_err("too many memblk ranges\n");
15187482708SMike Rapoport (Microsoft) 		return -EINVAL;
15287482708SMike Rapoport (Microsoft) 	}
15387482708SMike Rapoport (Microsoft) 
15487482708SMike Rapoport (Microsoft) 	mi->blk[mi->nr_blks].start = start;
15587482708SMike Rapoport (Microsoft) 	mi->blk[mi->nr_blks].end = end;
15687482708SMike Rapoport (Microsoft) 	mi->blk[mi->nr_blks].nid = nid;
15787482708SMike Rapoport (Microsoft) 	mi->nr_blks++;
15887482708SMike Rapoport (Microsoft) 	return 0;
15987482708SMike Rapoport (Microsoft) }
16087482708SMike Rapoport (Microsoft) 
16187482708SMike Rapoport (Microsoft) /**
16287482708SMike Rapoport (Microsoft)  * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
16387482708SMike Rapoport (Microsoft)  * @idx: Index of memblk to remove
16487482708SMike Rapoport (Microsoft)  * @mi: numa_meminfo to remove memblk from
16587482708SMike Rapoport (Microsoft)  *
16687482708SMike Rapoport (Microsoft)  * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
16787482708SMike Rapoport (Microsoft)  * decrementing @mi->nr_blks.
16887482708SMike Rapoport (Microsoft)  */
numa_remove_memblk_from(int idx,struct numa_meminfo * mi)16987482708SMike Rapoport (Microsoft) void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
17087482708SMike Rapoport (Microsoft) {
17187482708SMike Rapoport (Microsoft) 	mi->nr_blks--;
17287482708SMike Rapoport (Microsoft) 	memmove(&mi->blk[idx], &mi->blk[idx + 1],
17387482708SMike Rapoport (Microsoft) 		(mi->nr_blks - idx) * sizeof(mi->blk[0]));
17487482708SMike Rapoport (Microsoft) }
17587482708SMike Rapoport (Microsoft) 
17687482708SMike Rapoport (Microsoft) /**
17787482708SMike Rapoport (Microsoft)  * numa_move_tail_memblk - Move a numa_memblk from one numa_meminfo to another
17887482708SMike Rapoport (Microsoft)  * @dst: numa_meminfo to append block to
17987482708SMike Rapoport (Microsoft)  * @idx: Index of memblk to remove
18087482708SMike Rapoport (Microsoft)  * @src: numa_meminfo to remove memblk from
18187482708SMike Rapoport (Microsoft)  */
numa_move_tail_memblk(struct numa_meminfo * dst,int idx,struct numa_meminfo * src)18287482708SMike Rapoport (Microsoft) static void __init numa_move_tail_memblk(struct numa_meminfo *dst, int idx,
18387482708SMike Rapoport (Microsoft) 					 struct numa_meminfo *src)
18487482708SMike Rapoport (Microsoft) {
18587482708SMike Rapoport (Microsoft) 	dst->blk[dst->nr_blks++] = src->blk[idx];
18687482708SMike Rapoport (Microsoft) 	numa_remove_memblk_from(idx, src);
18787482708SMike Rapoport (Microsoft) }
18887482708SMike Rapoport (Microsoft) 
18987482708SMike Rapoport (Microsoft) /**
19087482708SMike Rapoport (Microsoft)  * numa_add_memblk - Add one numa_memblk to numa_meminfo
19187482708SMike Rapoport (Microsoft)  * @nid: NUMA node ID of the new memblk
19287482708SMike Rapoport (Microsoft)  * @start: Start address of the new memblk
19387482708SMike Rapoport (Microsoft)  * @end: End address of the new memblk
19487482708SMike Rapoport (Microsoft)  *
19587482708SMike Rapoport (Microsoft)  * Add a new memblk to the default numa_meminfo.
19687482708SMike Rapoport (Microsoft)  *
19787482708SMike Rapoport (Microsoft)  * RETURNS:
19887482708SMike Rapoport (Microsoft)  * 0 on success, -errno on failure.
19987482708SMike Rapoport (Microsoft)  */
numa_add_memblk(int nid,u64 start,u64 end)20087482708SMike Rapoport (Microsoft) int __init numa_add_memblk(int nid, u64 start, u64 end)
20187482708SMike Rapoport (Microsoft) {
20287482708SMike Rapoport (Microsoft) 	return numa_add_memblk_to(nid, start, end, &numa_meminfo);
20387482708SMike Rapoport (Microsoft) }
20487482708SMike Rapoport (Microsoft) 
20587482708SMike Rapoport (Microsoft) /**
2063f126809SYuquan Wang  * numa_add_reserved_memblk - Add one numa_memblk to numa_reserved_meminfo
2073f126809SYuquan Wang  * @nid: NUMA node ID of the new memblk
2083f126809SYuquan Wang  * @start: Start address of the new memblk
2093f126809SYuquan Wang  * @end: End address of the new memblk
2103f126809SYuquan Wang  *
2113f126809SYuquan Wang  * Add a new memblk to the numa_reserved_meminfo.
2123f126809SYuquan Wang  *
2133f126809SYuquan Wang  * Usage Case: numa_cleanup_meminfo() reconciles all numa_memblk instances
2143f126809SYuquan Wang  * against memblock_type information and moves any that intersect reserved
2153f126809SYuquan Wang  * ranges to numa_reserved_meminfo. However, when that information is known
2163f126809SYuquan Wang  * ahead of time, we use numa_add_reserved_memblk() to add the numa_memblk
2173f126809SYuquan Wang  * to numa_reserved_meminfo directly.
2183f126809SYuquan Wang  *
2193f126809SYuquan Wang  * RETURNS:
2203f126809SYuquan Wang  * 0 on success, -errno on failure.
2213f126809SYuquan Wang  */
numa_add_reserved_memblk(int nid,u64 start,u64 end)2223f126809SYuquan Wang int __init numa_add_reserved_memblk(int nid, u64 start, u64 end)
2233f126809SYuquan Wang {
2243f126809SYuquan Wang 	return numa_add_memblk_to(nid, start, end, &numa_reserved_meminfo);
2253f126809SYuquan Wang }
2263f126809SYuquan Wang 
2273f126809SYuquan Wang /**
22887482708SMike Rapoport (Microsoft)  * numa_cleanup_meminfo - Cleanup a numa_meminfo
22987482708SMike Rapoport (Microsoft)  * @mi: numa_meminfo to clean up
23087482708SMike Rapoport (Microsoft)  *
23187482708SMike Rapoport (Microsoft)  * Sanitize @mi by merging and removing unnecessary memblks.  Also check for
23287482708SMike Rapoport (Microsoft)  * conflicts and clear unused memblks.
23387482708SMike Rapoport (Microsoft)  *
23487482708SMike Rapoport (Microsoft)  * RETURNS:
23587482708SMike Rapoport (Microsoft)  * 0 on success, -errno on failure.
23687482708SMike Rapoport (Microsoft)  */
numa_cleanup_meminfo(struct numa_meminfo * mi)23787482708SMike Rapoport (Microsoft) int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
23887482708SMike Rapoport (Microsoft) {
239f7feea28SMike Rapoport (Microsoft) 	const u64 low = memblock_start_of_DRAM();
240f7feea28SMike Rapoport (Microsoft) 	const u64 high = memblock_end_of_DRAM();
24187482708SMike Rapoport (Microsoft) 	int i, j, k;
24287482708SMike Rapoport (Microsoft) 
24387482708SMike Rapoport (Microsoft) 	/* first, trim all entries */
24487482708SMike Rapoport (Microsoft) 	for (i = 0; i < mi->nr_blks; i++) {
24587482708SMike Rapoport (Microsoft) 		struct numa_memblk *bi = &mi->blk[i];
24687482708SMike Rapoport (Microsoft) 
24787482708SMike Rapoport (Microsoft) 		/* move / save reserved memory ranges */
24887482708SMike Rapoport (Microsoft) 		if (!memblock_overlaps_region(&memblock.memory,
24987482708SMike Rapoport (Microsoft) 					bi->start, bi->end - bi->start)) {
25087482708SMike Rapoport (Microsoft) 			numa_move_tail_memblk(&numa_reserved_meminfo, i--, mi);
25187482708SMike Rapoport (Microsoft) 			continue;
25287482708SMike Rapoport (Microsoft) 		}
25387482708SMike Rapoport (Microsoft) 
25487482708SMike Rapoport (Microsoft) 		/* make sure all non-reserved blocks are inside the limits */
25587482708SMike Rapoport (Microsoft) 		bi->start = max(bi->start, low);
25687482708SMike Rapoport (Microsoft) 
25787482708SMike Rapoport (Microsoft) 		/* preserve info for non-RAM areas above 'max_pfn': */
25887482708SMike Rapoport (Microsoft) 		if (bi->end > high) {
25987482708SMike Rapoport (Microsoft) 			numa_add_memblk_to(bi->nid, high, bi->end,
26087482708SMike Rapoport (Microsoft) 					   &numa_reserved_meminfo);
26187482708SMike Rapoport (Microsoft) 			bi->end = high;
26287482708SMike Rapoport (Microsoft) 		}
26387482708SMike Rapoport (Microsoft) 
26487482708SMike Rapoport (Microsoft) 		/* and there's no empty block */
26587482708SMike Rapoport (Microsoft) 		if (bi->start >= bi->end)
26687482708SMike Rapoport (Microsoft) 			numa_remove_memblk_from(i--, mi);
26787482708SMike Rapoport (Microsoft) 	}
26887482708SMike Rapoport (Microsoft) 
26987482708SMike Rapoport (Microsoft) 	/* merge neighboring / overlapping entries */
27087482708SMike Rapoport (Microsoft) 	for (i = 0; i < mi->nr_blks; i++) {
27187482708SMike Rapoport (Microsoft) 		struct numa_memblk *bi = &mi->blk[i];
27287482708SMike Rapoport (Microsoft) 
27387482708SMike Rapoport (Microsoft) 		for (j = i + 1; j < mi->nr_blks; j++) {
27487482708SMike Rapoport (Microsoft) 			struct numa_memblk *bj = &mi->blk[j];
27587482708SMike Rapoport (Microsoft) 			u64 start, end;
27687482708SMike Rapoport (Microsoft) 
27787482708SMike Rapoport (Microsoft) 			/*
27887482708SMike Rapoport (Microsoft) 			 * See whether there are overlapping blocks.  Whine
27987482708SMike Rapoport (Microsoft) 			 * about but allow overlaps of the same nid.  They
28087482708SMike Rapoport (Microsoft) 			 * will be merged below.
28187482708SMike Rapoport (Microsoft) 			 */
28287482708SMike Rapoport (Microsoft) 			if (bi->end > bj->start && bi->start < bj->end) {
28387482708SMike Rapoport (Microsoft) 				if (bi->nid != bj->nid) {
28487482708SMike Rapoport (Microsoft) 					pr_err("node %d [mem %#010Lx-%#010Lx] overlaps with node %d [mem %#010Lx-%#010Lx]\n",
28587482708SMike Rapoport (Microsoft) 					       bi->nid, bi->start, bi->end - 1,
28687482708SMike Rapoport (Microsoft) 					       bj->nid, bj->start, bj->end - 1);
28787482708SMike Rapoport (Microsoft) 					return -EINVAL;
28887482708SMike Rapoport (Microsoft) 				}
28987482708SMike Rapoport (Microsoft) 				pr_warn("Warning: node %d [mem %#010Lx-%#010Lx] overlaps with itself [mem %#010Lx-%#010Lx]\n",
29087482708SMike Rapoport (Microsoft) 					bi->nid, bi->start, bi->end - 1,
29187482708SMike Rapoport (Microsoft) 					bj->start, bj->end - 1);
29287482708SMike Rapoport (Microsoft) 			}
29387482708SMike Rapoport (Microsoft) 
29487482708SMike Rapoport (Microsoft) 			/*
29587482708SMike Rapoport (Microsoft) 			 * Join together blocks on the same node, holes
29687482708SMike Rapoport (Microsoft) 			 * between which don't overlap with memory on other
29787482708SMike Rapoport (Microsoft) 			 * nodes.
29887482708SMike Rapoport (Microsoft) 			 */
29987482708SMike Rapoport (Microsoft) 			if (bi->nid != bj->nid)
30087482708SMike Rapoport (Microsoft) 				continue;
30187482708SMike Rapoport (Microsoft) 			start = min(bi->start, bj->start);
30287482708SMike Rapoport (Microsoft) 			end = max(bi->end, bj->end);
30387482708SMike Rapoport (Microsoft) 			for (k = 0; k < mi->nr_blks; k++) {
30487482708SMike Rapoport (Microsoft) 				struct numa_memblk *bk = &mi->blk[k];
30587482708SMike Rapoport (Microsoft) 
30687482708SMike Rapoport (Microsoft) 				if (bi->nid == bk->nid)
30787482708SMike Rapoport (Microsoft) 					continue;
30887482708SMike Rapoport (Microsoft) 				if (start < bk->end && end > bk->start)
30987482708SMike Rapoport (Microsoft) 					break;
31087482708SMike Rapoport (Microsoft) 			}
31187482708SMike Rapoport (Microsoft) 			if (k < mi->nr_blks)
31287482708SMike Rapoport (Microsoft) 				continue;
31387482708SMike Rapoport (Microsoft) 			pr_info("NUMA: Node %d [mem %#010Lx-%#010Lx] + [mem %#010Lx-%#010Lx] -> [mem %#010Lx-%#010Lx]\n",
31487482708SMike Rapoport (Microsoft) 			       bi->nid, bi->start, bi->end - 1, bj->start,
31587482708SMike Rapoport (Microsoft) 			       bj->end - 1, start, end - 1);
31687482708SMike Rapoport (Microsoft) 			bi->start = start;
31787482708SMike Rapoport (Microsoft) 			bi->end = end;
31887482708SMike Rapoport (Microsoft) 			numa_remove_memblk_from(j--, mi);
31987482708SMike Rapoport (Microsoft) 		}
32087482708SMike Rapoport (Microsoft) 	}
32187482708SMike Rapoport (Microsoft) 
32287482708SMike Rapoport (Microsoft) 	/* clear unused ones */
32387482708SMike Rapoport (Microsoft) 	for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) {
32487482708SMike Rapoport (Microsoft) 		mi->blk[i].start = mi->blk[i].end = 0;
32587482708SMike Rapoport (Microsoft) 		mi->blk[i].nid = NUMA_NO_NODE;
32687482708SMike Rapoport (Microsoft) 	}
32787482708SMike Rapoport (Microsoft) 
32887482708SMike Rapoport (Microsoft) 	return 0;
32987482708SMike Rapoport (Microsoft) }
33087482708SMike Rapoport (Microsoft) 
33187482708SMike Rapoport (Microsoft) /*
33287482708SMike Rapoport (Microsoft)  * Mark all currently memblock-reserved physical memory (which covers the
33387482708SMike Rapoport (Microsoft)  * kernel's own memory ranges) as hot-unswappable.
33487482708SMike Rapoport (Microsoft)  */
numa_clear_kernel_node_hotplug(void)33587482708SMike Rapoport (Microsoft) static void __init numa_clear_kernel_node_hotplug(void)
33687482708SMike Rapoport (Microsoft) {
33787482708SMike Rapoport (Microsoft) 	nodemask_t reserved_nodemask = NODE_MASK_NONE;
33887482708SMike Rapoport (Microsoft) 	struct memblock_region *mb_region;
33987482708SMike Rapoport (Microsoft) 	int i;
34087482708SMike Rapoport (Microsoft) 
34187482708SMike Rapoport (Microsoft) 	/*
34287482708SMike Rapoport (Microsoft) 	 * We have to do some preprocessing of memblock regions, to
34387482708SMike Rapoport (Microsoft) 	 * make them suitable for reservation.
34487482708SMike Rapoport (Microsoft) 	 *
34587482708SMike Rapoport (Microsoft) 	 * At this time, all memory regions reserved by memblock are
34687482708SMike Rapoport (Microsoft) 	 * used by the kernel, but those regions are not split up
34787482708SMike Rapoport (Microsoft) 	 * along node boundaries yet, and don't necessarily have their
34887482708SMike Rapoport (Microsoft) 	 * node ID set yet either.
34987482708SMike Rapoport (Microsoft) 	 *
35087482708SMike Rapoport (Microsoft) 	 * So iterate over all parsed memory blocks and use those ranges to
35187482708SMike Rapoport (Microsoft) 	 * set the nid in memblock.reserved.  This will split up the
35287482708SMike Rapoport (Microsoft) 	 * memblock regions along node boundaries and will set the node IDs
35387482708SMike Rapoport (Microsoft) 	 * as well.
35487482708SMike Rapoport (Microsoft) 	 */
35587482708SMike Rapoport (Microsoft) 	for (i = 0; i < numa_meminfo.nr_blks; i++) {
35687482708SMike Rapoport (Microsoft) 		struct numa_memblk *mb = numa_meminfo.blk + i;
35787482708SMike Rapoport (Microsoft) 		int ret;
35887482708SMike Rapoport (Microsoft) 
35987482708SMike Rapoport (Microsoft) 		ret = memblock_set_node(mb->start, mb->end - mb->start,
36087482708SMike Rapoport (Microsoft) 					&memblock.reserved, mb->nid);
36187482708SMike Rapoport (Microsoft) 		WARN_ON_ONCE(ret);
36287482708SMike Rapoport (Microsoft) 	}
36387482708SMike Rapoport (Microsoft) 
36487482708SMike Rapoport (Microsoft) 	/*
36587482708SMike Rapoport (Microsoft) 	 * Now go over all reserved memblock regions, to construct a
36687482708SMike Rapoport (Microsoft) 	 * node mask of all kernel reserved memory areas.
36787482708SMike Rapoport (Microsoft) 	 *
36887482708SMike Rapoport (Microsoft) 	 * [ Note, when booting with mem=nn[kMG] or in a kdump kernel,
36987482708SMike Rapoport (Microsoft) 	 *   numa_meminfo might not include all memblock.reserved
37087482708SMike Rapoport (Microsoft) 	 *   memory ranges, because quirks such as trim_snb_memory()
37187482708SMike Rapoport (Microsoft) 	 *   reserve specific pages for Sandy Bridge graphics. ]
37287482708SMike Rapoport (Microsoft) 	 */
37387482708SMike Rapoport (Microsoft) 	for_each_reserved_mem_region(mb_region) {
37487482708SMike Rapoport (Microsoft) 		int nid = memblock_get_region_node(mb_region);
37587482708SMike Rapoport (Microsoft) 
376d95fb348SNobuhiro Iwamatsu 		if (numa_valid_node(nid))
37787482708SMike Rapoport (Microsoft) 			node_set(nid, reserved_nodemask);
37887482708SMike Rapoport (Microsoft) 	}
37987482708SMike Rapoport (Microsoft) 
38087482708SMike Rapoport (Microsoft) 	/*
38187482708SMike Rapoport (Microsoft) 	 * Finally, clear the MEMBLOCK_HOTPLUG flag for all memory
38287482708SMike Rapoport (Microsoft) 	 * belonging to the reserved node mask.
38387482708SMike Rapoport (Microsoft) 	 *
38487482708SMike Rapoport (Microsoft) 	 * Note that this will include memory regions that reside
38587482708SMike Rapoport (Microsoft) 	 * on nodes that contain kernel memory - entire nodes
38687482708SMike Rapoport (Microsoft) 	 * become hot-unpluggable:
38787482708SMike Rapoport (Microsoft) 	 */
38887482708SMike Rapoport (Microsoft) 	for (i = 0; i < numa_meminfo.nr_blks; i++) {
38987482708SMike Rapoport (Microsoft) 		struct numa_memblk *mb = numa_meminfo.blk + i;
39087482708SMike Rapoport (Microsoft) 
39187482708SMike Rapoport (Microsoft) 		if (!node_isset(mb->nid, reserved_nodemask))
39287482708SMike Rapoport (Microsoft) 			continue;
39387482708SMike Rapoport (Microsoft) 
39487482708SMike Rapoport (Microsoft) 		memblock_clear_hotplug(mb->start, mb->end - mb->start);
39587482708SMike Rapoport (Microsoft) 	}
39687482708SMike Rapoport (Microsoft) }
39787482708SMike Rapoport (Microsoft) 
numa_register_meminfo(struct numa_meminfo * mi)398317ef459SMike Rapoport (Microsoft) static int __init numa_register_meminfo(struct numa_meminfo *mi)
39987482708SMike Rapoport (Microsoft) {
40087482708SMike Rapoport (Microsoft) 	int i;
40187482708SMike Rapoport (Microsoft) 
40287482708SMike Rapoport (Microsoft) 	/* Account for nodes with cpus and no memory */
40387482708SMike Rapoport (Microsoft) 	node_possible_map = numa_nodes_parsed;
40487482708SMike Rapoport (Microsoft) 	numa_nodemask_from_meminfo(&node_possible_map, mi);
40587482708SMike Rapoport (Microsoft) 	if (WARN_ON(nodes_empty(node_possible_map)))
40687482708SMike Rapoport (Microsoft) 		return -EINVAL;
40787482708SMike Rapoport (Microsoft) 
40887482708SMike Rapoport (Microsoft) 	for (i = 0; i < mi->nr_blks; i++) {
40987482708SMike Rapoport (Microsoft) 		struct numa_memblk *mb = &mi->blk[i];
41087482708SMike Rapoport (Microsoft) 
41187482708SMike Rapoport (Microsoft) 		memblock_set_node(mb->start, mb->end - mb->start,
41287482708SMike Rapoport (Microsoft) 				  &memblock.memory, mb->nid);
41387482708SMike Rapoport (Microsoft) 	}
41487482708SMike Rapoport (Microsoft) 
41587482708SMike Rapoport (Microsoft) 	/*
41687482708SMike Rapoport (Microsoft) 	 * At very early time, the kernel have to use some memory such as
41787482708SMike Rapoport (Microsoft) 	 * loading the kernel image. We cannot prevent this anyway. So any
41887482708SMike Rapoport (Microsoft) 	 * node the kernel resides in should be un-hotpluggable.
41987482708SMike Rapoport (Microsoft) 	 *
42087482708SMike Rapoport (Microsoft) 	 * And when we come here, alloc node data won't fail.
42187482708SMike Rapoport (Microsoft) 	 */
42287482708SMike Rapoport (Microsoft) 	numa_clear_kernel_node_hotplug();
42387482708SMike Rapoport (Microsoft) 
42487482708SMike Rapoport (Microsoft) 	/*
42587482708SMike Rapoport (Microsoft) 	 * If sections array is gonna be used for pfn -> nid mapping, check
42687482708SMike Rapoport (Microsoft) 	 * whether its granularity is fine enough.
42787482708SMike Rapoport (Microsoft) 	 */
42887482708SMike Rapoport (Microsoft) 	if (IS_ENABLED(NODE_NOT_IN_PAGE_FLAGS)) {
42987482708SMike Rapoport (Microsoft) 		unsigned long pfn_align = node_map_pfn_alignment();
43087482708SMike Rapoport (Microsoft) 
43187482708SMike Rapoport (Microsoft) 		if (pfn_align && pfn_align < PAGES_PER_SECTION) {
4324647c4deSPratyush Brahma 			unsigned long node_align_mb = PFN_PHYS(pfn_align) / SZ_1M;
43376750765SMike Rapoport (Microsoft) 
4344647c4deSPratyush Brahma 			unsigned long sect_align_mb = PFN_PHYS(PAGES_PER_SECTION) / SZ_1M;
43576750765SMike Rapoport (Microsoft) 
43676750765SMike Rapoport (Microsoft) 			pr_warn("Node alignment %luMB < min %luMB, rejecting NUMA config\n",
43776750765SMike Rapoport (Microsoft) 				node_align_mb, sect_align_mb);
43887482708SMike Rapoport (Microsoft) 			return -EINVAL;
43987482708SMike Rapoport (Microsoft) 		}
44087482708SMike Rapoport (Microsoft) 	}
44187482708SMike Rapoport (Microsoft) 
44287482708SMike Rapoport (Microsoft) 	return 0;
44387482708SMike Rapoport (Microsoft) }
44487482708SMike Rapoport (Microsoft) 
numa_memblks_init(int (* init_func)(void),bool memblock_force_top_down)445692d73d2SMike Rapoport (Microsoft) int __init numa_memblks_init(int (*init_func)(void),
446692d73d2SMike Rapoport (Microsoft) 			     bool memblock_force_top_down)
447692d73d2SMike Rapoport (Microsoft) {
44876750765SMike Rapoport (Microsoft) 	phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
449692d73d2SMike Rapoport (Microsoft) 	int ret;
450692d73d2SMike Rapoport (Microsoft) 
451692d73d2SMike Rapoport (Microsoft) 	nodes_clear(numa_nodes_parsed);
452692d73d2SMike Rapoport (Microsoft) 	nodes_clear(node_possible_map);
453692d73d2SMike Rapoport (Microsoft) 	nodes_clear(node_online_map);
454692d73d2SMike Rapoport (Microsoft) 	memset(&numa_meminfo, 0, sizeof(numa_meminfo));
45576750765SMike Rapoport (Microsoft) 	WARN_ON(memblock_set_node(0, max_addr, &memblock.memory, NUMA_NO_NODE));
45676750765SMike Rapoport (Microsoft) 	WARN_ON(memblock_set_node(0, max_addr, &memblock.reserved,
457692d73d2SMike Rapoport (Microsoft) 				  NUMA_NO_NODE));
458692d73d2SMike Rapoport (Microsoft) 	/* In case that parsing SRAT failed. */
45976750765SMike Rapoport (Microsoft) 	WARN_ON(memblock_clear_hotplug(0, max_addr));
460692d73d2SMike Rapoport (Microsoft) 	numa_reset_distance();
461692d73d2SMike Rapoport (Microsoft) 
462692d73d2SMike Rapoport (Microsoft) 	ret = init_func();
463692d73d2SMike Rapoport (Microsoft) 	if (ret < 0)
464692d73d2SMike Rapoport (Microsoft) 		return ret;
465692d73d2SMike Rapoport (Microsoft) 
466692d73d2SMike Rapoport (Microsoft) 	/*
467692d73d2SMike Rapoport (Microsoft) 	 * We reset memblock back to the top-down direction
468692d73d2SMike Rapoport (Microsoft) 	 * here because if we configured ACPI_NUMA, we have
469692d73d2SMike Rapoport (Microsoft) 	 * parsed SRAT in init_func(). It is ok to have the
47062451ae3SKevin Lourenco 	 * reset here even if we didn't configure ACPI_NUMA
471692d73d2SMike Rapoport (Microsoft) 	 * or acpi numa init fails and fallbacks to dummy
472692d73d2SMike Rapoport (Microsoft) 	 * numa init.
473692d73d2SMike Rapoport (Microsoft) 	 */
474692d73d2SMike Rapoport (Microsoft) 	if (memblock_force_top_down)
475692d73d2SMike Rapoport (Microsoft) 		memblock_set_bottom_up(false);
476692d73d2SMike Rapoport (Microsoft) 
477692d73d2SMike Rapoport (Microsoft) 	ret = numa_cleanup_meminfo(&numa_meminfo);
478692d73d2SMike Rapoport (Microsoft) 	if (ret < 0)
479692d73d2SMike Rapoport (Microsoft) 		return ret;
480692d73d2SMike Rapoport (Microsoft) 
481692d73d2SMike Rapoport (Microsoft) 	numa_emulation(&numa_meminfo, numa_distance_cnt);
482692d73d2SMike Rapoport (Microsoft) 
483692d73d2SMike Rapoport (Microsoft) 	return numa_register_meminfo(&numa_meminfo);
484692d73d2SMike Rapoport (Microsoft) }
485692d73d2SMike Rapoport (Microsoft) 
cmp_memblk(const void * a,const void * b)48687482708SMike Rapoport (Microsoft) static int __init cmp_memblk(const void *a, const void *b)
48787482708SMike Rapoport (Microsoft) {
48887482708SMike Rapoport (Microsoft) 	const struct numa_memblk *ma = *(const struct numa_memblk **)a;
48987482708SMike Rapoport (Microsoft) 	const struct numa_memblk *mb = *(const struct numa_memblk **)b;
49087482708SMike Rapoport (Microsoft) 
49187482708SMike Rapoport (Microsoft) 	return (ma->start > mb->start) - (ma->start < mb->start);
49287482708SMike Rapoport (Microsoft) }
49387482708SMike Rapoport (Microsoft) 
49487482708SMike Rapoport (Microsoft) static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
49587482708SMike Rapoport (Microsoft) 
49687482708SMike Rapoport (Microsoft) /**
49787482708SMike Rapoport (Microsoft)  * numa_fill_memblks - Fill gaps in numa_meminfo memblks
49887482708SMike Rapoport (Microsoft)  * @start: address to begin fill
49987482708SMike Rapoport (Microsoft)  * @end: address to end fill
50087482708SMike Rapoport (Microsoft)  *
50187482708SMike Rapoport (Microsoft)  * Find and extend numa_meminfo memblks to cover the physical
50287482708SMike Rapoport (Microsoft)  * address range @start-@end
50387482708SMike Rapoport (Microsoft)  *
50487482708SMike Rapoport (Microsoft)  * RETURNS:
50587482708SMike Rapoport (Microsoft)  * 0		  : Success
50687482708SMike Rapoport (Microsoft)  * NUMA_NO_MEMBLK : No memblks exist in address range @start-@end
50787482708SMike Rapoport (Microsoft)  */
50887482708SMike Rapoport (Microsoft) 
numa_fill_memblks(u64 start,u64 end)50987482708SMike Rapoport (Microsoft) int __init numa_fill_memblks(u64 start, u64 end)
51087482708SMike Rapoport (Microsoft) {
51187482708SMike Rapoport (Microsoft) 	struct numa_memblk **blk = &numa_memblk_list[0];
51287482708SMike Rapoport (Microsoft) 	struct numa_meminfo *mi = &numa_meminfo;
51387482708SMike Rapoport (Microsoft) 	int count = 0;
51487482708SMike Rapoport (Microsoft) 	u64 prev_end;
51587482708SMike Rapoport (Microsoft) 
51687482708SMike Rapoport (Microsoft) 	/*
51787482708SMike Rapoport (Microsoft) 	 * Create a list of pointers to numa_meminfo memblks that
51887482708SMike Rapoport (Microsoft) 	 * overlap start, end. The list is used to make in-place
51987482708SMike Rapoport (Microsoft) 	 * changes that fill out the numa_meminfo memblks.
52087482708SMike Rapoport (Microsoft) 	 */
52187482708SMike Rapoport (Microsoft) 	for (int i = 0; i < mi->nr_blks; i++) {
52287482708SMike Rapoport (Microsoft) 		struct numa_memblk *bi = &mi->blk[i];
52387482708SMike Rapoport (Microsoft) 
52487482708SMike Rapoport (Microsoft) 		if (memblock_addrs_overlap(start, end - start, bi->start,
52587482708SMike Rapoport (Microsoft) 					   bi->end - bi->start)) {
52687482708SMike Rapoport (Microsoft) 			blk[count] = &mi->blk[i];
52787482708SMike Rapoport (Microsoft) 			count++;
52887482708SMike Rapoport (Microsoft) 		}
52987482708SMike Rapoport (Microsoft) 	}
53087482708SMike Rapoport (Microsoft) 	if (!count)
53187482708SMike Rapoport (Microsoft) 		return NUMA_NO_MEMBLK;
53287482708SMike Rapoport (Microsoft) 
53387482708SMike Rapoport (Microsoft) 	/* Sort the list of pointers in memblk->start order */
53487482708SMike Rapoport (Microsoft) 	sort(&blk[0], count, sizeof(blk[0]), cmp_memblk, NULL);
53587482708SMike Rapoport (Microsoft) 
53687482708SMike Rapoport (Microsoft) 	/* Make sure the first/last memblks include start/end */
53787482708SMike Rapoport (Microsoft) 	blk[0]->start = min(blk[0]->start, start);
53887482708SMike Rapoport (Microsoft) 	blk[count - 1]->end = max(blk[count - 1]->end, end);
53987482708SMike Rapoport (Microsoft) 
54087482708SMike Rapoport (Microsoft) 	/*
54187482708SMike Rapoport (Microsoft) 	 * Fill any gaps by tracking the previous memblks
54287482708SMike Rapoport (Microsoft) 	 * end address and backfilling to it if needed.
54387482708SMike Rapoport (Microsoft) 	 */
54487482708SMike Rapoport (Microsoft) 	prev_end = blk[0]->end;
54587482708SMike Rapoport (Microsoft) 	for (int i = 1; i < count; i++) {
54687482708SMike Rapoport (Microsoft) 		struct numa_memblk *curr = blk[i];
54787482708SMike Rapoport (Microsoft) 
54887482708SMike Rapoport (Microsoft) 		if (prev_end >= curr->start) {
54987482708SMike Rapoport (Microsoft) 			if (prev_end < curr->end)
55087482708SMike Rapoport (Microsoft) 				prev_end = curr->end;
55187482708SMike Rapoport (Microsoft) 		} else {
55287482708SMike Rapoport (Microsoft) 			curr->start = prev_end;
55387482708SMike Rapoport (Microsoft) 			prev_end = curr->end;
55487482708SMike Rapoport (Microsoft) 		}
55587482708SMike Rapoport (Microsoft) 	}
55687482708SMike Rapoport (Microsoft) 	return 0;
55787482708SMike Rapoport (Microsoft) }
5581b5695b0SMike Rapoport (Microsoft) 
5591b5695b0SMike Rapoport (Microsoft) #ifdef CONFIG_NUMA_KEEP_MEMINFO
meminfo_to_nid(struct numa_meminfo * mi,u64 start)5601b5695b0SMike Rapoport (Microsoft) static int meminfo_to_nid(struct numa_meminfo *mi, u64 start)
5611b5695b0SMike Rapoport (Microsoft) {
5621b5695b0SMike Rapoport (Microsoft) 	int i;
5631b5695b0SMike Rapoport (Microsoft) 
5641b5695b0SMike Rapoport (Microsoft) 	for (i = 0; i < mi->nr_blks; i++)
5651b5695b0SMike Rapoport (Microsoft) 		if (mi->blk[i].start <= start && mi->blk[i].end > start)
5661b5695b0SMike Rapoport (Microsoft) 			return mi->blk[i].nid;
5671b5695b0SMike Rapoport (Microsoft) 	return NUMA_NO_NODE;
5681b5695b0SMike Rapoport (Microsoft) }
5691b5695b0SMike Rapoport (Microsoft) 
phys_to_target_node(u64 start)5701b5695b0SMike Rapoport (Microsoft) int phys_to_target_node(u64 start)
5711b5695b0SMike Rapoport (Microsoft) {
5721b5695b0SMike Rapoport (Microsoft) 	int nid = meminfo_to_nid(&numa_meminfo, start);
573*f043a93fSCui Chao 	int reserved_nid = meminfo_to_nid(&numa_reserved_meminfo, start);
5741b5695b0SMike Rapoport (Microsoft) 
5751b5695b0SMike Rapoport (Microsoft) 	/*
576*f043a93fSCui Chao 	 * Prefer online nodes unless the address is also described
577*f043a93fSCui Chao 	 * by reserved ranges, in which case use the reserved nid.
5781b5695b0SMike Rapoport (Microsoft) 	 */
579*f043a93fSCui Chao 	if (nid != NUMA_NO_NODE && reserved_nid == NUMA_NO_NODE)
5801b5695b0SMike Rapoport (Microsoft) 		return nid;
5811b5695b0SMike Rapoport (Microsoft) 
582*f043a93fSCui Chao 	return reserved_nid;
5831b5695b0SMike Rapoport (Microsoft) }
5841b5695b0SMike Rapoport (Microsoft) EXPORT_SYMBOL_GPL(phys_to_target_node);
5851b5695b0SMike Rapoport (Microsoft) 
memory_add_physaddr_to_nid(u64 start)5861b5695b0SMike Rapoport (Microsoft) int memory_add_physaddr_to_nid(u64 start)
5871b5695b0SMike Rapoport (Microsoft) {
5881b5695b0SMike Rapoport (Microsoft) 	int nid = meminfo_to_nid(&numa_meminfo, start);
5891b5695b0SMike Rapoport (Microsoft) 
5901b5695b0SMike Rapoport (Microsoft) 	if (nid == NUMA_NO_NODE)
5911b5695b0SMike Rapoport (Microsoft) 		nid = numa_meminfo.blk[0].nid;
5921b5695b0SMike Rapoport (Microsoft) 	return nid;
5931b5695b0SMike Rapoport (Microsoft) }
5941b5695b0SMike Rapoport (Microsoft) EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
5951b5695b0SMike Rapoport (Microsoft) 
5961b5695b0SMike Rapoport (Microsoft) #endif /* CONFIG_NUMA_KEEP_MEMINFO */
597