Blame view

drivers/acpi/numa.c 12.2 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
  /*
   *  acpi_numa.c - ACPI NUMA support
   *
   *  Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   */
ac906a6d5   Hanjun Guo   ACPI / NUMA: Use ...
7
8
  
  #define pr_fmt(fmt) "ACPI: " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/acpi.h>
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
15
  #include <linux/memblock.h>
b552a8c56   David Rientjes   ACPI: remove NID_...
16
  #include <linux/numa.h>
99759869f   Toshi Kani   acpi: Add acpi_ma...
17
18
  #include <linux/nodemask.h>
  #include <linux/topology.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

762834e8b   Yasunori Goto   [PATCH] Unify pxm...
20
  static nodemask_t nodes_found_map = NODE_MASK_NONE;
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
21
22
  
  /* maps to convert between proximity domain and logical node ID */
ffada8913   Jan Beulich   ACPI: fix modpost...
23
  static int pxm_to_node_map[MAX_PXM_DOMAINS]
b552a8c56   David Rientjes   ACPI: remove NID_...
24
  			= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
ffada8913   Jan Beulich   ACPI: fix modpost...
25
  static int node_to_pxm_map[MAX_NUMNODES]
b552a8c56   David Rientjes   ACPI: remove NID_...
26
  			= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
27

8df0eb7c9   Kurt Garloff   ACPI: Store SRAT ...
28
  unsigned char acpi_srat_revision __initdata;
e84025e27   David Daney   ACPI / NUMA: move...
29
  int acpi_numa __initdata;
8df0eb7c9   Kurt Garloff   ACPI: Store SRAT ...
30

f363d16fb   Aaron Durbin   acpi: fix potenti...
31
  int pxm_to_node(int pxm)
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
32
33
  {
  	if (pxm < 0)
b552a8c56   David Rientjes   ACPI: remove NID_...
34
  		return NUMA_NO_NODE;
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
35
36
  	return pxm_to_node_map[pxm];
  }
f363d16fb   Aaron Durbin   acpi: fix potenti...
37
  int node_to_pxm(int node)
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
38
39
40
41
42
  {
  	if (node < 0)
  		return PXM_INVAL;
  	return node_to_pxm_map[node];
  }
d79ed248d   Bjorn Helgaas   ACPI / numa: Make...
43
  static void __acpi_map_pxm_to_node(int pxm, int node)
3484d7981   David Rientjes   x86_64: fake pxm-...
44
  {
0f9b75ef3   David Rientjes   ACPI: NUMA: map p...
45
46
47
48
  	if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
  		pxm_to_node_map[pxm] = node;
  	if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
  		node_to_pxm_map[node] = pxm;
3484d7981   David Rientjes   x86_64: fake pxm-...
49
  }
8ff6f48d9   Tony Luck   ACPI: Section mis...
50
  int acpi_map_pxm_to_node(int pxm)
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
51
  {
99759869f   Toshi Kani   acpi: Add acpi_ma...
52
  	int node;
aec03f89e   Boris Ostrovsky   ACPI/NUMA: Do not...
53
  	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
99759869f   Toshi Kani   acpi: Add acpi_ma...
54
55
56
  		return NUMA_NO_NODE;
  
  	node = pxm_to_node_map[pxm];
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
57

1bb25df0f   Jianguo Wu   ACPI / mm: use NU...
58
  	if (node == NUMA_NO_NODE) {
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
59
  		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
b552a8c56   David Rientjes   ACPI: remove NID_...
60
  			return NUMA_NO_NODE;
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
61
  		node = first_unset_node(nodes_found_map);
3484d7981   David Rientjes   x86_64: fake pxm-...
62
  		__acpi_map_pxm_to_node(pxm, node);
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
63
64
65
66
67
  		node_set(node, nodes_found_map);
  	}
  
  	return node;
  }
8fc5c7355   Dan Williams   acpi/nfit, device...
68
  EXPORT_SYMBOL(acpi_map_pxm_to_node);
