aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/mm/srat.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/mm/srat.c')
-rw-r--r--arch/x86_64/mm/srat.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
new file mode 100644
index 000000000000..5d01b31472e1
--- /dev/null
+++ b/arch/x86_64/mm/srat.c
@@ -0,0 +1,217 @@
1/*
2 * ACPI 3.0 based NUMA setup
3 * Copyright 2004 Andi Kleen, SuSE Labs.
4 *
5 * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
6 *
7 * Called from acpi_numa_init while reading the SRAT and SLIT tables.
8 * Assumes all memory regions belonging to a single proximity domain
9 * are in one chunk. Holes between them will be included in the node.
10 */
11
12#include <linux/kernel.h>
13#include <linux/acpi.h>
14#include <linux/mmzone.h>
15#include <linux/bitmap.h>
16#include <linux/module.h>
17#include <linux/topology.h>
18#include <asm/proto.h>
19#include <asm/numa.h>
20
21static struct acpi_table_slit *acpi_slit;
22
23static nodemask_t nodes_parsed __initdata;
24static nodemask_t nodes_found __initdata;
25static struct node nodes[MAX_NUMNODES] __initdata;
26static __u8 pxm2node[256] = { [0 ... 255] = 0xff };
27
28static __init int setup_node(int pxm)
29{
30 unsigned node = pxm2node[pxm];
31 if (node == 0xff) {
32 if (nodes_weight(nodes_found) >= MAX_NUMNODES)
33 return -1;
34 node = first_unset_node(nodes_found);
35 node_set(node, nodes_found);
36 pxm2node[pxm] = node;
37 }
38 return pxm2node[pxm];
39}
40
41static __init int conflicting_nodes(unsigned long start, unsigned long end)
42{
43 int i;
44 for_each_online_node(i) {
45 struct node *nd = &nodes[i];
46 if (nd->start == nd->end)
47 continue;
48 if (nd->end > start && nd->start < end)
49 return 1;
50 if (nd->end == end && nd->start == start)
51 return 1;
52 }
53 return -1;
54}
55
56static __init void cutoff_node(int i, unsigned long start, unsigned long end)
57{
58 struct node *nd = &nodes[i];
59 if (nd->start < start) {
60 nd->start = start;
61 if (nd->end < nd->start)
62 nd->start = nd->end;
63 }
64 if (nd->end > end) {
65 if (!(end & 0xfff))
66 end--;
67 nd->end = end;
68 if (nd->start > nd->end)
69 nd->start = nd->end;
70 }
71}
72
73static __init void bad_srat(void)
74{
75 printk(KERN_ERR "SRAT: SRAT not used.\n");
76 acpi_numa = -1;
77}
78
79static __init inline int srat_disabled(void)
80{
81 return numa_off || acpi_numa < 0;
82}
83
84/* Callback for SLIT parsing */
85void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
86{
87 acpi_slit = slit;
88}
89
90/* Callback for Proximity Domain -> LAPIC mapping */
91void __init
92acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
93{
94 int pxm, node;
95 if (srat_disabled() || pa->flags.enabled == 0)
96 return;
97 pxm = pa->proximity_domain;
98 node = setup_node(pxm);
99 if (node < 0) {
100 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
101 bad_srat();
102 return;
103 }
104 if (pa->apic_id >= NR_CPUS) {
105 printk(KERN_ERR "SRAT: lapic %u too large.\n",
106 pa->apic_id);
107 bad_srat();
108 return;
109 }
110 cpu_to_node[pa->apic_id] = node;
111 acpi_numa = 1;
112 printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
113 pxm, pa->apic_id, node);
114}
115
116/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
117void __init
118acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
119{
120 struct node *nd;
121 unsigned long start, end;
122 int node, pxm;
123 int i;
124
125 if (srat_disabled() || ma->flags.enabled == 0)
126 return;
127 /* hotplug bit is ignored for now */
128 pxm = ma->proximity_domain;
129 node = setup_node(pxm);
130 if (node < 0) {
131 printk(KERN_ERR "SRAT: Too many proximity domains.\n");
132 bad_srat();
133 return;
134 }
135 start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
136 end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
137 i = conflicting_nodes(start, end);
138 if (i >= 0) {
139 printk(KERN_ERR
140 "SRAT: pxm %d overlap %lx-%lx with node %d(%Lx-%Lx)\n",
141 pxm, start, end, i, nodes[i].start, nodes[i].end);
142 bad_srat();
143 return;
144 }
145 nd = &nodes[node];
146 if (!node_test_and_set(node, nodes_parsed)) {
147 nd->start = start;
148 nd->end = end;
149 } else {
150 if (start < nd->start)
151 nd->start = start;
152 if (nd->end < end)
153 nd->end = end;
154 }
155 if (!(nd->end & 0xfff))
156 nd->end--;
157 printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
158 nd->start, nd->end);
159}
160
161void __init acpi_numa_arch_fixup(void) {}
162
163/* Use the information discovered above to actually set up the nodes. */
164int __init acpi_scan_nodes(unsigned long start, unsigned long end)
165{
166 int i;
167 if (acpi_numa <= 0)
168 return -1;
169 memnode_shift = compute_hash_shift(nodes, nodes_weight(nodes_parsed));
170 if (memnode_shift < 0) {
171 printk(KERN_ERR
172 "SRAT: No NUMA node hash function found. Contact maintainer\n");
173 bad_srat();
174 return -1;
175 }
176 for (i = 0; i < MAX_NUMNODES; i++) {
177 if (!node_isset(i, nodes_parsed))
178 continue;
179 cutoff_node(i, start, end);
180 if (nodes[i].start == nodes[i].end) {
181 node_clear(i, nodes_parsed);
182 continue;
183 }
184 setup_node_bootmem(i, nodes[i].start, nodes[i].end);
185 }
186 for (i = 0; i < NR_CPUS; i++) {
187 if (cpu_to_node[i] == NUMA_NO_NODE)
188 continue;
189 if (!node_isset(cpu_to_node[i], nodes_parsed))
190 cpu_to_node[i] = NUMA_NO_NODE;
191 }
192 numa_init_array();
193 return 0;
194}
195
196int node_to_pxm(int n)
197{
198 int i;
199 if (pxm2node[n] == n)
200 return n;
201 for (i = 0; i < 256; i++)
202 if (pxm2node[i] == n)
203 return i;
204 return 0;
205}
206
207int __node_distance(int a, int b)
208{
209 int index;
210
211 if (!acpi_slit)
212 return a == b ? 10 : 20;
213 index = acpi_slit->localities * node_to_pxm(a);
214 return acpi_slit->entry[index + node_to_pxm(b)];
215}
216
217EXPORT_SYMBOL(__node_distance);