x86-64, NUMA: Unify emulated distance mapping
[deliverable/linux.git] / arch / x86 / mm / srat_64.c
CommitLineData
1da177e4
LT
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>
68a3a7fe 18#include <linux/bootmem.h>
a9ce6bc1 19#include <linux/memblock.h>
68a3a7fe 20#include <linux/mm.h>
1da177e4
LT
21#include <asm/proto.h>
22#include <asm/numa.h>
8a6fdd3e 23#include <asm/e820.h>
7b6aa335 24#include <asm/apic.h>
4ec71fa2 25#include <asm/uv/uv.h>
1da177e4 26
c31fbb1a
AK
27int acpi_numa __initdata;
28
4942e998 29static struct bootnode nodes_add[MAX_NUMNODES];
1da177e4
LT
30
31static __init int setup_node(int pxm)
32{
762834e8 33 return acpi_map_pxm_to_node(pxm);
1da177e4
LT
34}
35
1da177e4
LT
36static __init void bad_srat(void)
37{
38 printk(KERN_ERR "SRAT: SRAT not used.\n");
39 acpi_numa = -1;
91556237 40 memset(nodes_add, 0, sizeof(nodes_add));
1da177e4
LT
41}
42
43static __init inline int srat_disabled(void)
44{
ffe77a46 45 return acpi_numa < 0;
1da177e4
LT
46}
47
48/* Callback for SLIT parsing */
49void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
50{
ac7136b6 51 int i, j;
f302a5bb 52
ac7136b6
TH
53 for (i = 0; i < slit->locality_count; i++)
54 for (j = 0; j < slit->locality_count; j++)
55 numa_set_distance(pxm_to_node(i), pxm_to_node(j),
56 slit->entry[slit->locality_count * i + j]);
1da177e4
LT
57}
58
7237d3de
SS
59/* Callback for Proximity Domain -> x2APIC mapping */
60void __init
61acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
62{
63 int pxm, node;
64 int apic_id;
65
66 if (srat_disabled())
67 return;
68 if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
69 bad_srat();
70 return;
71 }
72 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
73 return;
74 pxm = pa->proximity_domain;
75 node = setup_node(pxm);
76 if (node < 0) {
77 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
78 bad_srat();
79 return;
80 }
81
82 apic_id = pa->apic_id;
d3bd0588
YL
83 if (apic_id >= MAX_LOCAL_APIC) {
84 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
85 return;
86 }
bbc9e2f4 87 set_apicid_to_node(apic_id, node);
92d4a437 88 node_set(node, numa_nodes_parsed);
7237d3de 89 acpi_numa = 1;
163d3866 90 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
7237d3de
SS
91 pxm, apic_id, node);
92}
93
1da177e4
LT
94/* Callback for Proximity Domain -> LAPIC mapping */
95void __init
15a58ed1 96acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
1da177e4
LT
97{
98 int pxm, node;
ef97001f 99 int apic_id;
100
d22fe808
AK
101 if (srat_disabled())
102 return;
15a58ed1 103 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
fad7906d 104 bad_srat();
d22fe808
AK
105 return;
106 }
15a58ed1 107 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
1da177e4 108 return;
15a58ed1 109 pxm = pa->proximity_domain_lo;
1da177e4
LT
110 node = setup_node(pxm);
111 if (node < 0) {
112 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
113 bad_srat();
114 return;
115 }
beafe91f 116
2e42060c 117 if (get_uv_system_type() >= UV_X2APIC)
a65d1d64
JS
118 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
119 else
120 apic_id = pa->apic_id;
d3bd0588
YL
121
122 if (apic_id >= MAX_LOCAL_APIC) {
123 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
124 return;
125 }
126
bbc9e2f4 127 set_apicid_to_node(apic_id, node);
92d4a437 128 node_set(node, numa_nodes_parsed);
1da177e4 129 acpi_numa = 1;
163d3866 130 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
ef97001f 131 pxm, apic_id, node);
1da177e4
LT
132}
133
71efa8fd
KM
134#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
135static inline int save_add_info(void) {return 1;}
136#else
137static inline int save_add_info(void) {return 0;}
138#endif
68a3a7fe 139/*
888a589f
YL
140 * Update nodes_add[]
141 * This code supports one contiguous hot add area per node
68a3a7fe 142 */
888a589f
YL
143static void __init
144update_nodes_add(int node, unsigned long start, unsigned long end)
68a3a7fe
AK
145{
146 unsigned long s_pfn = start >> PAGE_SHIFT;
147 unsigned long e_pfn = end >> PAGE_SHIFT;
888a589f 148 int changed = 0;
68a3a7fe
AK
149 struct bootnode *nd = &nodes_add[node];
150
151 /* I had some trouble with strange memory hotadd regions breaking
152 the boot. Be very strict here and reject anything unexpected.
153 If you want working memory hotadd write correct SRATs.
154
155 The node size check is a basic sanity check to guard against
156 mistakes */
157 if ((signed long)(end - start) < NODE_MIN_SIZE) {
158 printk(KERN_ERR "SRAT: Hotplug area too small\n");
888a589f 159 return;
68a3a7fe
AK
160 }
161
162 /* This check might be a bit too strict, but I'm keeping it for now. */
5cb248ab 163 if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
9c7cd687
MG
164 printk(KERN_ERR
165 "SRAT: Hotplug area %lu -> %lu has existing memory\n",
166 s_pfn, e_pfn);
888a589f 167 return;
68a3a7fe
AK
168 }
169
170 /* Looks good */
171
68a3a7fe 172 if (nd->start == nd->end) {
15a58ed1
AS
173 nd->start = start;
174 nd->end = end;
68a3a7fe 175 changed = 1;
15a58ed1
AS
176 } else {
177 if (nd->start == end) {
178 nd->start = start;
68a3a7fe
AK
179 changed = 1;
180 }
15a58ed1
AS
181 if (nd->end == start) {
182 nd->end = end;
68a3a7fe
AK
183 changed = 1;
184 }
185 if (!changed)
186 printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
15a58ed1 187 }
68a3a7fe 188
3a5fc0e4 189 if (changed) {
92d4a437 190 node_set(node, numa_nodes_parsed);
888a589f
YL
191 printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
192 nd->start, nd->end);
3a5fc0e4 193 }
68a3a7fe 194}
68a3a7fe 195
1da177e4
LT
196/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
197void __init
15a58ed1 198acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
1da177e4 199{
1da177e4
LT
200 unsigned long start, end;
201 int node, pxm;
1da177e4 202
d22fe808 203 if (srat_disabled())
1da177e4 204 return;
15a58ed1 205 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
d22fe808
AK
206 bad_srat();
207 return;
208 }
15a58ed1 209 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
d22fe808 210 return;
15a58ed1
AS
211
212 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
68a3a7fe 213 return;
15a58ed1
AS
214 start = ma->base_address;
215 end = start + ma->length;
1da177e4
LT
216 pxm = ma->proximity_domain;
217 node = setup_node(pxm);
218 if (node < 0) {
219 printk(KERN_ERR "SRAT: Too many proximity domains.\n");
220 bad_srat();
221 return;
222 }
ef396ec9
TH
223
224 if (numa_add_memblk(node, start, end) < 0) {
1da177e4
LT
225 bad_srat();
226 return;
227 }
68a3a7fe 228
6ec6e0d9
SS
229 printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
230 start, end);
68a3a7fe 231
4697bdcc 232 if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
888a589f 233 update_nodes_add(node, start, end);
1da177e4
LT
234}
235
236void __init acpi_numa_arch_fixup(void) {}
237
a9aec56a
TH
238int __init x86_acpi_numa_init(void)
239{
240 int ret;
241
242 ret = acpi_numa_init();
243 if (ret < 0)
244 return ret;
245 return srat_disabled() ? -EINVAL : 0;
246}
247
6a1673ae 248#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
4942e998
KM
249int memory_add_physaddr_to_nid(u64 start)
250{
251 int i, ret = 0;
252
253 for_each_node(i)
254 if (nodes_add[i].start <= start && nodes_add[i].end > start)
255 ret = i;
256
257 return ret;
258}
8c2676a5 259EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
6a1673ae 260#endif
This page took 0.647783 seconds and 5 git commands to generate.