Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/acpi/numa.c
15109 views
1
/*
2
* acpi_numa.c - ACPI NUMA support
3
*
4
* Copyright (C) 2002 Takayoshi Kochi <[email protected]>
5
*
6
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*
22
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23
*
24
*/
25
#include <linux/module.h>
26
#include <linux/init.h>
27
#include <linux/kernel.h>
28
#include <linux/types.h>
29
#include <linux/errno.h>
30
#include <linux/acpi.h>
31
#include <linux/numa.h>
32
#include <acpi/acpi_bus.h>
33
34
#define PREFIX "ACPI: "
35
36
#define ACPI_NUMA 0x80000000
37
#define _COMPONENT ACPI_NUMA
38
ACPI_MODULE_NAME("numa");
39
40
static nodemask_t nodes_found_map = NODE_MASK_NONE;
41
42
/* maps to convert between proximity domain and logical node ID */
43
static int pxm_to_node_map[MAX_PXM_DOMAINS]
44
= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
45
static int node_to_pxm_map[MAX_NUMNODES]
46
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
47
48
int pxm_to_node(int pxm)
49
{
50
if (pxm < 0)
51
return NUMA_NO_NODE;
52
return pxm_to_node_map[pxm];
53
}
54
55
int node_to_pxm(int node)
56
{
57
if (node < 0)
58
return PXM_INVAL;
59
return node_to_pxm_map[node];
60
}
61
62
void __acpi_map_pxm_to_node(int pxm, int node)
63
{
64
if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
65
pxm_to_node_map[pxm] = node;
66
if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
67
node_to_pxm_map[node] = pxm;
68
}
69
70
int acpi_map_pxm_to_node(int pxm)
71
{
72
int node = pxm_to_node_map[pxm];
73
74
if (node < 0) {
75
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
76
return NUMA_NO_NODE;
77
node = first_unset_node(nodes_found_map);
78
__acpi_map_pxm_to_node(pxm, node);
79
node_set(node, nodes_found_map);
80
}
81
82
return node;
83
}
84
85
static void __init
86
acpi_table_print_srat_entry(struct acpi_subtable_header *header)
87
{
88
89
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
90
91
if (!header)
92
return;
93
94
switch (header->type) {
95
96
case ACPI_SRAT_TYPE_CPU_AFFINITY:
97
#ifdef ACPI_DEBUG_OUTPUT
98
{
99
struct acpi_srat_cpu_affinity *p =
100
(struct acpi_srat_cpu_affinity *)header;
101
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
102
"SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
103
p->apic_id, p->local_sapic_eid,
104
p->proximity_domain_lo,
105
(p->flags & ACPI_SRAT_CPU_ENABLED)?
106
"enabled" : "disabled"));
107
}
108
#endif /* ACPI_DEBUG_OUTPUT */
109
break;
110
111
case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
112
#ifdef ACPI_DEBUG_OUTPUT
113
{
114
struct acpi_srat_mem_affinity *p =
115
(struct acpi_srat_mem_affinity *)header;
116
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
117
"SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n",
118
(unsigned long)p->base_address,
119
(unsigned long)p->length,
120
p->proximity_domain,
121
(p->flags & ACPI_SRAT_MEM_ENABLED)?
122
"enabled" : "disabled",
123
(p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
124
" hot-pluggable" : ""));
125
}
126
#endif /* ACPI_DEBUG_OUTPUT */
127
break;
128
129
case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
130
#ifdef ACPI_DEBUG_OUTPUT
131
{
132
struct acpi_srat_x2apic_cpu_affinity *p =
133
(struct acpi_srat_x2apic_cpu_affinity *)header;
134
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
135
"SRAT Processor (x2apicid[0x%08x]) in"
136
" proximity domain %d %s\n",
137
p->apic_id,
138
p->proximity_domain,
139
(p->flags & ACPI_SRAT_CPU_ENABLED) ?
140
"enabled" : "disabled"));
141
}
142
#endif /* ACPI_DEBUG_OUTPUT */
143
break;
144
default:
145
printk(KERN_WARNING PREFIX
146
"Found unsupported SRAT entry (type = 0x%x)\n",
147
header->type);
148
break;
149
}
150
}
151
152
/*
153
* A lot of BIOS fill in 10 (= no distance) everywhere. This messes
154
* up the NUMA heuristics which wants the local node to have a smaller
155
* distance than the others.
156
* Do some quick checks here and only use the SLIT if it passes.
157
*/
158
static __init int slit_valid(struct acpi_table_slit *slit)
159
{
160
int i, j;
161
int d = slit->locality_count;
162
for (i = 0; i < d; i++) {
163
for (j = 0; j < d; j++) {
164
u8 val = slit->entry[d*i + j];
165
if (i == j) {
166
if (val != LOCAL_DISTANCE)
167
return 0;
168
} else if (val <= LOCAL_DISTANCE)
169
return 0;
170
}
171
}
172
return 1;
173
}
174
175
static int __init acpi_parse_slit(struct acpi_table_header *table)
176
{
177
struct acpi_table_slit *slit;
178
179
if (!table)
180
return -EINVAL;
181
182
slit = (struct acpi_table_slit *)table;
183
184
if (!slit_valid(slit)) {
185
printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
186
return -EINVAL;
187
}
188
acpi_numa_slit_init(slit);
189
190
return 0;
191
}
192
193
void __init __attribute__ ((weak))
194
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
195
{
196
printk(KERN_WARNING PREFIX
197
"Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
198
return;
199
}
200
201
202
static int __init
203
acpi_parse_x2apic_affinity(struct acpi_subtable_header *header,
204
const unsigned long end)
205
{
206
struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
207
208
processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
209
if (!processor_affinity)
210
return -EINVAL;
211
212
acpi_table_print_srat_entry(header);
213
214
/* let architecture-dependent part to do it */
215
acpi_numa_x2apic_affinity_init(processor_affinity);
216
217
return 0;
218
}
219
220
static int __init
221
acpi_parse_processor_affinity(struct acpi_subtable_header *header,
222
const unsigned long end)
223
{
224
struct acpi_srat_cpu_affinity *processor_affinity;
225
226
processor_affinity = (struct acpi_srat_cpu_affinity *)header;
227
if (!processor_affinity)
228
return -EINVAL;
229
230
acpi_table_print_srat_entry(header);
231
232
/* let architecture-dependent part to do it */
233
acpi_numa_processor_affinity_init(processor_affinity);
234
235
return 0;
236
}
237
238
static int __init
239
acpi_parse_memory_affinity(struct acpi_subtable_header * header,
240
const unsigned long end)
241
{
242
struct acpi_srat_mem_affinity *memory_affinity;
243
244
memory_affinity = (struct acpi_srat_mem_affinity *)header;
245
if (!memory_affinity)
246
return -EINVAL;
247
248
acpi_table_print_srat_entry(header);
249
250
/* let architecture-dependent part to do it */
251
acpi_numa_memory_affinity_init(memory_affinity);
252
253
return 0;
254
}
255
256
static int __init acpi_parse_srat(struct acpi_table_header *table)
257
{
258
if (!table)
259
return -EINVAL;
260
261
/* Real work done in acpi_table_parse_srat below. */
262
263
return 0;
264
}
265
266
static int __init
267
acpi_table_parse_srat(enum acpi_srat_type id,
268
acpi_table_entry_handler handler, unsigned int max_entries)
269
{
270
return acpi_table_parse_entries(ACPI_SIG_SRAT,
271
sizeof(struct acpi_table_srat), id,
272
handler, max_entries);
273
}
274
275
int __init acpi_numa_init(void)
276
{
277
int cnt = 0;
278
279
/*
280
* Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
281
* SRAT cpu entries could have different order with that in MADT.
282
* So go over all cpu entries in SRAT to get apicid to node mapping.
283
*/
284
285
/* SRAT: Static Resource Affinity Table */
286
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
287
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
288
acpi_parse_x2apic_affinity, 0);
289
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
290
acpi_parse_processor_affinity, 0);
291
cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
292
acpi_parse_memory_affinity,
293
NR_NODE_MEMBLKS);
294
}
295
296
/* SLIT: System Locality Information Table */
297
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
298
299
acpi_numa_arch_fixup();
300
301
if (cnt <= 0)
302
return cnt ?: -ENOENT;
303
return 0;
304
}
305
306
int acpi_get_pxm(acpi_handle h)
307
{
308
unsigned long long pxm;
309
acpi_status status;
310
acpi_handle handle;
311
acpi_handle phandle = h;
312
313
do {
314
handle = phandle;
315
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
316
if (ACPI_SUCCESS(status))
317
return pxm;
318
status = acpi_get_parent(handle, &phandle);
319
} while (ACPI_SUCCESS(status));
320
return -1;
321
}
322
323
int acpi_get_node(acpi_handle *handle)
324
{
325
int pxm, node = -1;
326
327
pxm = acpi_get_pxm(handle);
328
if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
329
node = acpi_map_pxm_to_node(pxm);
330
331
return node;
332
}
333
EXPORT_SYMBOL(acpi_get_node);
334
335