762834e8b   Yasunori Goto   [PATCH] Unify pxm...
69

99759869f   Toshi Kani   acpi: Add acpi_ma...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  /**
   * acpi_map_pxm_to_online_node - Map proximity ID to online node
   * @pxm: ACPI proximity ID
   *
   * This is similar to acpi_map_pxm_to_node(), but always returns an online
   * node.  When the mapped node from a given proximity ID is offline, it
   * looks up the node distance table and returns the nearest online node.
   *
   * ACPI device drivers, which are called after the NUMA initialization has
   * completed in the kernel, can call this interface to obtain their device
   * NUMA topology from ACPI tables.  Such drivers do not have to deal with
   * offline nodes.  A node may be offline when a device proximity ID is
   * unique, SRAT memory entry does not exist, or NUMA is disabled, ex.
   * "numa=off" on x86.
   */
  int acpi_map_pxm_to_online_node(int pxm)
  {
dc9e0a934   Dan Williams   acpi, numa: fix p...
87
  	int node, min_node;
99759869f   Toshi Kani   acpi: Add acpi_ma...
88
89
90
91
92
  
  	node = acpi_map_pxm_to_node(pxm);
  
  	if (node == NUMA_NO_NODE)
  		node = 0;
dc9e0a934   Dan Williams   acpi, numa: fix p...
93
  	min_node = node;
99759869f   Toshi Kani   acpi: Add acpi_ma...
94
  	if (!node_online(node)) {
dc9e0a934   Dan Williams   acpi, numa: fix p...
95
  		int min_dist = INT_MAX, dist, n;
99759869f   Toshi Kani   acpi: Add acpi_ma...
96
97
98
99
  		for_each_online_node(n) {
  			dist = node_distance(node, n);
  			if (dist < min_dist) {
  				min_dist = dist;
dc9e0a934   Dan Williams   acpi, numa: fix p...
100
  				min_node = n;
99759869f   Toshi Kani   acpi: Add acpi_ma...
101
102
103
  			}
  		}
  	}
dc9e0a934   Dan Williams   acpi, numa: fix p...
104
  	return min_node;
99759869f   Toshi Kani   acpi: Add acpi_ma...
105
106
  }
  EXPORT_SYMBOL(acpi_map_pxm_to_online_node);
ae2c6dcf9   David Rientjes   x86_64: various c...
107
108
  static void __init
  acpi_table_print_srat_entry(struct acpi_subtable_header *header)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  	switch (header->type) {
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
111
  	case ACPI_SRAT_TYPE_CPU_AFFINITY:
4be44fcd3   Len Brown   [ACPI] Lindent al...
112
  		{
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
113
114
  			struct acpi_srat_cpu_affinity *p =
  			    (struct acpi_srat_cpu_affinity *)header;
3dda44818   Hanjun Guo   ACPI / NUMA: Repl...
115
116
117
118
119
120
  			pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s
  ",
  				 p->apic_id, p->local_sapic_eid,
  				 p->proximity_domain_lo,
  				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
  				 "enabled" : "disabled");
4be44fcd3   Len Brown   [ACPI] Lindent al...
121
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  		break;
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
123
  	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
4be44fcd3   Len Brown   [ACPI] Lindent al...
124
  		{
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
125
126
  			struct acpi_srat_mem_affinity *p =
  			    (struct acpi_srat_mem_affinity *)header;
b9ced18ac   Chao Fan   ACPI: NUMA: Use c...
127
128
129
130
  			pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s
  ",
  				 (unsigned long long)p->base_address,
  				 (unsigned long long)p->length,
3dda44818   Hanjun Guo   ACPI / NUMA: Repl...
131
132
133
134
135
136
137
  				 p->proximity_domain,
  				 (p->flags & ACPI_SRAT_MEM_ENABLED) ?
  				 "enabled" : "disabled",
  				 (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
  				 " hot-pluggable" : "",
  				 (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ?
  				 " non-volatile" : "");
4be44fcd3   Len Brown   [ACPI] Lindent al...
138
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  		break;
7237d3de7   Suresh Siddha   x86, ACPI: add su...
140
  	case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
7237d3de7   Suresh Siddha   x86, ACPI: add su...
141
142
143
  		{
  			struct acpi_srat_x2apic_cpu_affinity *p =
  			    (struct acpi_srat_x2apic_cpu_affinity *)header;
3dda44818   Hanjun Guo   ACPI / NUMA: Repl...
144
145
146
147
148
149
  			pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s
  ",
  				 p->apic_id,
  				 p->proximity_domain,
  				 (p->flags & ACPI_SRAT_CPU_ENABLED) ?
  				 "enabled" : "disabled");
7237d3de7   Suresh Siddha   x86, ACPI: add su...
150
  		}
7237d3de7   Suresh Siddha   x86, ACPI: add su...
151
  		break;
3dda44818   Hanjun Guo   ACPI / NUMA: Repl...
152

4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
153
154
155
156
157
158
159
160
161
162
163
164
  	case ACPI_SRAT_TYPE_GICC_AFFINITY:
  		{
  			struct acpi_srat_gicc_affinity *p =
  			    (struct acpi_srat_gicc_affinity *)header;
  			pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s
  ",
  				 p->acpi_processor_uid,
  				 p->proximity_domain,
  				 (p->flags & ACPI_SRAT_GICC_ENABLED) ?
  				 "enabled" : "disabled");
  		}
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	default:
ac906a6d5   Hanjun Guo   ACPI / NUMA: Use ...
166
167
168
  		pr_warn("Found unsupported SRAT entry (type = 0x%x)
  ",
  			header->type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
  		break;
  	}
  }
