18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file contains NUMA specific variables and functions which can
78c2ecf20Sopenharmony_ci * be split away from DISCONTIGMEM and are used on NUMA machines with
88c2ecf20Sopenharmony_ci * contiguous memory.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *                         2002/08/07 Erich Focht <efocht@ess.nec.de>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/cpu.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/mm.h>
168c2ecf20Sopenharmony_ci#include <linux/node.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/memblock.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <asm/mmzone.h>
218c2ecf20Sopenharmony_ci#include <asm/numa.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * The following structures are usually initialized by ACPI or
268c2ecf20Sopenharmony_ci * similar mechanisms and describe the NUMA characteristics of the machine.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ciint num_node_memblks;
298c2ecf20Sopenharmony_cistruct node_memblk_s node_memblk[NR_NODE_MEMBLKS];
308c2ecf20Sopenharmony_cistruct node_cpuid_s node_cpuid[NR_CPUS] =
318c2ecf20Sopenharmony_ci	{ [0 ... NR_CPUS-1] = { .phys_id = 0, .nid = NUMA_NO_NODE } };
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * This is a matrix with "distances" between nodes, they should be
358c2ecf20Sopenharmony_ci * proportional to the memory access latency ratios.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ciu8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciint __node_distance(int from, int to)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return slit_distance(from, to);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__node_distance);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Identify which cnode a physical address resides on */
468c2ecf20Sopenharmony_ciint
478c2ecf20Sopenharmony_cipaddr_to_nid(unsigned long paddr)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int	i;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (i = 0; i < num_node_memblks; i++)
528c2ecf20Sopenharmony_ci		if (paddr >= node_memblk[i].start_paddr &&
538c2ecf20Sopenharmony_ci		    paddr < node_memblk[i].start_paddr + node_memblk[i].size)
548c2ecf20Sopenharmony_ci			break;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(paddr_to_nid);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * Because of holes evaluate on section limits.
638c2ecf20Sopenharmony_ci * If the section of memory exists, then return the node where the section
648c2ecf20Sopenharmony_ci * resides.  Otherwise return node 0 as the default.  This is used by
658c2ecf20Sopenharmony_ci * SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where
668c2ecf20Sopenharmony_ci * the section resides.
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_ciint __meminit __early_pfn_to_nid(unsigned long pfn,
698c2ecf20Sopenharmony_ci					struct mminit_pfnnid_cache *state)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (section >= state->last_start && section < state->last_end)
748c2ecf20Sopenharmony_ci		return state->last_nid;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	for (i = 0; i < num_node_memblks; i++) {
778c2ecf20Sopenharmony_ci		ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT;
788c2ecf20Sopenharmony_ci		esec = (node_memblk[i].start_paddr + node_memblk[i].size +
798c2ecf20Sopenharmony_ci			((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT;
808c2ecf20Sopenharmony_ci		if (section >= ssec && section < esec) {
818c2ecf20Sopenharmony_ci			state->last_start = ssec;
828c2ecf20Sopenharmony_ci			state->last_end = esec;
838c2ecf20Sopenharmony_ci			state->last_nid = node_memblk[i].nid;
848c2ecf20Sopenharmony_ci			return node_memblk[i].nid;
858c2ecf20Sopenharmony_ci		}
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return -1;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_civoid numa_clear_node(int cpu)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	unmap_cpu_from_node(cpu, NUMA_NO_NODE);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#ifdef CONFIG_MEMORY_HOTPLUG
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci *  SRAT information is stored in node_memblk[], then we can use SRAT
998c2ecf20Sopenharmony_ci *  information at memory-hot-add if necessary.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ciint memory_add_physaddr_to_nid(u64 addr)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	int nid = paddr_to_nid(addr);
1058c2ecf20Sopenharmony_ci	if (nid < 0)
1068c2ecf20Sopenharmony_ci		return 0;
1078c2ecf20Sopenharmony_ci	return nid;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memory_add_physaddr_to_nid);
1108c2ecf20Sopenharmony_ci#endif
1118c2ecf20Sopenharmony_ci#endif
112