18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * acpi_numa.c - ACPI NUMA support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ACPI: " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/acpi.h> 168c2ecf20Sopenharmony_ci#include <linux/memblock.h> 178c2ecf20Sopenharmony_ci#include <linux/numa.h> 188c2ecf20Sopenharmony_ci#include <linux/nodemask.h> 198c2ecf20Sopenharmony_ci#include <linux/topology.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic nodemask_t nodes_found_map = NODE_MASK_NONE; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* maps to convert between proximity domain and logical node ID */ 248c2ecf20Sopenharmony_cistatic int pxm_to_node_map[MAX_PXM_DOMAINS] 258c2ecf20Sopenharmony_ci = { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; 268c2ecf20Sopenharmony_cistatic int node_to_pxm_map[MAX_NUMNODES] 278c2ecf20Sopenharmony_ci = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciunsigned char acpi_srat_revision __initdata; 308c2ecf20Sopenharmony_cistatic int acpi_numa __initdata; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid __init disable_srat(void) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci acpi_numa = -1; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciint pxm_to_node(int pxm) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off) 408c2ecf20Sopenharmony_ci return NUMA_NO_NODE; 418c2ecf20Sopenharmony_ci return pxm_to_node_map[pxm]; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pxm_to_node); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint node_to_pxm(int node) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci if (node < 0) 488c2ecf20Sopenharmony_ci return PXM_INVAL; 498c2ecf20Sopenharmony_ci return node_to_pxm_map[node]; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void __acpi_map_pxm_to_node(int pxm, int node) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm]) 558c2ecf20Sopenharmony_ci pxm_to_node_map[pxm] = node; 568c2ecf20Sopenharmony_ci if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node]) 578c2ecf20Sopenharmony_ci node_to_pxm_map[node] = pxm; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciint acpi_map_pxm_to_node(int pxm) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int node; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off) 658c2ecf20Sopenharmony_ci return NUMA_NO_NODE; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci node = pxm_to_node_map[pxm]; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (node == NUMA_NO_NODE) { 708c2ecf20Sopenharmony_ci if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) 718c2ecf20Sopenharmony_ci return NUMA_NO_NODE; 728c2ecf20Sopenharmony_ci node = first_unset_node(nodes_found_map); 738c2ecf20Sopenharmony_ci __acpi_map_pxm_to_node(pxm, node); 748c2ecf20Sopenharmony_ci node_set(node, nodes_found_map); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return node; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_map_pxm_to_node); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void __init 828c2ecf20Sopenharmony_ciacpi_table_print_srat_entry(struct acpi_subtable_header *header) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci switch (header->type) { 858c2ecf20Sopenharmony_ci case ACPI_SRAT_TYPE_CPU_AFFINITY: 868c2ecf20Sopenharmony_ci { 878c2ecf20Sopenharmony_ci struct acpi_srat_cpu_affinity *p = 888c2ecf20Sopenharmony_ci (struct acpi_srat_cpu_affinity *)header; 898c2ecf20Sopenharmony_ci pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", 908c2ecf20Sopenharmony_ci p->apic_id, p->local_sapic_eid, 918c2ecf20Sopenharmony_ci p->proximity_domain_lo, 928c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_CPU_ENABLED) ? 938c2ecf20Sopenharmony_ci "enabled" : "disabled"); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci case ACPI_SRAT_TYPE_MEMORY_AFFINITY: 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci struct acpi_srat_mem_affinity *p = 1008c2ecf20Sopenharmony_ci (struct acpi_srat_mem_affinity *)header; 1018c2ecf20Sopenharmony_ci pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n", 1028c2ecf20Sopenharmony_ci (unsigned long long)p->base_address, 1038c2ecf20Sopenharmony_ci (unsigned long long)p->length, 1048c2ecf20Sopenharmony_ci p->proximity_domain, 1058c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_MEM_ENABLED) ? 1068c2ecf20Sopenharmony_ci "enabled" : "disabled", 1078c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? 1088c2ecf20Sopenharmony_ci " hot-pluggable" : "", 1098c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ? 1108c2ecf20Sopenharmony_ci " non-volatile" : ""); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci struct acpi_srat_x2apic_cpu_affinity *p = 1178c2ecf20Sopenharmony_ci (struct acpi_srat_x2apic_cpu_affinity *)header; 1188c2ecf20Sopenharmony_ci pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s\n", 1198c2ecf20Sopenharmony_ci p->apic_id, 1208c2ecf20Sopenharmony_ci p->proximity_domain, 1218c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_CPU_ENABLED) ? 1228c2ecf20Sopenharmony_ci "enabled" : "disabled"); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci case ACPI_SRAT_TYPE_GICC_AFFINITY: 1278c2ecf20Sopenharmony_ci { 1288c2ecf20Sopenharmony_ci struct acpi_srat_gicc_affinity *p = 1298c2ecf20Sopenharmony_ci (struct acpi_srat_gicc_affinity *)header; 1308c2ecf20Sopenharmony_ci pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n", 1318c2ecf20Sopenharmony_ci p->acpi_processor_uid, 1328c2ecf20Sopenharmony_ci p->proximity_domain, 1338c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_GICC_ENABLED) ? 1348c2ecf20Sopenharmony_ci "enabled" : "disabled"); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci case ACPI_SRAT_TYPE_GENERIC_AFFINITY: 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci struct acpi_srat_generic_affinity *p = 1418c2ecf20Sopenharmony_ci (struct acpi_srat_generic_affinity *)header; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (p->device_handle_type == 0) { 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * For pci devices this may be the only place they 1468c2ecf20Sopenharmony_ci * are assigned a proximity domain 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_ci pr_debug("SRAT Generic Initiator(Seg:%u BDF:%u) in proximity domain %d %s\n", 1498c2ecf20Sopenharmony_ci *(u16 *)(&p->device_handle[0]), 1508c2ecf20Sopenharmony_ci *(u16 *)(&p->device_handle[2]), 1518c2ecf20Sopenharmony_ci p->proximity_domain, 1528c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ? 1538c2ecf20Sopenharmony_ci "enabled" : "disabled"); 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * In this case we can rely on the device having a 1578c2ecf20Sopenharmony_ci * proximity domain reference 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci pr_debug("SRAT Generic Initiator(HID=%.8s UID=%.4s) in proximity domain %d %s\n", 1608c2ecf20Sopenharmony_ci (char *)(&p->device_handle[0]), 1618c2ecf20Sopenharmony_ci (char *)(&p->device_handle[8]), 1628c2ecf20Sopenharmony_ci p->proximity_domain, 1638c2ecf20Sopenharmony_ci (p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ? 1648c2ecf20Sopenharmony_ci "enabled" : "disabled"); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci default: 1698c2ecf20Sopenharmony_ci pr_warn("Found unsupported SRAT entry (type = 0x%x)\n", 1708c2ecf20Sopenharmony_ci header->type); 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * A lot of BIOS fill in 10 (= no distance) everywhere. This messes 1778c2ecf20Sopenharmony_ci * up the NUMA heuristics which wants the local node to have a smaller 1788c2ecf20Sopenharmony_ci * distance than the others. 1798c2ecf20Sopenharmony_ci * Do some quick checks here and only use the SLIT if it passes. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int __init slit_valid(struct acpi_table_slit *slit) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci int i, j; 1848c2ecf20Sopenharmony_ci int d = slit->locality_count; 1858c2ecf20Sopenharmony_ci for (i = 0; i < d; i++) { 1868c2ecf20Sopenharmony_ci for (j = 0; j < d; j++) { 1878c2ecf20Sopenharmony_ci u8 val = slit->entry[d*i + j]; 1888c2ecf20Sopenharmony_ci if (i == j) { 1898c2ecf20Sopenharmony_ci if (val != LOCAL_DISTANCE) 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci } else if (val <= LOCAL_DISTANCE) 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci return 1; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid __init bad_srat(void) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci pr_err("SRAT: SRAT not used.\n"); 2018c2ecf20Sopenharmony_ci disable_srat(); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciint __init srat_disabled(void) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return acpi_numa < 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#if defined(CONFIG_X86) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH) 2108c2ecf20Sopenharmony_ci/* 2118c2ecf20Sopenharmony_ci * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for 2128c2ecf20Sopenharmony_ci * I/O localities since SRAT does not list them. I/O localities are 2138c2ecf20Sopenharmony_ci * not supported at this point. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_civoid __init acpi_numa_slit_init(struct acpi_table_slit *slit) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci int i, j; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (i = 0; i < slit->locality_count; i++) { 2208c2ecf20Sopenharmony_ci const int from_node = pxm_to_node(i); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (from_node == NUMA_NO_NODE) 2238c2ecf20Sopenharmony_ci continue; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci for (j = 0; j < slit->locality_count; j++) { 2268c2ecf20Sopenharmony_ci const int to_node = pxm_to_node(j); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (to_node == NUMA_NO_NODE) 2298c2ecf20Sopenharmony_ci continue; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci numa_set_distance(from_node, to_node, 2328c2ecf20Sopenharmony_ci slit->entry[slit->locality_count * i + j]); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * Default callback for parsing of the Proximity Domain <-> Memory 2398c2ecf20Sopenharmony_ci * Area mappings 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ciint __init 2428c2ecf20Sopenharmony_ciacpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci u64 start, end; 2458c2ecf20Sopenharmony_ci u32 hotpluggable; 2468c2ecf20Sopenharmony_ci int node, pxm; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (srat_disabled()) 2498c2ecf20Sopenharmony_ci goto out_err; 2508c2ecf20Sopenharmony_ci if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) { 2518c2ecf20Sopenharmony_ci pr_err("SRAT: Unexpected header length: %d\n", 2528c2ecf20Sopenharmony_ci ma->header.length); 2538c2ecf20Sopenharmony_ci goto out_err_bad_srat; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) 2568c2ecf20Sopenharmony_ci goto out_err; 2578c2ecf20Sopenharmony_ci hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; 2588c2ecf20Sopenharmony_ci if (hotpluggable && !IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) 2598c2ecf20Sopenharmony_ci goto out_err; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci start = ma->base_address; 2628c2ecf20Sopenharmony_ci end = start + ma->length; 2638c2ecf20Sopenharmony_ci pxm = ma->proximity_domain; 2648c2ecf20Sopenharmony_ci if (acpi_srat_revision <= 1) 2658c2ecf20Sopenharmony_ci pxm &= 0xff; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci node = acpi_map_pxm_to_node(pxm); 2688c2ecf20Sopenharmony_ci if (node == NUMA_NO_NODE) { 2698c2ecf20Sopenharmony_ci pr_err("SRAT: Too many proximity domains.\n"); 2708c2ecf20Sopenharmony_ci goto out_err_bad_srat; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (numa_add_memblk(node, start, end) < 0) { 2748c2ecf20Sopenharmony_ci pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]\n", 2758c2ecf20Sopenharmony_ci node, (unsigned long long) start, 2768c2ecf20Sopenharmony_ci (unsigned long long) end - 1); 2778c2ecf20Sopenharmony_ci goto out_err_bad_srat; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci node_set(node, numa_nodes_parsed); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n", 2838c2ecf20Sopenharmony_ci node, pxm, 2848c2ecf20Sopenharmony_ci (unsigned long long) start, (unsigned long long) end - 1, 2858c2ecf20Sopenharmony_ci hotpluggable ? " hotplug" : "", 2868c2ecf20Sopenharmony_ci ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : ""); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Mark hotplug range in memblock. */ 2898c2ecf20Sopenharmony_ci if (hotpluggable && memblock_mark_hotplug(start, ma->length)) 2908c2ecf20Sopenharmony_ci pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", 2918c2ecf20Sopenharmony_ci (unsigned long long)start, (unsigned long long)end - 1); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1)); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ciout_err_bad_srat: 2978c2ecf20Sopenharmony_ci bad_srat(); 2988c2ecf20Sopenharmony_ciout_err: 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int __init acpi_parse_slit(struct acpi_table_header *table) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct acpi_table_slit *slit = (struct acpi_table_slit *)table; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!slit_valid(slit)) { 3088c2ecf20Sopenharmony_ci pr_info("SLIT table looks invalid. Not used.\n"); 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci acpi_numa_slit_init(slit); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_civoid __init __weak 3178c2ecf20Sopenharmony_ciacpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci pr_warn("Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int __init 3238c2ecf20Sopenharmony_ciacpi_parse_x2apic_affinity(union acpi_subtable_headers *header, 3248c2ecf20Sopenharmony_ci const unsigned long end) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct acpi_srat_x2apic_cpu_affinity *processor_affinity; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci acpi_table_print_srat_entry(&header->common); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* let architecture-dependent part to do it */ 3338c2ecf20Sopenharmony_ci acpi_numa_x2apic_affinity_init(processor_affinity); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int __init 3398c2ecf20Sopenharmony_ciacpi_parse_processor_affinity(union acpi_subtable_headers *header, 3408c2ecf20Sopenharmony_ci const unsigned long end) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct acpi_srat_cpu_affinity *processor_affinity; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci processor_affinity = (struct acpi_srat_cpu_affinity *)header; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci acpi_table_print_srat_entry(&header->common); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* let architecture-dependent part to do it */ 3498c2ecf20Sopenharmony_ci acpi_numa_processor_affinity_init(processor_affinity); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int __init 3558c2ecf20Sopenharmony_ciacpi_parse_gicc_affinity(union acpi_subtable_headers *header, 3568c2ecf20Sopenharmony_ci const unsigned long end) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct acpi_srat_gicc_affinity *processor_affinity; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci processor_affinity = (struct acpi_srat_gicc_affinity *)header; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci acpi_table_print_srat_entry(&header->common); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* let architecture-dependent part to do it */ 3658c2ecf20Sopenharmony_ci acpi_numa_gicc_affinity_init(processor_affinity); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci#if defined(CONFIG_X86) || defined(CONFIG_ARM64) 3718c2ecf20Sopenharmony_cistatic int __init 3728c2ecf20Sopenharmony_ciacpi_parse_gi_affinity(union acpi_subtable_headers *header, 3738c2ecf20Sopenharmony_ci const unsigned long end) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct acpi_srat_generic_affinity *gi_affinity; 3768c2ecf20Sopenharmony_ci int node; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci gi_affinity = (struct acpi_srat_generic_affinity *)header; 3798c2ecf20Sopenharmony_ci if (!gi_affinity) 3808c2ecf20Sopenharmony_ci return -EINVAL; 3818c2ecf20Sopenharmony_ci acpi_table_print_srat_entry(&header->common); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (!(gi_affinity->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED)) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci node = acpi_map_pxm_to_node(gi_affinity->proximity_domain); 3878c2ecf20Sopenharmony_ci if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { 3888c2ecf20Sopenharmony_ci pr_err("SRAT: Too many proximity domains.\n"); 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci node_set(node, numa_nodes_parsed); 3928c2ecf20Sopenharmony_ci node_set_state(node, N_GENERIC_INITIATOR); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci#else 3978c2ecf20Sopenharmony_cistatic int __init 3988c2ecf20Sopenharmony_ciacpi_parse_gi_affinity(union acpi_subtable_headers *header, 3998c2ecf20Sopenharmony_ci const unsigned long end) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int __initdata parsed_numa_memblks; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int __init 4088c2ecf20Sopenharmony_ciacpi_parse_memory_affinity(union acpi_subtable_headers * header, 4098c2ecf20Sopenharmony_ci const unsigned long end) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct acpi_srat_mem_affinity *memory_affinity; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci memory_affinity = (struct acpi_srat_mem_affinity *)header; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci acpi_table_print_srat_entry(&header->common); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* let architecture-dependent part to do it */ 4188c2ecf20Sopenharmony_ci if (!acpi_numa_memory_affinity_init(memory_affinity)) 4198c2ecf20Sopenharmony_ci parsed_numa_memblks++; 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int __init acpi_parse_srat(struct acpi_table_header *table) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct acpi_table_srat *srat = (struct acpi_table_srat *)table; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci acpi_srat_revision = srat->header.revision; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Real work done in acpi_table_parse_srat below. */ 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int __init 4358c2ecf20Sopenharmony_ciacpi_table_parse_srat(enum acpi_srat_type id, 4368c2ecf20Sopenharmony_ci acpi_tbl_entry_handler handler, unsigned int max_entries) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci return acpi_table_parse_entries(ACPI_SIG_SRAT, 4398c2ecf20Sopenharmony_ci sizeof(struct acpi_table_srat), id, 4408c2ecf20Sopenharmony_ci handler, max_entries); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciint __init acpi_numa_init(void) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci int cnt = 0; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (acpi_disabled) 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* 4518c2ecf20Sopenharmony_ci * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= 4528c2ecf20Sopenharmony_ci * SRAT cpu entries could have different order with that in MADT. 4538c2ecf20Sopenharmony_ci * So go over all cpu entries in SRAT to get apicid to node mapping. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* SRAT: System Resource Affinity Table */ 4578c2ecf20Sopenharmony_ci if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { 4588c2ecf20Sopenharmony_ci struct acpi_subtable_proc srat_proc[4]; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci memset(srat_proc, 0, sizeof(srat_proc)); 4618c2ecf20Sopenharmony_ci srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY; 4628c2ecf20Sopenharmony_ci srat_proc[0].handler = acpi_parse_processor_affinity; 4638c2ecf20Sopenharmony_ci srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY; 4648c2ecf20Sopenharmony_ci srat_proc[1].handler = acpi_parse_x2apic_affinity; 4658c2ecf20Sopenharmony_ci srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY; 4668c2ecf20Sopenharmony_ci srat_proc[2].handler = acpi_parse_gicc_affinity; 4678c2ecf20Sopenharmony_ci srat_proc[3].id = ACPI_SRAT_TYPE_GENERIC_AFFINITY; 4688c2ecf20Sopenharmony_ci srat_proc[3].handler = acpi_parse_gi_affinity; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci acpi_table_parse_entries_array(ACPI_SIG_SRAT, 4718c2ecf20Sopenharmony_ci sizeof(struct acpi_table_srat), 4728c2ecf20Sopenharmony_ci srat_proc, ARRAY_SIZE(srat_proc), 0); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, 4758c2ecf20Sopenharmony_ci acpi_parse_memory_affinity, 0); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* SLIT: System Locality Information Table */ 4798c2ecf20Sopenharmony_ci acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (cnt < 0) 4828c2ecf20Sopenharmony_ci return cnt; 4838c2ecf20Sopenharmony_ci else if (!parsed_numa_memblks) 4848c2ecf20Sopenharmony_ci return -ENOENT; 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int acpi_get_pxm(acpi_handle h) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci unsigned long long pxm; 4918c2ecf20Sopenharmony_ci acpi_status status; 4928c2ecf20Sopenharmony_ci acpi_handle handle; 4938c2ecf20Sopenharmony_ci acpi_handle phandle = h; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci do { 4968c2ecf20Sopenharmony_ci handle = phandle; 4978c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); 4988c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 4998c2ecf20Sopenharmony_ci return pxm; 5008c2ecf20Sopenharmony_ci status = acpi_get_parent(handle, &phandle); 5018c2ecf20Sopenharmony_ci } while (ACPI_SUCCESS(status)); 5028c2ecf20Sopenharmony_ci return -1; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ciint acpi_get_node(acpi_handle handle) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci int pxm; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci pxm = acpi_get_pxm(handle); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return pxm_to_node(pxm); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_get_node); 514