numa.c 12.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  acpi_numa.c - ACPI NUMA support
 *
 *  Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 */
21 22 23

#define pr_fmt(fmt) "ACPI: " fmt

L
Linus Torvalds 已提交
24 25 26 27 28 29
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/acpi.h>
30 31
#include <linux/bootmem.h>
#include <linux/memblock.h>
D
David Rientjes 已提交
32
#include <linux/numa.h>
33 34
#include <linux/nodemask.h>
#include <linux/topology.h>
L
Linus Torvalds 已提交
35

36 37 38
static nodemask_t nodes_found_map = NODE_MASK_NONE;

/* maps to convert between proximity domain and logical node ID */
J
Jan Beulich 已提交
39
static int pxm_to_node_map[MAX_PXM_DOMAINS]
D
David Rientjes 已提交
40
			= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
J
Jan Beulich 已提交
41
static int node_to_pxm_map[MAX_NUMNODES]
D
David Rientjes 已提交
42
			= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
43

K
Kurt Garloff 已提交
44
unsigned char acpi_srat_revision __initdata;
45
int acpi_numa __initdata;
K
Kurt Garloff 已提交
46

47
int pxm_to_node(int pxm)
48 49
{
	if (pxm < 0)
D
David Rientjes 已提交
50
		return NUMA_NO_NODE;
51 52
	return pxm_to_node_map[pxm];
}
53
EXPORT_SYMBOL(pxm_to_node);
54

55
int node_to_pxm(int node)
56 57 58 59 60 61
{
	if (node < 0)
		return PXM_INVAL;
	return node_to_pxm_map[node];
}

62
static void __acpi_map_pxm_to_node(int pxm, int node)
63
{
64 65 66 67
	if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
		pxm_to_node_map[pxm] = node;
	if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
		node_to_pxm_map[node] = pxm;
68 69
}

70
int acpi_map_pxm_to_node(int pxm)
71
{
72 73
	int node;

74
	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
75 76 77
		return NUMA_NO_NODE;

	node = pxm_to_node_map[pxm];
78

J
Jianguo Wu 已提交
79
	if (node == NUMA_NO_NODE) {
80
		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
D
David Rientjes 已提交
81
			return NUMA_NO_NODE;
82
		node = first_unset_node(nodes_found_map);
83
		__acpi_map_pxm_to_node(pxm, node);
84 85 86 87 88
		node_set(node, nodes_found_map);
	}

	return node;
}
89
EXPORT_SYMBOL(acpi_map_pxm_to_node);
90

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/**
 * acpi_map_pxm_to_online_node - Map proximity ID to online node
 * @pxm: ACPI proximity ID
 *
 * This is similar to acpi_map_pxm_to_node(), but always returns an online
 * node.  When the mapped node from a given proximity ID is offline, it
 * looks up the node distance table and returns the nearest online node.
 *
 * ACPI device drivers, which are called after the NUMA initialization has
 * completed in the kernel, can call this interface to obtain their device
 * NUMA topology from ACPI tables.  Such drivers do not have to deal with
 * offline nodes.  A node may be offline when a device proximity ID is
 * unique, SRAT memory entry does not exist, or NUMA is disabled, ex.
 * "numa=off" on x86.
 */
int acpi_map_pxm_to_online_node(int pxm)
{
108
	int node, min_node;
109 110 111 112 113 114

	node = acpi_map_pxm_to_node(pxm);

	if (node == NUMA_NO_NODE)
		node = 0;

115
	min_node = node;
116
	if (!node_online(node)) {
117 118
		int min_dist = INT_MAX, dist, n;

119 120 121 122
		for_each_online_node(n) {
			dist = node_distance(node, n);
			if (dist < min_dist) {
				min_dist = dist;
123
				min_node = n;
124 125 126 127
			}
		}
	}

128
	return min_node;
129 130 131
}
EXPORT_SYMBOL(acpi_map_pxm_to_online_node);

