Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ACPI 5.1 based NUMA setup for ARM64
0004  * Lots of code was borrowed from arch/x86/mm/srat.c
0005  *
0006  * Copyright 2004 Andi Kleen, SuSE Labs.
0007  * Copyright (C) 2013-2016, Linaro Ltd.
0008  *      Author: Hanjun Guo <hanjun.guo@linaro.org>
0009  *
0010  * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
0011  *
0012  * Called from acpi_numa_init while reading the SRAT and SLIT tables.
0013  * Assumes all memory regions belonging to a single proximity domain
0014  * are in one chunk. Holes between them will be included in the node.
0015  */
0016 
0017 #define pr_fmt(fmt) "ACPI: NUMA: " fmt
0018 
0019 #include <linux/acpi.h>
0020 #include <linux/bitmap.h>
0021 #include <linux/kernel.h>
0022 #include <linux/mm.h>
0023 #include <linux/memblock.h>
0024 #include <linux/mmzone.h>
0025 #include <linux/module.h>
0026 #include <linux/topology.h>
0027 
0028 #include <asm/numa.h>
0029 
0030 static int acpi_early_node_map[NR_CPUS] __initdata = { NUMA_NO_NODE };
0031 
0032 int __init acpi_numa_get_nid(unsigned int cpu)
0033 {
0034     return acpi_early_node_map[cpu];
0035 }
0036 
0037 static inline int get_cpu_for_acpi_id(u32 uid)
0038 {
0039     int cpu;
0040 
0041     for (cpu = 0; cpu < nr_cpu_ids; cpu++)
0042         if (uid == get_acpi_id_for_cpu(cpu))
0043             return cpu;
0044 
0045     return -EINVAL;
0046 }
0047 
0048 static int __init acpi_parse_gicc_pxm(union acpi_subtable_headers *header,
0049                       const unsigned long end)
0050 {
0051     struct acpi_srat_gicc_affinity *pa;
0052     int cpu, pxm, node;
0053 
0054     if (srat_disabled())
0055         return -EINVAL;
0056 
0057     pa = (struct acpi_srat_gicc_affinity *)header;
0058     if (!pa)
0059         return -EINVAL;
0060 
0061     if (!(pa->flags & ACPI_SRAT_GICC_ENABLED))
0062         return 0;
0063 
0064     pxm = pa->proximity_domain;
0065     node = pxm_to_node(pxm);
0066 
0067     /*
0068      * If we can't map the UID to a logical cpu this
0069      * means that the UID is not part of possible cpus
0070      * so we do not need a NUMA mapping for it, skip
0071      * the SRAT entry and keep parsing.
0072      */
0073     cpu = get_cpu_for_acpi_id(pa->acpi_processor_uid);
0074     if (cpu < 0)
0075         return 0;
0076 
0077     acpi_early_node_map[cpu] = node;
0078     pr_info("SRAT: PXM %d -> MPIDR 0x%llx -> Node %d\n", pxm,
0079         cpu_logical_map(cpu), node);
0080 
0081     return 0;
0082 }
0083 
0084 void __init acpi_map_cpus_to_nodes(void)
0085 {
0086     acpi_table_parse_entries(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat),
0087                         ACPI_SRAT_TYPE_GICC_AFFINITY,
0088                         acpi_parse_gicc_pxm, 0);
0089 }
0090 
0091 /* Callback for Proximity Domain -> ACPI processor UID mapping */
0092 void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa)
0093 {
0094     int pxm, node;
0095 
0096     if (srat_disabled())
0097         return;
0098 
0099     if (pa->header.length < sizeof(struct acpi_srat_gicc_affinity)) {
0100         pr_err("SRAT: Invalid SRAT header length: %d\n",
0101             pa->header.length);
0102         bad_srat();
0103         return;
0104     }
0105 
0106     if (!(pa->flags & ACPI_SRAT_GICC_ENABLED))
0107         return;
0108 
0109     pxm = pa->proximity_domain;
0110     node = acpi_map_pxm_to_node(pxm);
0111 
0112     if (node == NUMA_NO_NODE) {
0113         pr_err("SRAT: Too many proximity domains %d\n", pxm);
0114         bad_srat();
0115         return;
0116     }
0117 
0118     node_set(node, numa_nodes_parsed);
0119 }
0120