39b8931b5   Fenghua Yu   ACPI: handle inva...
172
173
174
175
176
177
  /*
   * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
   * up the NUMA heuristics which wants the local node to have a smaller
   * distance than the others.
   * Do some quick checks here and only use the SLIT if it passes.
   */
40e318563   Hanjun Guo   ACPI / numa: Fix ...
178
  static int __init slit_valid(struct acpi_table_slit *slit)
39b8931b5   Fenghua Yu   ACPI: handle inva...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  {
  	int i, j;
  	int d = slit->locality_count;
  	for (i = 0; i < d; i++) {
  		for (j = 0; j < d; j++)  {
  			u8 val = slit->entry[d*i + j];
  			if (i == j) {
  				if (val != LOCAL_DISTANCE)
  					return 0;
  			} else if (val <= LOCAL_DISTANCE)
  				return 0;
  		}
  	}
  	return 1;
  }
e84025e27   David Daney   ACPI / NUMA: move...
194
195
196
197
198
199
200
201
202
203
204
  void __init bad_srat(void)
  {
  	pr_err("SRAT: SRAT not used.
  ");
  	acpi_numa = -1;
  }
  
  int __init srat_disabled(void)
  {
  	return acpi_numa < 0;
  }
6525afdf5   Hanjun Guo   ACPI / NUMA: move...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  #if defined(CONFIG_X86) || defined(CONFIG_ARM64)
  /*
   * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
   * I/O localities since SRAT does not list them.  I/O localities are
   * not supported at this point.
   */
  void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
  {
  	int i, j;
  
  	for (i = 0; i < slit->locality_count; i++) {
  		const int from_node = pxm_to_node(i);
  
  		if (from_node == NUMA_NO_NODE)
  			continue;
  
  		for (j = 0; j < slit->locality_count; j++) {
  			const int to_node = pxm_to_node(j);
  
  			if (to_node == NUMA_NO_NODE)
  				continue;
  
  			numa_set_distance(from_node, to_node,
  				slit->entry[slit->locality_count * i + j]);
  		}
  	}
  }
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  
  /*
   * Default callback for parsing of the Proximity Domain <-> Memory
   * Area mappings
   */
  int __init
  acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
  {
  	u64 start, end;
  	u32 hotpluggable;
  	int node, pxm;
  
  	if (srat_disabled())
  		goto out_err;
e0af261a4   David Daney   ACPI / NUMA: Impr...
246
247
248
249
  	if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) {
  		pr_err("SRAT: Unexpected header length: %d
  ",
  		       ma->header.length);
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
250
  		goto out_err_bad_srat;
e0af261a4   David Daney   ACPI / NUMA: Impr...
251
  	}
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
252
253
254
255
256
257
258
259
260
261
262
263
264
  	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
  		goto out_err;
  	hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
  	if (hotpluggable && !IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
  		goto out_err;
  
  	start = ma->base_address;
  	end = start + ma->length;
  	pxm = ma->proximity_domain;
  	if (acpi_srat_revision <= 1)
  		pxm &= 0xff;
  
  	node = acpi_map_pxm_to_node(pxm);
e0af261a4   David Daney   ACPI / NUMA: Impr...
265
266
267
  	if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
  		pr_err("SRAT: Too many proximity domains.
  ");
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
268
269
  		goto out_err_bad_srat;
  	}
e0af261a4   David Daney   ACPI / NUMA: Impr...
270
271
272
273
274
  	if (numa_add_memblk(node, start, end) < 0) {
  		pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]
  ",
  		       node, (unsigned long long) start,
  		       (unsigned long long) end - 1);
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
275
  		goto out_err_bad_srat;
e0af261a4   David Daney   ACPI / NUMA: Impr...
276
  	}
