xref: /openbmc/linux/drivers/acpi/numa/srat.c (revision 59b4412f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  acpi_numa.c - ACPI NUMA support
4  *
5  *  Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
6  */
7 
8 #define pr_fmt(fmt) "ACPI: " fmt
9 
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/errno.h>
15 #include <linux/acpi.h>
16 #include <linux/memblock.h>
17 #include <linux/numa.h>
18 #include <linux/nodemask.h>
19 #include <linux/topology.h>
20 
21 static nodemask_t nodes_found_map = NODE_MASK_NONE;
22 
23 /* maps to convert between proximity domain and logical node ID */
24 static int pxm_to_node_map[MAX_PXM_DOMAINS]
25 			= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
26 static int node_to_pxm_map[MAX_NUMNODES]
27 			= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
28 
29 unsigned char acpi_srat_revision __initdata;
30 int acpi_numa __initdata;
31 
32 int pxm_to_node(int pxm)
33 {
34 	if (pxm < 0)
35 		return NUMA_NO_NODE;
36 	return pxm_to_node_map[pxm];
37 }
38 EXPORT_SYMBOL(pxm_to_node);
39 
40 int node_to_pxm(int node)
41 {
42 	if (node < 0)
43 		return PXM_INVAL;
44 	return node_to_pxm_map[node];
45 }
46 
47 static void __acpi_map_pxm_to_node(int pxm, int node)
48 {
49 	if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
50 		pxm_to_node_map[pxm] = node;
51 	if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
52 		node_to_pxm_map[node] = pxm;
53 }
54 
55 int acpi_map_pxm_to_node(int pxm)
56 {
57 	int node;
58 
59 	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
60 		return NUMA_NO_NODE;
61 
62 	node = pxm_to_node_map[pxm];
63 
64 	if (node == NUMA_NO_NODE) {
65 		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
66 			return NUMA_NO_NODE;
67 		node = first_unset_node(nodes_found_map);
68 		__acpi_map_pxm_to_node(pxm, node);
69 		node_set(node, nodes_found_map);
70 	}
71 
72 	return node;
73 }
74 EXPORT_SYMBOL(acpi_map_pxm_to_node);
75 
76 static void __init
77 acpi_table_print_srat_entry(struct acpi_subtable_header *header)
78 {
79 	switch (header->type) {
80 	case ACPI_SRAT_TYPE_CPU_AFFINITY:
81 		{
82 			struct acpi_srat_cpu_affinity *p =
83 			    (struct acpi_srat_cpu_affinity *)header;
84 			pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
85 				 p->apic_id, p->local_sapic_eid,
86 				 p->proximity_domain_lo,
87 				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
88 				 "enabled" : "disabled");
89 		}
90 		break;
91 
92 	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
93 		{
94 			struct acpi_srat_mem_affinity *p =
95 			    (struct acpi_srat_mem_affinity *)header;
96 			pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n",
97 				 (unsigned long long)p->base_address,
98 				 (unsigned long long)p->length,
99 				 p->proximity_domain,
100 				 (p->flags & ACPI_SRAT_MEM_ENABLED) ?
101 				 "enabled" : "disabled",
102 				 (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
103 				 " hot-pluggable" : "",
104 				 (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ?
105 				 " non-volatile" : "");
106 		}
107 		break;
108 
109 	case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
110 		{
111 			struct acpi_srat_x2apic_cpu_affinity *p =
112 			    (struct acpi_srat_x2apic_cpu_affinity *)header;
113 			pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s\n",
114 				 p->apic_id,
115 				 p->proximity_domain,
116 				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
117 				 "enabled" : "disabled");
118 		}
119 		break;
120 
121 	case ACPI_SRAT_TYPE_GICC_AFFINITY:
122 		{
123 			struct acpi_srat_gicc_affinity *p =
124 			    (struct acpi_srat_gicc_affinity *)header;
125 			pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n",
126 				 p->acpi_processor_uid,
127 				 p->proximity_domain,
128 				 (p->flags & ACPI_SRAT_GICC_ENABLED) ?
129 				 "enabled" : "disabled");
130 		}
131 		break;
132 
133 	default:
134 		pr_warn("Found unsupported SRAT entry (type = 0x%x)\n",
135 			header->type);
136 		break;
137 	}
138 }
139 
140 /*
141  * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
142  * up the NUMA heuristics which wants the local node to have a smaller
143  * distance than the others.
144  * Do some quick checks here and only use the SLIT if it passes.
145  */
146 static int __init slit_valid(struct acpi_table_slit *slit)
147 {
148 	int i, j;
149 	int d = slit->locality_count;
150 	for (i = 0; i < d; i++) {
151 		for (j = 0; j < d; j++)  {
152 			u8 val = slit->entry[d*i + j];
153 			if (i == j) {
154 				if (val != LOCAL_DISTANCE)
155 					return 0;
156 			} else if (val <= LOCAL_DISTANCE)
157 				return 0;
158 		}
159 	}
160 	return 1;
161 }
162 
163 void __init bad_srat(void)
164 {
165 	pr_err("SRAT: SRAT not used.\n");
166 	acpi_numa = -1;
167 }
168 
169 int __init srat_disabled(void)
170 {
171 	return acpi_numa < 0;
172 }
173 
174 #if defined(CONFIG_X86) || defined(CONFIG_ARM64)
175 /*
176  * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
177  * I/O localities since SRAT does not list them.  I/O localities are
178  * not supported at this point.
179  */
180 void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
181 {
182 	int i, j;
183 
184 	for (i = 0; i < slit->locality_count; i++) {
185 		const int from_node = pxm_to_node(i);
186 
187 		if (from_node == NUMA_NO_NODE)
188 			continue;
189 
190 		for (j = 0; j < slit->locality_count; j++) {
191 			const int to_node = pxm_to_node(j);
192 
193 			if (to_node == NUMA_NO_NODE)
194 				continue;
195 
196 			numa_set_distance(from_node, to_node,
197 				slit->entry[slit->locality_count * i + j]);
198 		}
199 	}
200 }
201 
202 /*
203  * Default callback for parsing of the Proximity Domain <-> Memory
204  * Area mappings
205  */
206 int __init
207 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
208 {
209 	u64 start, end;
210 	u32 hotpluggable;
211 	int node, pxm;
212 
213 	if (srat_disabled())
214 		goto out_err;
215 	if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) {
216 		pr_err("SRAT: Unexpected header length: %d\n",
217 		       ma->header.length);
218 		goto out_err_bad_srat;
219 	}
220 	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
221 		goto out_err;
222 	hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
223 	if (hotpluggable && !IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
224 		goto out_err;
225 
226 	start = ma->base_address;
227 	end = start + ma->length;
228 	pxm = ma->proximity_domain;
229 	if (acpi_srat_revision <= 1)
230 		pxm &= 0xff;
231 
232 	node = acpi_map_pxm_to_node(pxm);
233 	if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
234 		pr_err("SRAT: Too many proximity domains.\n");
235 		goto out_err_bad_srat;
236 	}
237 
238 	if (numa_add_memblk(node, start, end) < 0) {
239 		pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]\n",
240 		       node, (unsigned long long) start,
241 		       (unsigned long long) end - 1);
242 		goto out_err_bad_srat;
243 	}
244 
245 	node_set(node, numa_nodes_parsed);
246 
247 	pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n",
248 		node, pxm,
249 		(unsigned long long) start, (unsigned long long) end - 1,
250 		hotpluggable ? " hotplug" : "",
251 		ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : "");
252 
253 	/* Mark hotplug range in memblock. */
254 	if (hotpluggable && memblock_mark_hotplug(start, ma->length))
255 		pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
256 			(unsigned long long)start, (unsigned long long)end - 1);
257 
258 	max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
259 
260 	return 0;
261 out_err_bad_srat:
262 	bad_srat();
263 out_err:
264 	return -EINVAL;
265 }
266 #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
267 
268 static int __init acpi_parse_slit(struct acpi_table_header *table)
269 {
270 	struct acpi_table_slit *slit = (struct acpi_table_slit *)table;
271 
272 	if (!slit_valid(slit)) {
273 		pr_info("SLIT table looks invalid. Not used.\n");
274 		return -EINVAL;
275 	}
276 	acpi_numa_slit_init(slit);
277 
278 	return 0;
279 }
280 
281 void __init __weak
282 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
283 {
284 	pr_warn("Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
285 }
286 
287 static int __init
288 acpi_parse_x2apic_affinity(union acpi_subtable_headers *header,
289 			   const unsigned long end)
290 {
291 	struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
292 
293 	processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
294 	if (!processor_affinity)
295 		return -EINVAL;
296 
297 	acpi_table_print_srat_entry(&header->common);
298 
299 	/* let architecture-dependent part to do it */
300 	acpi_numa_x2apic_affinity_init(processor_affinity);
301 
302 	return 0;
303 }
304 
305 static int __init
306 acpi_parse_processor_affinity(union acpi_subtable_headers *header,
307 			      const unsigned long end)
308 {
309 	struct acpi_srat_cpu_affinity *processor_affinity;
310 
311 	processor_affinity = (struct acpi_srat_cpu_affinity *)header;
312 	if (!processor_affinity)
313 		return -EINVAL;
314 
315 	acpi_table_print_srat_entry(&header->common);
316 
317 	/* let architecture-dependent part to do it */
318 	acpi_numa_processor_affinity_init(processor_affinity);
319 
320 	return 0;
321 }
322 
323 static int __init
324 acpi_parse_gicc_affinity(union acpi_subtable_headers *header,
325 			 const unsigned long end)
326 {
327 	struct acpi_srat_gicc_affinity *processor_affinity;
328 
329 	processor_affinity = (struct acpi_srat_gicc_affinity *)header;
330 	if (!processor_affinity)
331 		return -EINVAL;
332 
333 	acpi_table_print_srat_entry(&header->common);
334 
335 	/* let architecture-dependent part to do it */
336 	acpi_numa_gicc_affinity_init(processor_affinity);
337 
338 	return 0;
339 }
340 
341 static int __initdata parsed_numa_memblks;
342 
343 static int __init
344 acpi_parse_memory_affinity(union acpi_subtable_headers * header,
345 			   const unsigned long end)
346 {
347 	struct acpi_srat_mem_affinity *memory_affinity;
348 
349 	memory_affinity = (struct acpi_srat_mem_affinity *)header;
350 	if (!memory_affinity)
351 		return -EINVAL;
352 
353 	acpi_table_print_srat_entry(&header->common);
354 
355 	/* let architecture-dependent part to do it */
356 	if (!acpi_numa_memory_affinity_init(memory_affinity))
357 		parsed_numa_memblks++;
358 	return 0;
359 }
360 
361 static int __init acpi_parse_srat(struct acpi_table_header *table)
362 {
363 	struct acpi_table_srat *srat = (struct acpi_table_srat *)table;
364 
365 	acpi_srat_revision = srat->header.revision;
366 
367 	/* Real work done in acpi_table_parse_srat below. */
368 
369 	return 0;
370 }
371 
372 static int __init
373 acpi_table_parse_srat(enum acpi_srat_type id,
374 		      acpi_tbl_entry_handler handler, unsigned int max_entries)
375 {
376 	return acpi_table_parse_entries(ACPI_SIG_SRAT,
377 					    sizeof(struct acpi_table_srat), id,
378 					    handler, max_entries);
379 }
380 
381 int __init acpi_numa_init(void)
382 {
383 	int cnt = 0;
384 
385 	if (acpi_disabled)
386 		return -EINVAL;
387 
388 	/*
389 	 * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
390 	 * SRAT cpu entries could have different order with that in MADT.
391 	 * So go over all cpu entries in SRAT to get apicid to node mapping.
392 	 */
393 
394 	/* SRAT: System Resource Affinity Table */
395 	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
396 		struct acpi_subtable_proc srat_proc[3];
397 
398 		memset(srat_proc, 0, sizeof(srat_proc));
399 		srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
400 		srat_proc[0].handler = acpi_parse_processor_affinity;
401 		srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
402 		srat_proc[1].handler = acpi_parse_x2apic_affinity;
403 		srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY;
404 		srat_proc[2].handler = acpi_parse_gicc_affinity;
405 
406 		acpi_table_parse_entries_array(ACPI_SIG_SRAT,
407 					sizeof(struct acpi_table_srat),
408 					srat_proc, ARRAY_SIZE(srat_proc), 0);
409 
410 		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
411 					    acpi_parse_memory_affinity, 0);
412 	}
413 
414 	/* SLIT: System Locality Information Table */
415 	acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
416 
417 	if (cnt < 0)
418 		return cnt;
419 	else if (!parsed_numa_memblks)
420 		return -ENOENT;
421 	return 0;
422 }
423 
424 static int acpi_get_pxm(acpi_handle h)
425 {
426 	unsigned long long pxm;
427 	acpi_status status;
428 	acpi_handle handle;
429 	acpi_handle phandle = h;
430 
431 	do {
432 		handle = phandle;
433 		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
434 		if (ACPI_SUCCESS(status))
435 			return pxm;
436 		status = acpi_get_parent(handle, &phandle);
437 	} while (ACPI_SUCCESS(status));
438 	return -1;
439 }
440 
441 int acpi_get_node(acpi_handle handle)
442 {
443 	int pxm;
444 
445 	pxm = acpi_get_pxm(handle);
446 
447 	return acpi_map_pxm_to_node(pxm);
448 }
449 EXPORT_SYMBOL(acpi_get_node);
450