132 133
static void __init
acpi_table_print_srat_entry(struct acpi_subtable_header *header)
L
Linus Torvalds 已提交
134 135
{
	switch (header->type) {
136
	case ACPI_SRAT_TYPE_CPU_AFFINITY:
L
Len Brown 已提交
137
		{
138 139
			struct acpi_srat_cpu_affinity *p =
			    (struct acpi_srat_cpu_affinity *)header;
140 141 142 143 144
			pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
				 p->apic_id, p->local_sapic_eid,
				 p->proximity_domain_lo,
				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
				 "enabled" : "disabled");
L
Len Brown 已提交
145
		}
L
Linus Torvalds 已提交
146 147
		break;

148
	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
L
Len Brown 已提交
149
		{
150 151
			struct acpi_srat_mem_affinity *p =
			    (struct acpi_srat_mem_affinity *)header;
152 153 154
			pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n",
				 (unsigned long long)p->base_address,
				 (unsigned long long)p->length,
155 156 157 158 159 160 161
				 p->proximity_domain,
				 (p->flags & ACPI_SRAT_MEM_ENABLED) ?
				 "enabled" : "disabled",
				 (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
				 " hot-pluggable" : "",
				 (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ?
				 " non-volatile" : "");
L
Len Brown 已提交
162
		}
L
Linus Torvalds 已提交
163 164
		break;

165 166 167 168
	case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
		{
			struct acpi_srat_x2apic_cpu_affinity *p =
			    (struct acpi_srat_x2apic_cpu_affinity *)header;
169 170 171 172 173
			pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s\n",
				 p->apic_id,
				 p->proximity_domain,
				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
				 "enabled" : "disabled");
174 175
		}
		break;
176

177 178 179 180 181 182 183 184 185 186 187 188
	case ACPI_SRAT_TYPE_GICC_AFFINITY:
		{
			struct acpi_srat_gicc_affinity *p =
			    (struct acpi_srat_gicc_affinity *)header;
			pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n",
				 p->acpi_processor_uid,
				 p->proximity_domain,
				 (p->flags & ACPI_SRAT_GICC_ENABLED) ?
				 "enabled" : "disabled");
		}
		break;

L
Linus Torvalds 已提交
189
	default:
190 191
		pr_warn("Found unsupported SRAT entry (type = 0x%x)\n",
			header->type);
L
Linus Torvalds 已提交
192 193 194 195
		break;
	}
}

196 197 198 199 200 201
/*
 * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
 * up the NUMA heuristics which wants the local node to have a smaller
 * distance than the others.
 * Do some quick checks here and only use the SLIT if it passes.
 */
202
static int __init slit_valid(struct acpi_table_slit *slit)
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
{
	int i, j;
	int d = slit->locality_count;
	for (i = 0; i < d; i++) {
		for (j = 0; j < d; j++)  {
			u8 val = slit->entry[d*i + j];
			if (i == j) {
				if (val != LOCAL_DISTANCE)
					return 0;
			} else if (val <= LOCAL_DISTANCE)
				return 0;
		}
	}
	return 1;
}

219 220 221 222 223 224 225 226 227 228 229
void __init bad_srat(void)
{
	pr_err("SRAT: SRAT not used.\n");
	acpi_numa = -1;
}

int __init srat_disabled(void)
{
	return acpi_numa < 0;
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
#if defined(CONFIG_X86) || defined(CONFIG_ARM64)
/*
 * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
 * I/O localities since SRAT does not list them.  I/O localities are
 * not supported at this point.
 */
void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
{
	int i, j;

	for (i = 0; i < slit->locality_count; i++) {
		const int from_node = pxm_to_node(i);

		if (from_node == NUMA_NO_NODE)
			continue;

		for (j = 0; j < slit->locality_count; j++) {
			const int to_node = pxm_to_node(j);

			if (to_node == NUMA_NO_NODE)
				continue;

			numa_set_distance(from_node, to_node,
				slit->entry[slit->locality_count * i + j]);
		}
	}
}
257 258 259 260 261 262 263 264 265 266 267 268 269 270

/*
 * Default callback for parsing of the Proximity Domain <-> Memory
 * Area mappings
 */
int __init
acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
{
	u64 start, end;
	u32 hotpluggable;
	int node, pxm;

	if (srat_disabled())
		goto out_err;
271 272 273
	if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) {
		pr_err("SRAT: Unexpected header length: %d\n",
		       ma->header.length);
274
		goto out_err_bad_srat;
275
	}
276 277 278 279 280 281 282 283 284 285 286 287 288
	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
		goto out_err;
	hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
	if (hotpluggable && !IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
		goto out_err;

	start = ma->base_address;
	end = start + ma->length;
	pxm = ma->proximity_domain;
	if (acpi_srat_revision <= 1)
		pxm &= 0xff;

	node = acpi_map_pxm_to_node(pxm);
289 290
	if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
		pr_err("SRAT: Too many proximity domains.\n");
291 292 293
		goto out_err_bad_srat;
	}

294 295 296 297
	if (numa_add_memblk(node, start, end) < 0) {
		pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]\n",
		       node, (unsigned long long) start,
		       (unsigned long long) end - 1);