3770442e7   Hanjun Guo   ACPI / NUMA: Move...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  
  	node_set(node, numa_nodes_parsed);
  
  	pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s
  ",
  		node, pxm,
  		(unsigned long long) start, (unsigned long long) end - 1,
  		hotpluggable ? " hotplug" : "",
  		ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : "");
  
  	/* Mark hotplug range in memblock. */
  	if (hotpluggable && memblock_mark_hotplug(start, ma->length))
  		pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock
  ",
  			(unsigned long long)start, (unsigned long long)end - 1);
  
  	max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
  
  	return 0;
  out_err_bad_srat:
  	bad_srat();
  out_err:
  	return -EINVAL;
  }
6525afdf5   Hanjun Guo   ACPI / NUMA: move...
301
  #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
302
  static int __init acpi_parse_slit(struct acpi_table_header *table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  {
2fad93083   Hanjun Guo   ACPI / table: rem...
304
  	struct acpi_table_slit *slit = (struct acpi_table_slit *)table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

39b8931b5   Fenghua Yu   ACPI: handle inva...
306
  	if (!slit_valid(slit)) {
ac906a6d5   Hanjun Guo   ACPI / NUMA: Use ...
307
308
  		pr_info("SLIT table looks invalid. Not used.
  ");
39b8931b5   Fenghua Yu   ACPI: handle inva...
309
310
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
  	acpi_numa_slit_init(slit);
  
  	return 0;
  }
beffbe54f   Bjorn Helgaas   ACPI / numa: Use ...
315
  void __init __weak
7237d3de7   Suresh Siddha   x86, ACPI: add su...
316
317
  acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
  {
ac906a6d5   Hanjun Guo   ACPI / NUMA: Use ...
318
319
  	pr_warn("Found unsupported x2apic [0x%08x] SRAT entry
  ", pa->apic_id);
7237d3de7   Suresh Siddha   x86, ACPI: add su...
320
  }
7237d3de7   Suresh Siddha   x86, ACPI: add su...
321
  static int __init
60574d1e0   Keith Busch   acpi: Create subt...
322
  acpi_parse_x2apic_affinity(union acpi_subtable_headers *header,
7237d3de7   Suresh Siddha   x86, ACPI: add su...
323
324
325
326
327
328
329
  			   const unsigned long end)
  {
  	struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
  
  	processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
  	if (!processor_affinity)
  		return -EINVAL;
60574d1e0   Keith Busch   acpi: Create subt...
330
  	acpi_table_print_srat_entry(&header->common);
7237d3de7   Suresh Siddha   x86, ACPI: add su...
331
332
333
334
335
336
  
  	/* let architecture-dependent part to do it */
  	acpi_numa_x2apic_affinity_init(processor_affinity);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  static int __init
60574d1e0   Keith Busch   acpi: Create subt...
338
  acpi_parse_processor_affinity(union acpi_subtable_headers *header,
4be44fcd3   Len Brown   [ACPI] Lindent al...
339
  			      const unsigned long end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  {
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
341
  	struct acpi_srat_cpu_affinity *processor_affinity;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
343
  	processor_affinity = (struct acpi_srat_cpu_affinity *)header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	if (!processor_affinity)
  		return -EINVAL;
60574d1e0   Keith Busch   acpi: Create subt...
346
  	acpi_table_print_srat_entry(&header->common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
351
352
  
  	/* let architecture-dependent part to do it */
  	acpi_numa_processor_affinity_init(processor_affinity);
  
  	return 0;
  }
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
353
  static int __init
60574d1e0   Keith Busch   acpi: Create subt...
354
  acpi_parse_gicc_affinity(union acpi_subtable_headers *header,
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
355
356
357
358
359
360
361
  			 const unsigned long end)
  {
  	struct acpi_srat_gicc_affinity *processor_affinity;
  
  	processor_affinity = (struct acpi_srat_gicc_affinity *)header;
  	if (!processor_affinity)
  		return -EINVAL;
60574d1e0   Keith Busch   acpi: Create subt...
362
  	acpi_table_print_srat_entry(&header->common);
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
363
364
365
366
367
368
  
  	/* let architecture-dependent part to do it */
  	acpi_numa_gicc_affinity_init(processor_affinity);
  
  	return 0;
  }
095adbb64   Thomas Renninger   ACPI: Only count ...
369
  static int __initdata parsed_numa_memblks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  static int __init
60574d1e0   Keith Busch   acpi: Create subt...
371
  acpi_parse_memory_affinity(union acpi_subtable_headers * header,
4be44fcd3   Len Brown   [ACPI] Lindent al...
372
  			   const unsigned long end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  {
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
374
  	struct acpi_srat_mem_affinity *memory_affinity;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
376
  	memory_affinity = (struct acpi_srat_mem_affinity *)header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  	if (!memory_affinity)
  		return -EINVAL;
60574d1e0   Keith Busch   acpi: Create subt...
379
  	acpi_table_print_srat_entry(&header->common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  
  	/* let architecture-dependent part to do it */
095adbb64   Thomas Renninger   ACPI: Only count ...
382
383
  	if (!acpi_numa_memory_affinity_init(memory_affinity))
  		parsed_numa_memblks++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
  	return 0;
  }
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
386
  static int __init acpi_parse_srat(struct acpi_table_header *table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  {
2fad93083   Hanjun Guo   ACPI / table: rem...
388
  	struct acpi_table_srat *srat = (struct acpi_table_srat *)table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389

8df0eb7c9   Kurt Garloff   ACPI: Store SRAT ...
390
  	acpi_srat_revision = srat->header.revision;
cfa806f05   Andi Kleen   gcc-4.6: ACPI: fi...
391
  	/* Real work done in acpi_table_parse_srat below. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
  
  	return 0;
  }
ae2c6dcf9   David Rientjes   x86_64: various c...
395
  static int __init
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
396
  acpi_table_parse_srat(enum acpi_srat_type id,
b43e1065c   Lv Zheng   ACPICA: Cleanup t...
397
  		      acpi_tbl_entry_handler handler, unsigned int max_entries)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  {
6eb87fed5   Len Brown   ACPI: acpi_table_...
399
  	return acpi_table_parse_entries(ACPI_SIG_SRAT,
4be44fcd3   Len Brown   [ACPI] Lindent al...
400
401
  					    sizeof(struct acpi_table_srat), id,
  					    handler, max_entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  }
20e6926dc   Yinghai Lu   x86, ACPI, mm: Re...
403
  int __init acpi_numa_init(void)
e8d195525   Tang Chen   acpi, memory-hotp...
404
  {
20e6926dc   Yinghai Lu   x86, ACPI, mm: Re...
405
  	int cnt = 0;
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
406
407
  	if (acpi_disabled)
  		return -EINVAL;
d3bd05882   Yinghai Lu   x86, acpi: Parse ...
408
409
410
411
412
  	/*
  	 * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
  	 * SRAT cpu entries could have different order with that in MADT.
  	 * So go over all cpu entries in SRAT to get apicid to node mapping.
  	 */
8716273ca   David Rientjes   x86: Export srat ...
413

02cb489be   Ross Zwisler   ACPI: NUMA: Fix t...
414
  	/* SRAT: System Resource Affinity Table */
7f8f97c3c   Len Brown   ACPI: acpi_table_...
415
  	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
416
  		struct acpi_subtable_proc srat_proc[3];
702b07fcc   Lukasz Anaczkowski   ACPI / SRAT: fix ...
417
418
419
420
421
422
  
  		memset(srat_proc, 0, sizeof(srat_proc));
  		srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
  		srat_proc[0].handler = acpi_parse_processor_affinity;
  		srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
  		srat_proc[1].handler = acpi_parse_x2apic_affinity;
4bac6fa73   Hanjun Guo   ACPI / NUMA: Enab...
423
424
  		srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY;
  		srat_proc[2].handler = acpi_parse_gicc_affinity;
702b07fcc   Lukasz Anaczkowski   ACPI / SRAT: fix ...
425
426
427
428
  
  		acpi_table_parse_entries_array(ACPI_SIG_SRAT,
  					sizeof(struct acpi_table_srat),
  					srat_proc, ARRAY_SIZE(srat_proc), 0);
20e6926dc   Yinghai Lu   x86, ACPI, mm: Re...
429
  		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
fd3e45436   Ganapatrao Kulkarni   ACPI / NUMA: ia64...
430
  					    acpi_parse_memory_affinity, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
  	}
  
  	/* SLIT: System Locality Information Table */
7f8f97c3c   Len Brown   ACPI: acpi_table_...
434
  	acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435

20e6926dc   Yinghai Lu   x86, ACPI, mm: Re...
436
437
  	if (cnt < 0)
  		return cnt;
095adbb64   Thomas Renninger   ACPI: Only count ...
438
  	else if (!parsed_numa_memblks)
f3946fb6e   Thomas Renninger   ACPI: Untangle a ...
439
  		return -ENOENT;
940fed2e7   Tejun Heo   x86-64, NUMA: Uni...
440
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  }
d79ed248d   Bjorn Helgaas   ACPI / numa: Make...
442
  static int acpi_get_pxm(acpi_handle h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  {
27663c585   Matthew Wilcox   ACPI: Change acpi...
444
  	unsigned long long pxm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
  	acpi_status status;
  	acpi_handle handle;
  	acpi_handle phandle = h;
  
  	do {
  		handle = phandle;
  		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
  		if (ACPI_SUCCESS(status))
50dd09697   Jan Engelhardt   ACPI: Remove unne...
453
  			return pxm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  		status = acpi_get_parent(handle, &phandle);
4be44fcd3   Len Brown   [ACPI] Lindent al...
455
  	} while (ACPI_SUCCESS(status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  	return -1;
  }
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
458

486c79b50   Bjorn Helgaas   ACPI / numa: Fix ...
459
  int acpi_get_node(acpi_handle handle)
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
460
  {
962fe9c91   Bjorn Helgaas   ACPI / numa: Simp...
461
  	int pxm;
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
462

1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
463
  	pxm = acpi_get_pxm(handle);
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
464

962fe9c91   Bjorn Helgaas   ACPI / numa: Simp...
465
  	return acpi_map_pxm_to_node(pxm);
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
466
467
  }
  EXPORT_SYMBOL(acpi_get_node);