1 /*
2  * ACPI 3.0 based NUMA setup
3  * Copyright 2004 Andi Kleen, SuSE Labs.
4  *
5  * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
6  *
7  * Called from acpi_numa_init while reading the SRAT and SLIT tables.
8  * Assumes all memory regions belonging to a single proximity domain
9  * are in one chunk. Holes between them will be included in the node.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/acpi.h>
14 #include <linux/mmzone.h>
15 #include <linux/bitmap.h>
16 #include <linux/module.h>
17 #include <linux/topology.h>
18 #include <linux/bootmem.h>
19 #include <linux/memblock.h>
20 #include <linux/mm.h>
21 #include <asm/proto.h>
22 #include <asm/numa.h>
23 #include <asm/e820.h>
24 #include <asm/apic.h>
25 #include <asm/uv/uv.h>
26 
27 int acpi_numa __initdata;
28 
29 static struct bootnode nodes_add[MAX_NUMNODES];
30 
setup_node(int pxm)31 static __init int setup_node(int pxm)
32 {
33 	return acpi_map_pxm_to_node(pxm);
34 }
35 
bad_srat(void)36 static __init void bad_srat(void)
37 {
38 	printk(KERN_ERR "SRAT: SRAT not used.\n");
39 	acpi_numa = -1;
40 	memset(nodes_add, 0, sizeof(nodes_add));
41 }
42 
srat_disabled(void)43 static __init inline int srat_disabled(void)
44 {
45 	return acpi_numa < 0;
46 }
47 
48 /* Callback for SLIT parsing */
acpi_numa_slit_init(struct acpi_table_slit * slit)49 void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
50 {
51 	int i, j;
52 
53 	for (i = 0; i < slit->locality_count; i++)
54 		for (j = 0; j < slit->locality_count; j++)
55 			numa_set_distance(pxm_to_node(i), pxm_to_node(j),
56 				slit->entry[slit->locality_count * i + j]);
57 }
58 
59 /* Callback for Proximity Domain -> x2APIC mapping */
60 void __init
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity * pa)61 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
62 {
63 	int pxm, node;
64 	int apic_id;
65 
66 	if (srat_disabled())
67 		return;
68 	if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
69 		bad_srat();
70 		return;
71 	}
72 	if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
73 		return;
74 	pxm = pa->proximity_domain;
75 	node = setup_node(pxm);
76 	if (node < 0) {
77 		printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
78 		bad_srat();
79 		return;
80 	}
81 
82 	apic_id = pa->apic_id;
83 	if (apic_id >= MAX_LOCAL_APIC) {
84 		printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
85 		return;
86 	}
87 	set_apicid_to_node(apic_id, node);
88 	node_set(node, numa_nodes_parsed);
89 	acpi_numa = 1;
90 	printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
91 	       pxm, apic_id, node);
92 }
93 
94 /* Callback for Proximity Domain -> LAPIC mapping */
95 void __init
acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity * pa)96 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
97 {
98 	int pxm, node;
99 	int apic_id;
100 
101 	if (srat_disabled())
102 		return;
103 	if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
104 		bad_srat();
105 		return;
106 	}
107 	if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
108 		return;
109 	pxm = pa->proximity_domain_lo;
110 	node = setup_node(pxm);
111 	if (node < 0) {
112 		printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
113 		bad_srat();
114 		return;
115 	}
116 
117 	if (get_uv_system_type() >= UV_X2APIC)
118 		apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
119 	else
120 		apic_id = pa->apic_id;
121 
122 	if (apic_id >= MAX_LOCAL_APIC) {
123 		printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
124 		return;
125 	}
126 
127 	set_apicid_to_node(apic_id, node);
128 	node_set(node, numa_nodes_parsed);
129 	acpi_numa = 1;
130 	printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
131 	       pxm, apic_id, node);
132 }
133 
134 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
save_add_info(void)135 static inline int save_add_info(void) {return 1;}
136 #else
save_add_info(void)137 static inline int save_add_info(void) {return 0;}
138 #endif
139 /*
140  * Update nodes_add[]
141  * This code supports one contiguous hot add area per node
142  */
143 static void __init
update_nodes_add(int node,unsigned long start,unsigned long end)144 update_nodes_add(int node, unsigned long start, unsigned long end)
145 {
146 	unsigned long s_pfn = start >> PAGE_SHIFT;
147 	unsigned long e_pfn = end >> PAGE_SHIFT;
148 	int changed = 0;
149 	struct bootnode *nd = &nodes_add[node];
150 
151 	/* I had some trouble with strange memory hotadd regions breaking
152 	   the boot. Be very strict here and reject anything unexpected.
153 	   If you want working memory hotadd write correct SRATs.
154 
155 	   The node size check is a basic sanity check to guard against
156 	   mistakes */
157 	if ((signed long)(end - start) < NODE_MIN_SIZE) {
158 		printk(KERN_ERR "SRAT: Hotplug area too small\n");
159 		return;
160 	}
161 
162 	/* This check might be a bit too strict, but I'm keeping it for now. */
163 	if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
164 		printk(KERN_ERR
165 			"SRAT: Hotplug area %lu -> %lu has existing memory\n",
166 			s_pfn, e_pfn);
167 		return;
168 	}
169 
170 	/* Looks good */
171 
172 	if (nd->start == nd->end) {
173 		nd->start = start;
174 		nd->end = end;
175 		changed = 1;
176 	} else {
177 		if (nd->start == end) {
178 			nd->start = start;
179 			changed = 1;
180 		}
181 		if (nd->end == start) {
182 			nd->end = end;
183 			changed = 1;
184 		}
185 		if (!changed)
186 			printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
187 	}
188 
189 	if (changed) {
190 		node_set(node, numa_nodes_parsed);
191 		printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
192 				 nd->start, nd->end);
193 	}
194 }
195 
196 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
197 void __init
acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity * ma)198 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
199 {
200 	unsigned long start, end;
201 	int node, pxm;
202 
203 	if (srat_disabled())
204 		return;
205 	if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
206 		bad_srat();
207 		return;
208 	}
209 	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
210 		return;
211 
212 	if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
213 		return;
214 	start = ma->base_address;
215 	end = start + ma->length;
216 	pxm = ma->proximity_domain;
217 	node = setup_node(pxm);
218 	if (node < 0) {
219 		printk(KERN_ERR "SRAT: Too many proximity domains.\n");
220 		bad_srat();
221 		return;
222 	}
223 
224 	if (numa_add_memblk(node, start, end) < 0) {
225 		bad_srat();
226 		return;
227 	}
228 
229 	printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
230 	       start, end);
231 
232 	if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
233 		update_nodes_add(node, start, end);
234 }
235 
acpi_numa_arch_fixup(void)236 void __init acpi_numa_arch_fixup(void) {}
237 
x86_acpi_numa_init(void)238 int __init x86_acpi_numa_init(void)
239 {
240 	int ret;
241 
242 	ret = acpi_numa_init();
243 	if (ret < 0)
244 		return ret;
245 	return srat_disabled() ? -EINVAL : 0;
246 }
247 
248 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
memory_add_physaddr_to_nid(u64 start)249 int memory_add_physaddr_to_nid(u64 start)
250 {
251 	int i, ret = 0;
252 
253 	for_each_node(i)
254 		if (nodes_add[i].start <= start && nodes_add[i].end > start)
255 			ret = i;
256 
257 	return ret;
258 }
259 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
260 #endif
261