blob: 5c0637e4c2f4353e6c51161a7f94b5a257a57389 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Andi Kleen68a3a7f2006-04-07 19:49:18 +020018#include <linux/bootmem.h>
19#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/proto.h>
21#include <asm/numa.h>
Andi Kleen8a6fdd32006-01-11 22:44:39 +010022#include <asm/e820.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Andi Kleenc31fbb12006-09-26 10:52:33 +020024int acpi_numa __initdata;
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026static struct acpi_table_slit *acpi_slit;
27
28static nodemask_t nodes_parsed __initdata;
Andi Kleenabe059e2006-03-25 16:29:12 +010029static struct bootnode nodes[MAX_NUMNODES] __initdata;
Keith Mannthey4942e992006-09-30 23:27:06 -070030static struct bootnode nodes_add[MAX_NUMNODES];
Andi Kleen68a3a7f2006-04-07 19:49:18 +020031static int found_add_area __initdata;
Andi Kleenfad79062006-05-15 18:19:44 +020032int hotadd_percent __initdata = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Andi Kleen9391a3f2006-02-03 21:51:17 +010034/* Too small nodes confuse the VM badly. Usually they result
35 from BIOS bugs. */
36#define NODE_MIN_SIZE (4*1024*1024)
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static __init int setup_node(int pxm)
39{
Yasunori Goto762834e2006-06-23 02:03:19 -070040 return acpi_map_pxm_to_node(pxm);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041}
42
43static __init int conflicting_nodes(unsigned long start, unsigned long end)
44{
45 int i;
Andi Kleen4b6a4552005-09-12 18:49:25 +020046 for_each_node_mask(i, nodes_parsed) {
Andi Kleenabe059e2006-03-25 16:29:12 +010047 struct bootnode *nd = &nodes[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 if (nd->start == nd->end)
49 continue;
50 if (nd->end > start && nd->start < end)
Andi Kleen05d1fa42005-09-12 18:49:24 +020051 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 if (nd->end == end && nd->start == start)
Andi Kleen05d1fa42005-09-12 18:49:24 +020053 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 }
55 return -1;
56}
57
58static __init void cutoff_node(int i, unsigned long start, unsigned long end)
59{
Andi Kleenabe059e2006-03-25 16:29:12 +010060 struct bootnode *nd = &nodes[i];
Andi Kleen68a3a7f2006-04-07 19:49:18 +020061
62 if (found_add_area)
63 return;
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 if (nd->start < start) {
66 nd->start = start;
67 if (nd->end < nd->start)
68 nd->start = nd->end;
69 }
70 if (nd->end > end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 nd->end = end;
72 if (nd->start > nd->end)
73 nd->start = nd->end;
74 }
75}
76
77static __init void bad_srat(void)
78{
Andi Kleen2bce2b52005-09-12 18:49:25 +020079 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 printk(KERN_ERR "SRAT: SRAT not used.\n");
81 acpi_numa = -1;
Andi Kleenfad79062006-05-15 18:19:44 +020082 found_add_area = 0;
Andi Kleen2bce2b52005-09-12 18:49:25 +020083 for (i = 0; i < MAX_LOCAL_APIC; i++)
84 apicid_to_node[i] = NUMA_NO_NODE;
Andi Kleen68a3a7f2006-04-07 19:49:18 +020085 for (i = 0; i < MAX_NUMNODES; i++)
86 nodes_add[i].start = nodes[i].end = 0;
Mel Gorman5cb248a2006-09-27 01:49:52 -070087 remove_all_active_ranges();
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
90static __init inline int srat_disabled(void)
91{
92 return numa_off || acpi_numa < 0;
93}
94
Andi Kleen1584b892006-01-11 22:43:42 +010095/*
96 * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
97 * up the NUMA heuristics which wants the local node to have a smaller
98 * distance than the others.
99 * Do some quick checks here and only use the SLIT if it passes.
100 */
101static __init int slit_valid(struct acpi_table_slit *slit)
102{
103 int i, j;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300104 int d = slit->locality_count;
Andi Kleen1584b892006-01-11 22:43:42 +0100105 for (i = 0; i < d; i++) {
106 for (j = 0; j < d; j++) {
107 u8 val = slit->entry[d*i + j];
108 if (i == j) {
David Rientjesa2e212d2007-07-21 17:09:55 +0200109 if (val != LOCAL_DISTANCE)
Andi Kleen1584b892006-01-11 22:43:42 +0100110 return 0;
David Rientjesa2e212d2007-07-21 17:09:55 +0200111 } else if (val <= LOCAL_DISTANCE)
Andi Kleen1584b892006-01-11 22:43:42 +0100112 return 0;
113 }
114 }
115 return 1;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/* Callback for SLIT parsing */
119void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
120{
Andi Kleen1584b892006-01-11 22:43:42 +0100121 if (!slit_valid(slit)) {
122 printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
123 return;
124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 acpi_slit = slit;
126}
127
128/* Callback for Proximity Domain -> LAPIC mapping */
129void __init
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300130acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 int pxm, node;
Andi Kleend22fe802006-02-03 21:51:26 +0100133 if (srat_disabled())
134 return;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300135 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
Andi Kleenfad79062006-05-15 18:19:44 +0200136 bad_srat();
Andi Kleend22fe802006-02-03 21:51:26 +0100137 return;
138 }
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300139 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300141 pxm = pa->proximity_domain_lo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 node = setup_node(pxm);
143 if (node < 0) {
144 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
145 bad_srat();
146 return;
147 }
Andi Kleen0b07e982005-09-12 18:49:24 +0200148 apicid_to_node[pa->apic_id] = node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 acpi_numa = 1;
Andi Kleen0b07e982005-09-12 18:49:24 +0200150 printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
151 pxm, pa->apic_id, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
keith mannthey926fafe2006-10-21 18:37:01 +0200154int update_end_of_memory(unsigned long end) {return -1;}
Keith Mannthey71efa8f2006-09-30 23:27:05 -0700155static int hotadd_enough_memory(struct bootnode *nd) {return 1;}
156#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
157static inline int save_add_info(void) {return 1;}
158#else
159static inline int save_add_info(void) {return 0;}
160#endif
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200161/*
Keith Mannthey71efa8f2006-09-30 23:27:05 -0700162 * Update nodes_add and decide if to include add are in the zone.
Joe Perchesab4a5742008-01-30 13:31:42 +0100163 * Both SPARSE and RESERVE need nodes_add information.
Simon Arlott676b1852007-10-20 01:25:36 +0200164 * This code supports one contiguous hot add area per node.
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200165 */
166static int reserve_hotadd(int node, unsigned long start, unsigned long end)
167{
168 unsigned long s_pfn = start >> PAGE_SHIFT;
169 unsigned long e_pfn = end >> PAGE_SHIFT;
Keith Mannthey71efa8f2006-09-30 23:27:05 -0700170 int ret = 0, changed = 0;
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200171 struct bootnode *nd = &nodes_add[node];
172
173 /* I had some trouble with strange memory hotadd regions breaking
174 the boot. Be very strict here and reject anything unexpected.
175 If you want working memory hotadd write correct SRATs.
176
177 The node size check is a basic sanity check to guard against
178 mistakes */
179 if ((signed long)(end - start) < NODE_MIN_SIZE) {
180 printk(KERN_ERR "SRAT: Hotplug area too small\n");
181 return -1;
182 }
183
184 /* This check might be a bit too strict, but I'm keeping it for now. */
Mel Gorman5cb248a2006-09-27 01:49:52 -0700185 if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
Mel Gorman9c7cd682006-09-27 01:49:58 -0700186 printk(KERN_ERR
187 "SRAT: Hotplug area %lu -> %lu has existing memory\n",
188 s_pfn, e_pfn);
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200189 return -1;
190 }
191
192 if (!hotadd_enough_memory(&nodes_add[node])) {
193 printk(KERN_ERR "SRAT: Hotplug area too large\n");
194 return -1;
195 }
196
197 /* Looks good */
198
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200199 if (nd->start == nd->end) {
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300200 nd->start = start;
201 nd->end = end;
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200202 changed = 1;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300203 } else {
204 if (nd->start == end) {
205 nd->start = start;
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200206 changed = 1;
207 }
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300208 if (nd->end == start) {
209 nd->end = end;
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200210 changed = 1;
211 }
212 if (!changed)
213 printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300214 }
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200215
Keith Mannthey71efa8f2006-09-30 23:27:05 -0700216 ret = update_end_of_memory(nd->end);
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200217
218 if (changed)
219 printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end);
Keith Mannthey71efa8f2006-09-30 23:27:05 -0700220 return ret;
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200221}
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
224void __init
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300225acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200227 struct bootnode *nd, oldnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 unsigned long start, end;
229 int node, pxm;
230 int i;
231
Andi Kleend22fe802006-02-03 21:51:26 +0100232 if (srat_disabled())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 return;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300234 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
Andi Kleend22fe802006-02-03 21:51:26 +0100235 bad_srat();
236 return;
237 }
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300238 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
Andi Kleend22fe802006-02-03 21:51:26 +0100239 return;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300240
241 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200242 return;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300243 start = ma->base_address;
244 end = start + ma->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 pxm = ma->proximity_domain;
246 node = setup_node(pxm);
247 if (node < 0) {
248 printk(KERN_ERR "SRAT: Too many proximity domains.\n");
249 bad_srat();
250 return;
251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 i = conflicting_nodes(start, end);
Andi Kleen05d1fa42005-09-12 18:49:24 +0200253 if (i == node) {
254 printk(KERN_WARNING
255 "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n",
256 pxm, start, end, nodes[i].start, nodes[i].end);
257 } else if (i >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 printk(KERN_ERR
Andi Kleen05d1fa42005-09-12 18:49:24 +0200259 "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n",
260 pxm, start, end, node_to_pxm(i),
261 nodes[i].start, nodes[i].end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 bad_srat();
263 return;
264 }
265 nd = &nodes[node];
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200266 oldnode = *nd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 if (!node_test_and_set(node, nodes_parsed)) {
268 nd->start = start;
269 nd->end = end;
270 } else {
271 if (start < nd->start)
272 nd->start = start;
273 if (nd->end < end)
274 nd->end = end;
275 }
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
278 nd->start, nd->end);
Mel Gorman5cb248a2006-09-27 01:49:52 -0700279 e820_register_active_regions(node, nd->start >> PAGE_SHIFT,
280 nd->end >> PAGE_SHIFT);
Mel Gormanfb014392006-09-27 01:49:59 -0700281 push_node_boundaries(node, nd->start >> PAGE_SHIFT,
282 nd->end >> PAGE_SHIFT);
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200283
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300284 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
285 (reserve_hotadd(node, start, end) < 0)) {
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200286 /* Ignore hotadd region. Undo damage */
287 printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
288 *nd = oldnode;
289 if ((nd->start | nd->end) == 0)
290 node_clear(node, nodes_parsed);
291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100294/* Sanity check to catch more bad SRATs (they are amazingly common).
295 Make sure the PXMs cover all memory. */
David Rientjes3484d792007-07-21 17:10:32 +0200296static int __init nodes_cover_memory(const struct bootnode *nodes)
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100297{
298 int i;
299 unsigned long pxmram, e820ram;
300
301 pxmram = 0;
302 for_each_node_mask(i, nodes_parsed) {
303 unsigned long s = nodes[i].start >> PAGE_SHIFT;
304 unsigned long e = nodes[i].end >> PAGE_SHIFT;
305 pxmram += e - s;
Mel Gorman5cb248a2006-09-27 01:49:52 -0700306 pxmram -= absent_pages_in_range(s, e);
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200307 if ((long)pxmram < 0)
308 pxmram = 0;
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100309 }
310
Mel Gorman5cb248a2006-09-27 01:49:52 -0700311 e820ram = end_pfn - absent_pages_in_range(0, end_pfn);
Andi Kleenfdb9df92006-02-16 23:42:13 +0100312 /* We seem to lose 3 pages somewhere. Allow a bit of slack. */
313 if ((long)(e820ram - pxmram) >= 1*1024*1024) {
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100314 printk(KERN_ERR
315 "SRAT: PXMs only cover %luMB of your %luMB e820 RAM. Not used.\n",
316 (pxmram << PAGE_SHIFT) >> 20,
317 (e820ram << PAGE_SHIFT) >> 20);
318 return 0;
319 }
320 return 1;
321}
322
Andi Kleen9391a3f2006-02-03 21:51:17 +0100323static void unparse_node(int node)
324{
325 int i;
326 node_clear(node, nodes_parsed);
327 for (i = 0; i < MAX_LOCAL_APIC; i++) {
328 if (apicid_to_node[i] == node)
329 apicid_to_node[i] = NUMA_NO_NODE;
330 }
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333void __init acpi_numa_arch_fixup(void) {}
334
335/* Use the information discovered above to actually set up the nodes. */
336int __init acpi_scan_nodes(unsigned long start, unsigned long end)
337{
338 int i;
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100339
David Rientjesae2c6dc2007-07-21 17:09:56 +0200340 if (acpi_numa <= 0)
341 return -1;
342
Andi Kleen9391a3f2006-02-03 21:51:17 +0100343 /* First clean up the node list */
344 for (i = 0; i < MAX_NUMNODES; i++) {
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300345 cutoff_node(i, start, end);
Daniel Yeisley0d015322006-05-30 22:47:57 +0200346 if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) {
Andi Kleen9391a3f2006-02-03 21:51:17 +0100347 unparse_node(i);
Daniel Yeisley0d015322006-05-30 22:47:57 +0200348 node_set_offline(i);
349 }
Andi Kleen9391a3f2006-02-03 21:51:17 +0100350 }
351
David Rientjes3484d792007-07-21 17:10:32 +0200352 if (!nodes_cover_memory(nodes)) {
Andi Kleen8a6fdd32006-01-11 22:44:39 +0100353 bad_srat();
354 return -1;
355 }
356
Andi Kleen2aed7112006-02-16 23:42:16 +0100357 memnode_shift = compute_hash_shift(nodes, MAX_NUMNODES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (memnode_shift < 0) {
359 printk(KERN_ERR
360 "SRAT: No NUMA node hash function found. Contact maintainer\n");
361 bad_srat();
362 return -1;
363 }
Andi Kleene58e0d02005-09-12 18:49:25 +0200364
Suresh Siddhae3f1cae2007-05-02 19:27:20 +0200365 node_possible_map = nodes_parsed;
366
Andi Kleene58e0d02005-09-12 18:49:25 +0200367 /* Finally register nodes */
Suresh Siddhae3f1cae2007-05-02 19:27:20 +0200368 for_each_node_mask(i, node_possible_map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 setup_node_bootmem(i, nodes[i].start, nodes[i].end);
Andi Kleena8062232006-04-07 19:49:21 +0200370 /* Try again in case setup_node_bootmem missed one due
371 to missing bootmem */
Suresh Siddhae3f1cae2007-05-02 19:27:20 +0200372 for_each_node_mask(i, node_possible_map)
Andi Kleena8062232006-04-07 19:49:21 +0200373 if (!node_online(i))
374 setup_node_bootmem(i, nodes[i].start, nodes[i].end);
375
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300376 for (i = 0; i < NR_CPUS; i++) {
Mike Travis98c9e272007-10-17 18:04:39 +0200377 if (cpu_to_node(i) == NUMA_NO_NODE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 continue;
Mike Travis98c9e272007-10-17 18:04:39 +0200379 if (!node_isset(cpu_to_node(i), node_possible_map))
Andi Kleen69d81fc2005-11-05 17:25:53 +0100380 numa_set_node(i, NUMA_NO_NODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
382 numa_init_array();
383 return 0;
384}
385
David Rientjes3484d792007-07-21 17:10:32 +0200386#ifdef CONFIG_NUMA_EMU
387static int __init find_node_by_addr(unsigned long addr)
388{
389 int ret = NUMA_NO_NODE;
390 int i;
391
392 for_each_node_mask(i, nodes_parsed) {
393 /*
394 * Find the real node that this emulated node appears on. For
395 * the sake of simplicity, we only use a real node's starting
396 * address to determine which emulated node it appears on.
397 */
398 if (addr >= nodes[i].start && addr < nodes[i].end) {
399 ret = i;
400 break;
401 }
402 }
403 return i;
404}
405
406/*
407 * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
408 * mappings that respect the real ACPI topology but reflect our emulated
409 * environment. For each emulated node, we find which real node it appears on
410 * and create PXM to NID mappings for those fake nodes which mirror that
411 * locality. SLIT will now represent the correct distances between emulated
412 * nodes as a result of the real topology.
413 */
414void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
415{
David Rientjes08705b82007-07-21 17:10:33 +0200416 int i, j;
David Rientjes3484d792007-07-21 17:10:32 +0200417 int fake_node_to_pxm_map[MAX_NUMNODES] = {
418 [0 ... MAX_NUMNODES-1] = PXM_INVAL
419 };
David Rientjes08705b82007-07-21 17:10:33 +0200420 unsigned char fake_apicid_to_node[MAX_LOCAL_APIC] = {
421 [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
422 };
David Rientjes3484d792007-07-21 17:10:32 +0200423
424 printk(KERN_INFO "Faking PXM affinity for fake nodes on real "
425 "topology.\n");
426 for (i = 0; i < num_nodes; i++) {
427 int nid, pxm;
428
429 nid = find_node_by_addr(fake_nodes[i].start);
430 if (nid == NUMA_NO_NODE)
431 continue;
432 pxm = node_to_pxm(nid);
433 if (pxm == PXM_INVAL)
434 continue;
435 fake_node_to_pxm_map[i] = pxm;
David Rientjes08705b82007-07-21 17:10:33 +0200436 /*
437 * For each apicid_to_node mapping that exists for this real
438 * node, it must now point to the fake node ID.
439 */
440 for (j = 0; j < MAX_LOCAL_APIC; j++)
441 if (apicid_to_node[j] == nid)
442 fake_apicid_to_node[j] = i;
David Rientjes3484d792007-07-21 17:10:32 +0200443 }
444 for (i = 0; i < num_nodes; i++)
445 __acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
David Rientjes08705b82007-07-21 17:10:33 +0200446 memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
David Rientjes3484d792007-07-21 17:10:32 +0200447
448 nodes_clear(nodes_parsed);
449 for (i = 0; i < num_nodes; i++)
450 if (fake_nodes[i].start != fake_nodes[i].end)
451 node_set(i, nodes_parsed);
452 WARN_ON(!nodes_cover_memory(fake_nodes));
453}
454
455static int null_slit_node_compare(int a, int b)
456{
457 return node_to_pxm(a) == node_to_pxm(b);
458}
459#else
460static int null_slit_node_compare(int a, int b)
461{
462 return a == b;
463}
464#endif /* CONFIG_NUMA_EMU */
465
Andi Kleen68a3a7f2006-04-07 19:49:18 +0200466void __init srat_reserve_add_area(int nodeid)
467{
468 if (found_add_area && nodes_add[nodeid].end) {
469 u64 total_mb;
470
471 printk(KERN_INFO "SRAT: Reserving hot-add memory space "
472 "for node %d at %Lx-%Lx\n",
473 nodeid, nodes_add[nodeid].start, nodes_add[nodeid].end);
474 total_mb = (nodes_add[nodeid].end - nodes_add[nodeid].start)
475 >> PAGE_SHIFT;
476 total_mb *= sizeof(struct page);
477 total_mb >>= 20;
478 printk(KERN_INFO "SRAT: This will cost you %Lu MB of "
479 "pre-allocated memory.\n", (unsigned long long)total_mb);
480 reserve_bootmem_node(NODE_DATA(nodeid), nodes_add[nodeid].start,
481 nodes_add[nodeid].end - nodes_add[nodeid].start);
482 }
483}
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485int __node_distance(int a, int b)
486{
487 int index;
488
489 if (!acpi_slit)
David Rientjes3484d792007-07-21 17:10:32 +0200490 return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
491 REMOTE_DISTANCE;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300492 index = acpi_slit->locality_count * node_to_pxm(a);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return acpi_slit->entry[index + node_to_pxm(b)];
494}
495
496EXPORT_SYMBOL(__node_distance);
Keith Mannthey4942e992006-09-30 23:27:06 -0700497
498int memory_add_physaddr_to_nid(u64 start)
499{
500 int i, ret = 0;
501
502 for_each_node(i)
503 if (nodes_add[i].start <= start && nodes_add[i].end > start)
504 ret = i;
505
506 return ret;
507}
Keith Mannthey8c2676a2006-09-30 23:27:07 -0700508EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
509