/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5* This file contains NUMA specific variables and functions which can6* be split away from DISCONTIGMEM and are used on NUMA machines with7* contiguous memory.8*9* 2002/08/07 Erich Focht <[email protected]>10*/1112#include <linux/cpu.h>13#include <linux/kernel.h>14#include <linux/mm.h>15#include <linux/node.h>16#include <linux/init.h>17#include <linux/bootmem.h>18#include <linux/module.h>19#include <asm/mmzone.h>20#include <asm/numa.h>212223/*24* The following structures are usually initialized by ACPI or25* similar mechanisms and describe the NUMA characteristics of the machine.26*/27int num_node_memblks;28struct node_memblk_s node_memblk[NR_NODE_MEMBLKS];29struct node_cpuid_s node_cpuid[NR_CPUS] =30{ [0 ... NR_CPUS-1] = { .phys_id = 0, .nid = NUMA_NO_NODE } };3132/*33* This is a matrix with "distances" between nodes, they should be34* proportional to the memory access latency ratios.35*/36u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];3738/* Identify which cnode a physical address resides on */39int40paddr_to_nid(unsigned long paddr)41{42int i;4344for (i = 0; i < num_node_memblks; i++)45if (paddr >= node_memblk[i].start_paddr &&46paddr < node_memblk[i].start_paddr + node_memblk[i].size)47break;4849return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);50}5152#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)53/*54* Because of holes evaluate on section limits.55* If the section of memory exists, then return the node where the section56* resides. Otherwise return node 0 as the default. This is used by57* SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where58* the section resides.59*/60int __meminit __early_pfn_to_nid(unsigned long pfn)61{62int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec;6364for (i = 0; i < num_node_memblks; i++) {65ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT;66esec = (node_memblk[i].start_paddr + node_memblk[i].size +67((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT;68if (section >= ssec && section < esec)69return node_memblk[i].nid;70}7172return -1;73}7475#ifdef CONFIG_MEMORY_HOTPLUG76/*77* SRAT information is stored in node_memblk[], then we can use SRAT78* information at memory-hot-add if necessary.79*/8081int memory_add_physaddr_to_nid(u64 addr)82{83int nid = paddr_to_nid(addr);84if (nid < 0)85return 0;86return nid;87}8889EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);90#endif91#endif929394