cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

srat.c (14842B)


      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
     21static nodemask_t nodes_found_map = NODE_MASK_NONE;
     22
     23/* maps to convert between proximity domain and logical node ID */
     24static int pxm_to_node_map[MAX_PXM_DOMAINS]
     25			= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
     26static int node_to_pxm_map[MAX_NUMNODES]
     27			= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
     28
     29unsigned char acpi_srat_revision __initdata;
     30static int acpi_numa __initdata;
     31
     32void __init disable_srat(void)
     33{
     34	acpi_numa = -1;
     35}
     36
     37int pxm_to_node(int pxm)
     38{
     39	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
     40		return NUMA_NO_NODE;
     41	return pxm_to_node_map[pxm];
     42}
     43EXPORT_SYMBOL(pxm_to_node);
     44
     45int node_to_pxm(int node)
     46{
     47	if (node < 0)
     48		return PXM_INVAL;
     49	return node_to_pxm_map[node];
     50}
     51
     52static void __acpi_map_pxm_to_node(int pxm, int node)
     53{
     54	if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
     55		pxm_to_node_map[pxm] = node;
     56	if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
     57		node_to_pxm_map[node] = pxm;
     58}
     59
     60int acpi_map_pxm_to_node(int pxm)
     61{
     62	int node;
     63
     64	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
     65		return NUMA_NO_NODE;
     66
     67	node = pxm_to_node_map[pxm];
     68
     69	if (node == NUMA_NO_NODE) {
     70		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
     71			return NUMA_NO_NODE;
     72		node = first_unset_node(nodes_found_map);
     73		__acpi_map_pxm_to_node(pxm, node);
     74		node_set(node, nodes_found_map);
     75	}
     76
     77	return node;
     78}
     79EXPORT_SYMBOL(acpi_map_pxm_to_node);
     80
     81static void __init
     82acpi_table_print_srat_entry(struct acpi_subtable_header *header)
     83{
     84	switch (header->type) {
     85	case ACPI_SRAT_TYPE_CPU_AFFINITY:
     86		{
     87			struct acpi_srat_cpu_affinity *p =
     88			    (struct acpi_srat_cpu_affinity *)header;
     89			pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
     90				 p->apic_id, p->local_sapic_eid,
     91				 p->proximity_domain_lo,
     92				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
     93				 "enabled" : "disabled");
     94		}
     95		break;
     96
     97	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
     98		{
     99			struct acpi_srat_mem_affinity *p =
    100			    (struct acpi_srat_mem_affinity *)header;
    101			pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n",
    102				 (unsigned long long)p->base_address,
    103				 (unsigned long long)p->length,
    104				 p->proximity_domain,
    105				 (p->flags & ACPI_SRAT_MEM_ENABLED) ?
    106				 "enabled" : "disabled",
    107				 (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
    108				 " hot-pluggable" : "",
    109				 (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ?
    110				 " non-volatile" : "");
    111		}
    112		break;
    113
    114	case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
    115		{
    116			struct acpi_srat_x2apic_cpu_affinity *p =
    117			    (struct acpi_srat_x2apic_cpu_affinity *)header;
    118			pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s\n",
    119				 p->apic_id,
    120				 p->proximity_domain,
    121				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
    122				 "enabled" : "disabled");
    123		}
    124		break;
    125
    126	case ACPI_SRAT_TYPE_GICC_AFFINITY:
    127		{
    128			struct acpi_srat_gicc_affinity *p =
    129			    (struct acpi_srat_gicc_affinity *)header;
    130			pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n",
    131				 p->acpi_processor_uid,
    132				 p->proximity_domain,
    133				 (p->flags & ACPI_SRAT_GICC_ENABLED) ?
    134				 "enabled" : "disabled");
    135		}
    136		break;
    137
    138	case ACPI_SRAT_TYPE_GENERIC_AFFINITY:
    139	{
    140		struct acpi_srat_generic_affinity *p =
    141			(struct acpi_srat_generic_affinity *)header;
    142
    143		if (p->device_handle_type == 0) {
    144			/*
    145			 * For pci devices this may be the only place they
    146			 * are assigned a proximity domain
    147			 */
    148			pr_debug("SRAT Generic Initiator(Seg:%u BDF:%u) in proximity domain %d %s\n",
    149				 *(u16 *)(&p->device_handle[0]),
    150				 *(u16 *)(&p->device_handle[2]),
    151				 p->proximity_domain,
    152				 (p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ?
    153				"enabled" : "disabled");
    154		} else {
    155			/*
    156			 * In this case we can rely on the device having a
    157			 * proximity domain reference
    158			 */
    159			pr_debug("SRAT Generic Initiator(HID=%.8s UID=%.4s) in proximity domain %d %s\n",
    160				(char *)(&p->device_handle[0]),
    161				(char *)(&p->device_handle[8]),
    162				p->proximity_domain,
    163				(p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ?
    164				"enabled" : "disabled");
    165		}
    166	}
    167	break;
    168	default:
    169		pr_warn("Found unsupported SRAT entry (type = 0x%x)\n",
    170			header->type);
    171		break;
    172	}
    173}
    174
    175/*
    176 * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
    177 * up the NUMA heuristics which wants the local node to have a smaller
    178 * distance than the others.
    179 * Do some quick checks here and only use the SLIT if it passes.
    180 */
    181static int __init slit_valid(struct acpi_table_slit *slit)
    182{
    183	int i, j;
    184	int d = slit->locality_count;
    185	for (i = 0; i < d; i++) {
    186		for (j = 0; j < d; j++)  {
    187			u8 val = slit->entry[d*i + j];
    188			if (i == j) {
    189				if (val != LOCAL_DISTANCE)
    190					return 0;
    191			} else if (val <= LOCAL_DISTANCE)
    192				return 0;
    193		}
    194	}
    195	return 1;
    196}
    197
    198void __init bad_srat(void)
    199{
    200	pr_err("SRAT: SRAT not used.\n");
    201	disable_srat();
    202}
    203
    204int __init srat_disabled(void)
    205{
    206	return acpi_numa < 0;
    207}
    208
    209#if defined(CONFIG_X86) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH)
    210/*
    211 * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
    212 * I/O localities since SRAT does not list them.  I/O localities are
    213 * not supported at this point.
    214 */
    215void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
    216{
    217	int i, j;
    218
    219	for (i = 0; i < slit->locality_count; i++) {
    220		const int from_node = pxm_to_node(i);
    221
    222		if (from_node == NUMA_NO_NODE)
    223			continue;
    224
    225		for (j = 0; j < slit->locality_count; j++) {
    226			const int to_node = pxm_to_node(j);
    227
    228			if (to_node == NUMA_NO_NODE)
    229				continue;
    230
    231			numa_set_distance(from_node, to_node,
    232				slit->entry[slit->locality_count * i + j]);
    233		}
    234	}
    235}
    236
    237/*
    238 * Default callback for parsing of the Proximity Domain <-> Memory
    239 * Area mappings
    240 */
    241int __init
    242acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
    243{
    244	u64 start, end;
    245	u32 hotpluggable;
    246	int node, pxm;
    247
    248	if (srat_disabled())
    249		goto out_err;
    250	if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) {
    251		pr_err("SRAT: Unexpected header length: %d\n",
    252		       ma->header.length);
    253		goto out_err_bad_srat;
    254	}
    255	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
    256		goto out_err;
    257	hotpluggable = IS_ENABLED(CONFIG_MEMORY_HOTPLUG) &&
    258		(ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE);
    259
    260	start = ma->base_address;
    261	end = start + ma->length;
    262	pxm = ma->proximity_domain;
    263	if (acpi_srat_revision <= 1)
    264		pxm &= 0xff;
    265
    266	node = acpi_map_pxm_to_node(pxm);
    267	if (node == NUMA_NO_NODE) {
    268		pr_err("SRAT: Too many proximity domains.\n");
    269		goto out_err_bad_srat;
    270	}
    271
    272	if (numa_add_memblk(node, start, end) < 0) {
    273		pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]\n",
    274		       node, (unsigned long long) start,
    275		       (unsigned long long) end - 1);
    276		goto out_err_bad_srat;
    277	}
    278
    279	node_set(node, numa_nodes_parsed);
    280
    281	pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n",
    282		node, pxm,
    283		(unsigned long long) start, (unsigned long long) end - 1,
    284		hotpluggable ? " hotplug" : "",
    285		ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : "");
    286
    287	/* Mark hotplug range in memblock. */
    288	if (hotpluggable && memblock_mark_hotplug(start, ma->length))
    289		pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
    290			(unsigned long long)start, (unsigned long long)end - 1);
    291
    292	max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
    293
    294	return 0;
    295out_err_bad_srat:
    296	bad_srat();
    297out_err:
    298	return -EINVAL;
    299}
    300
    301static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
    302				   void *arg, const unsigned long table_end)
    303{
    304	struct acpi_cedt_cfmws *cfmws;
    305	int *fake_pxm = arg;
    306	u64 start, end;
    307	int node;
    308
    309	cfmws = (struct acpi_cedt_cfmws *)header;
    310	start = cfmws->base_hpa;
    311	end = cfmws->base_hpa + cfmws->window_size;
    312
    313	/* Skip if the SRAT already described the NUMA details for this HPA */
    314	node = phys_to_target_node(start);
    315	if (node != NUMA_NO_NODE)
    316		return 0;
    317
    318	node = acpi_map_pxm_to_node(*fake_pxm);
    319
    320	if (node == NUMA_NO_NODE) {
    321		pr_err("ACPI NUMA: Too many proximity domains while processing CFMWS.\n");
    322		return -EINVAL;
    323	}
    324
    325	if (numa_add_memblk(node, start, end) < 0) {
    326		/* CXL driver must handle the NUMA_NO_NODE case */
    327		pr_warn("ACPI NUMA: Failed to add memblk for CFMWS node %d [mem %#llx-%#llx]\n",
    328			node, start, end);
    329	}
    330
    331	/* Set the next available fake_pxm value */
    332	(*fake_pxm)++;
    333	return 0;
    334}
    335#else
    336static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
    337				   void *arg, const unsigned long table_end)
    338{
    339	return 0;
    340}
    341#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
    342
    343static int __init acpi_parse_slit(struct acpi_table_header *table)
    344{
    345	struct acpi_table_slit *slit = (struct acpi_table_slit *)table;
    346
    347	if (!slit_valid(slit)) {
    348		pr_info("SLIT table looks invalid. Not used.\n");
    349		return -EINVAL;
    350	}
    351	acpi_numa_slit_init(slit);
    352
    353	return 0;
    354}
    355
    356void __init __weak
    357acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
    358{
    359	pr_warn("Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
    360}
    361
    362static int __init
    363acpi_parse_x2apic_affinity(union acpi_subtable_headers *header,
    364			   const unsigned long end)
    365{
    366	struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
    367
    368	processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
    369
    370	acpi_table_print_srat_entry(&header->common);
    371
    372	/* let architecture-dependent part to do it */
    373	acpi_numa_x2apic_affinity_init(processor_affinity);
    374
    375	return 0;
    376}
    377
    378static int __init
    379acpi_parse_processor_affinity(union acpi_subtable_headers *header,
    380			      const unsigned long end)
    381{
    382	struct acpi_srat_cpu_affinity *processor_affinity;
    383
    384	processor_affinity = (struct acpi_srat_cpu_affinity *)header;
    385
    386	acpi_table_print_srat_entry(&header->common);
    387
    388	/* let architecture-dependent part to do it */
    389	acpi_numa_processor_affinity_init(processor_affinity);
    390
    391	return 0;
    392}
    393
    394static int __init
    395acpi_parse_gicc_affinity(union acpi_subtable_headers *header,
    396			 const unsigned long end)
    397{
    398	struct acpi_srat_gicc_affinity *processor_affinity;
    399
    400	processor_affinity = (struct acpi_srat_gicc_affinity *)header;
    401
    402	acpi_table_print_srat_entry(&header->common);
    403
    404	/* let architecture-dependent part to do it */
    405	acpi_numa_gicc_affinity_init(processor_affinity);
    406
    407	return 0;
    408}
    409
    410#if defined(CONFIG_X86) || defined(CONFIG_ARM64)
    411static int __init
    412acpi_parse_gi_affinity(union acpi_subtable_headers *header,
    413		       const unsigned long end)
    414{
    415	struct acpi_srat_generic_affinity *gi_affinity;
    416	int node;
    417
    418	gi_affinity = (struct acpi_srat_generic_affinity *)header;
    419	if (!gi_affinity)
    420		return -EINVAL;
    421	acpi_table_print_srat_entry(&header->common);
    422
    423	if (!(gi_affinity->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED))
    424		return -EINVAL;
    425
    426	node = acpi_map_pxm_to_node(gi_affinity->proximity_domain);
    427	if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
    428		pr_err("SRAT: Too many proximity domains.\n");
    429		return -EINVAL;
    430	}
    431	node_set(node, numa_nodes_parsed);
    432	node_set_state(node, N_GENERIC_INITIATOR);
    433
    434	return 0;
    435}
    436#else
    437static int __init
    438acpi_parse_gi_affinity(union acpi_subtable_headers *header,
    439		       const unsigned long end)
    440{
    441	return 0;
    442}
    443#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
    444
    445static int __initdata parsed_numa_memblks;
    446
    447static int __init
    448acpi_parse_memory_affinity(union acpi_subtable_headers * header,
    449			   const unsigned long end)
    450{
    451	struct acpi_srat_mem_affinity *memory_affinity;
    452
    453	memory_affinity = (struct acpi_srat_mem_affinity *)header;
    454
    455	acpi_table_print_srat_entry(&header->common);
    456
    457	/* let architecture-dependent part to do it */
    458	if (!acpi_numa_memory_affinity_init(memory_affinity))
    459		parsed_numa_memblks++;
    460	return 0;
    461}
    462
    463static int __init acpi_parse_srat(struct acpi_table_header *table)
    464{
    465	struct acpi_table_srat *srat = (struct acpi_table_srat *)table;
    466
    467	acpi_srat_revision = srat->header.revision;
    468
    469	/* Real work done in acpi_table_parse_srat below. */
    470
    471	return 0;
    472}
    473
    474static int __init
    475acpi_table_parse_srat(enum acpi_srat_type id,
    476		      acpi_tbl_entry_handler handler, unsigned int max_entries)
    477{
    478	return acpi_table_parse_entries(ACPI_SIG_SRAT,
    479					    sizeof(struct acpi_table_srat), id,
    480					    handler, max_entries);
    481}
    482
    483int __init acpi_numa_init(void)
    484{
    485	int i, fake_pxm, cnt = 0;
    486
    487	if (acpi_disabled)
    488		return -EINVAL;
    489
    490	/*
    491	 * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
    492	 * SRAT cpu entries could have different order with that in MADT.
    493	 * So go over all cpu entries in SRAT to get apicid to node mapping.
    494	 */
    495
    496	/* SRAT: System Resource Affinity Table */
    497	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
    498		struct acpi_subtable_proc srat_proc[4];
    499
    500		memset(srat_proc, 0, sizeof(srat_proc));
    501		srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
    502		srat_proc[0].handler = acpi_parse_processor_affinity;
    503		srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
    504		srat_proc[1].handler = acpi_parse_x2apic_affinity;
    505		srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY;
    506		srat_proc[2].handler = acpi_parse_gicc_affinity;
    507		srat_proc[3].id = ACPI_SRAT_TYPE_GENERIC_AFFINITY;
    508		srat_proc[3].handler = acpi_parse_gi_affinity;
    509
    510		acpi_table_parse_entries_array(ACPI_SIG_SRAT,
    511					sizeof(struct acpi_table_srat),
    512					srat_proc, ARRAY_SIZE(srat_proc), 0);
    513
    514		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
    515					    acpi_parse_memory_affinity, 0);
    516	}
    517
    518	/* SLIT: System Locality Information Table */
    519	acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
    520
    521	/*
    522	 * CXL Fixed Memory Window Structures (CFMWS) must be parsed
    523	 * after the SRAT. Create NUMA Nodes for CXL memory ranges that
    524	 * are defined in the CFMWS and not already defined in the SRAT.
    525	 * Initialize a fake_pxm as the first available PXM to emulate.
    526	 */
    527
    528	/* fake_pxm is the next unused PXM value after SRAT parsing */
    529	for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) {
    530		if (node_to_pxm_map[i] > fake_pxm)
    531			fake_pxm = node_to_pxm_map[i];
    532	}
    533	fake_pxm++;
    534	acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws,
    535			      &fake_pxm);
    536
    537	if (cnt < 0)
    538		return cnt;
    539	else if (!parsed_numa_memblks)
    540		return -ENOENT;
    541	return 0;
    542}
    543
    544static int acpi_get_pxm(acpi_handle h)
    545{
    546	unsigned long long pxm;
    547	acpi_status status;
    548	acpi_handle handle;
    549	acpi_handle phandle = h;
    550
    551	do {
    552		handle = phandle;
    553		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
    554		if (ACPI_SUCCESS(status))
    555			return pxm;
    556		status = acpi_get_parent(handle, &phandle);
    557	} while (ACPI_SUCCESS(status));
    558	return -1;
    559}
    560
    561int acpi_get_node(acpi_handle handle)
    562{
    563	int pxm;
    564
    565	pxm = acpi_get_pxm(handle);
    566
    567	return pxm_to_node(pxm);
    568}
    569EXPORT_SYMBOL(acpi_get_node);