298
		goto out_err_bad_srat;
299
	}
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

	node_set(node, numa_nodes_parsed);

	pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n",
		node, pxm,
		(unsigned long long) start, (unsigned long long) end - 1,
		hotpluggable ? " hotplug" : "",
		ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : "");

	/* Mark hotplug range in memblock. */
	if (hotpluggable && memblock_mark_hotplug(start, ma->length))
		pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
			(unsigned long long)start, (unsigned long long)end - 1);

	max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));

	return 0;
out_err_bad_srat:
	bad_srat();
out_err:
	return -EINVAL;
}
322 323
#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */

324
static int __init acpi_parse_slit(struct acpi_table_header *table)
L
Linus Torvalds 已提交
325
{
326
	struct acpi_table_slit *slit = (struct acpi_table_slit *)table;
L
Linus Torvalds 已提交
327

328
	if (!slit_valid(slit)) {
329
		pr_info("SLIT table looks invalid. Not used.\n");
330 331
		return -EINVAL;
	}
L
Linus Torvalds 已提交
332 333 334 335 336
	acpi_numa_slit_init(slit);

	return 0;
}

337
void __init __weak
338 339
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
{
340
	pr_warn("Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
341 342 343
}

static int __init
344
acpi_parse_x2apic_affinity(union acpi_subtable_headers *header,
345 346 347 348 349 350 351 352
			   const unsigned long end)
{
	struct acpi_srat_x2apic_cpu_affinity *processor_affinity;

	processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
	if (!processor_affinity)
		return -EINVAL;

353
	acpi_table_print_srat_entry(&header->common);
354 355 356 357 358 359 360

	/* let architecture-dependent part to do it */
	acpi_numa_x2apic_affinity_init(processor_affinity);

	return 0;
}

L
Linus Torvalds 已提交
361
static int __init
362
acpi_parse_processor_affinity(union acpi_subtable_headers *header,
L
Len Brown 已提交
363
			      const unsigned long end)
L
Linus Torvalds 已提交
364
{
365
	struct acpi_srat_cpu_affinity *processor_affinity;
L
Linus Torvalds 已提交
366

367
	processor_affinity = (struct acpi_srat_cpu_affinity *)header;
L
Linus Torvalds 已提交
368 369 370
	if (!processor_affinity)
		return -EINVAL;

371
	acpi_table_print_srat_entry(&header->common);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378

	/* let architecture-dependent part to do it */
	acpi_numa_processor_affinity_init(processor_affinity);

	return 0;
}

379
static int __init
380
acpi_parse_gicc_affinity(union acpi_subtable_headers *header,
381 382 383 384 385 386 387 388
			 const unsigned long end)
{
	struct acpi_srat_gicc_affinity *processor_affinity;

	processor_affinity = (struct acpi_srat_gicc_affinity *)header;
	if (!processor_affinity)
		return -EINVAL;

389
	acpi_table_print_srat_entry(&header->common);
390 391 392 393 394 395 396

	/* let architecture-dependent part to do it */
	acpi_numa_gicc_affinity_init(processor_affinity);

	return 0;
}

397 398
static int __initdata parsed_numa_memblks;

L
Linus Torvalds 已提交
399
static int __init
400
acpi_parse_memory_affinity(union acpi_subtable_headers * header,
L
Len Brown 已提交
401
			   const unsigned long end)
L
Linus Torvalds 已提交
402
{
403
	struct acpi_srat_mem_affinity *memory_affinity;
L
Linus Torvalds 已提交
404

405
	memory_affinity = (struct acpi_srat_mem_affinity *)header;
L
Linus Torvalds 已提交
406 407 408
	if (!memory_affinity)
		return -EINVAL;

409
	acpi_table_print_srat_entry(&header->common);
L
Linus Torvalds 已提交
410 411

	/* let architecture-dependent part to do it */
412 413
	if (!acpi_numa_memory_affinity_init(memory_affinity))
		parsed_numa_memblks++;
L
Linus Torvalds 已提交
414 415 416
	return 0;
}

417
static int __init acpi_parse_srat(struct acpi_table_header *table)
L
Linus Torvalds 已提交
418
{
419
	struct acpi_table_srat *srat = (struct acpi_table_srat *)table;
L
Linus Torvalds 已提交
420

K
Kurt Garloff 已提交
421 422
	acpi_srat_revision = srat->header.revision;

423
	/* Real work done in acpi_table_parse_srat below. */
L
Linus Torvalds 已提交
424 425 426 427

	return 0;
}

428
static int __init
429
acpi_table_parse_srat(enum acpi_srat_type id,
430
		      acpi_tbl_entry_handler handler, unsigned int max_entries)
L
Linus Torvalds 已提交
431
{
432
	return acpi_table_parse_entries(ACPI_SIG_SRAT,
L
Len Brown 已提交
433 434
					    sizeof(struct acpi_table_srat), id,
					    handler, max_entries);
L
Linus Torvalds 已提交
435 436
}

437
int __init acpi_numa_init(void)
438
{
439 440
	int cnt = 0;

441 442 443
	if (acpi_disabled)
		return -EINVAL;

444 445 446 447 448
	/*
	 * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
	 * SRAT cpu entries could have different order with that in MADT.
	 * So go over all cpu entries in SRAT to get apicid to node mapping.
	 */
449

450
	/* SRAT: System Resource Affinity Table */
451
	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
452
		struct acpi_subtable_proc srat_proc[3];
453 454 455 456 457 458

		memset(srat_proc, 0, sizeof(srat_proc));
		srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
		srat_proc[0].handler = acpi_parse_processor_affinity;
		srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
		srat_proc[1].handler = acpi_parse_x2apic_affinity;
459 460
		srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY;
		srat_proc[2].handler = acpi_parse_gicc_affinity;
461 462 463 464 465

		acpi_table_parse_entries_array(ACPI_SIG_SRAT,
					sizeof(struct acpi_table_srat),
					srat_proc, ARRAY_SIZE(srat_proc), 0);

466
		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
467
					    acpi_parse_memory_affinity, 0);
L
Linus Torvalds 已提交
468 469 470
	}

	/* SLIT: System Locality Information Table */
471
	acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
L
Linus Torvalds 已提交
472

473 474
	if (cnt < 0)
		return cnt;
475
	else if (!parsed_numa_memblks)
476
		return -ENOENT;
477
	return 0;
L
Linus Torvalds 已提交
478 479
}

480
static int acpi_get_pxm(acpi_handle h)
L
Linus Torvalds 已提交
481
{
482
	unsigned long long pxm;
L
Linus Torvalds 已提交
483 484 485 486 487 488 489 490
	acpi_status status;
	acpi_handle handle;
	acpi_handle phandle = h;

	do {
		handle = phandle;
		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
		if (ACPI_SUCCESS(status))
491
			return pxm;
L
Linus Torvalds 已提交
492
		status = acpi_get_parent(handle, &phandle);
L
Len Brown 已提交
493
	} while (ACPI_SUCCESS(status));
L
Linus Torvalds 已提交
494 495
	return -1;
}
496

497
int acpi_get_node(acpi_handle handle)
498
{
499
	int pxm;
500 501 502

	pxm = acpi_get_pxm(handle);

503
	return acpi_map_pxm_to_node(pxm);
504 505
}
EXPORT_SYMBOL(acpi_get_node);