1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * ACPI 3.0 based NUMA setup |
4 | * Copyright 2004 Andi Kleen, SuSE Labs. |
5 | * |
6 | * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. |
7 | * |
8 | * Called from acpi_numa_init while reading the SRAT and SLIT tables. |
9 | * Assumes all memory regions belonging to a single proximity domain |
10 | * are in one chunk. Holes between them will be included in the node. |
11 | */ |
12 | |
13 | #include <linux/kernel.h> |
14 | #include <linux/acpi.h> |
15 | #include <linux/mmzone.h> |
16 | #include <linux/bitmap.h> |
17 | #include <linux/init.h> |
18 | #include <linux/topology.h> |
19 | #include <linux/mm.h> |
20 | #include <asm/proto.h> |
21 | #include <asm/numa.h> |
22 | #include <asm/e820/api.h> |
23 | #include <asm/apic.h> |
24 | #include <asm/uv/uv.h> |
25 | |
26 | /* Callback for Proximity Domain -> x2APIC mapping */ |
27 | void __init |
28 | acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) |
29 | { |
30 | int pxm, node; |
31 | int apic_id; |
32 | |
33 | if (srat_disabled()) |
34 | return; |
35 | if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { |
36 | bad_srat(); |
37 | return; |
38 | } |
39 | if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) |
40 | return; |
41 | pxm = pa->proximity_domain; |
42 | apic_id = pa->apic_id; |
43 | if (!apic_id_valid(apic_id)) { |
44 | pr_info("SRAT: PXM %u -> X2APIC 0x%04x ignored\n" , pxm, apic_id); |
45 | return; |
46 | } |
47 | node = acpi_map_pxm_to_node(pxm); |
48 | if (node < 0) { |
49 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n" , pxm); |
50 | bad_srat(); |
51 | return; |
52 | } |
53 | |
54 | if (apic_id >= MAX_LOCAL_APIC) { |
55 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n" , pxm, apic_id, node); |
56 | return; |
57 | } |
58 | set_apicid_to_node(apicid: apic_id, node); |
59 | node_set(node, numa_nodes_parsed); |
60 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n" , |
61 | pxm, apic_id, node); |
62 | } |
63 | |
64 | /* Callback for Proximity Domain -> LAPIC mapping */ |
65 | void __init |
66 | acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) |
67 | { |
68 | int pxm, node; |
69 | int apic_id; |
70 | |
71 | if (srat_disabled()) |
72 | return; |
73 | if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { |
74 | bad_srat(); |
75 | return; |
76 | } |
77 | if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) |
78 | return; |
79 | pxm = pa->proximity_domain_lo; |
80 | if (acpi_srat_revision >= 2) |
81 | pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; |
82 | node = acpi_map_pxm_to_node(pxm); |
83 | if (node < 0) { |
84 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n" , pxm); |
85 | bad_srat(); |
86 | return; |
87 | } |
88 | |
89 | if (get_uv_system_type() >= UV_X2APIC) |
90 | apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; |
91 | else |
92 | apic_id = pa->apic_id; |
93 | |
94 | if (apic_id >= MAX_LOCAL_APIC) { |
95 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n" , pxm, apic_id, node); |
96 | return; |
97 | } |
98 | |
99 | set_apicid_to_node(apicid: apic_id, node); |
100 | node_set(node, numa_nodes_parsed); |
101 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n" , |
102 | pxm, apic_id, node); |
103 | } |
104 | |
105 | int __init x86_acpi_numa_init(void) |
106 | { |
107 | int ret; |
108 | |
109 | ret = acpi_numa_init(); |
110 | if (ret < 0) |
111 | return ret; |
112 | return srat_disabled() ? -EINVAL : 0; |
113 | } |
114 | |