]> git.proxmox.com Git - mirror_qemu.git/blame - numa.c
numa: Allow setting NUMA distance for different NUMA nodes
[mirror_qemu.git] / numa.c
CommitLineData
96d0e26c
WG
1/*
2 * NUMA parameter parsing routines
3 *
4 * Copyright (c) 2014 Fujitsu Ltd.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
d38ea87a 25#include "qemu/osdep.h"
e35704ba 26#include "sysemu/numa.h"
96d0e26c 27#include "exec/cpu-common.h"
0987d735 28#include "exec/ramlist.h"
96d0e26c
WG
29#include "qemu/bitmap.h"
30#include "qom/cpu.h"
2b631ec2
WG
31#include "qemu/error-report.h"
32#include "include/exec/cpu-common.h" /* for RAM_ADDR_FMT */
0042109a
WG
33#include "qapi-visit.h"
34#include "qapi/opts-visitor.h"
dfabb8b9 35#include "hw/boards.h"
7febe36f 36#include "sysemu/hostmem.h"
76b5d850 37#include "qmp-commands.h"
5b009e40 38#include "hw/mem/pc-dimm.h"
7dcd1d70
EH
39#include "qemu/option.h"
40#include "qemu/config-file.h"
0042109a
WG
41
42QemuOptsList qemu_numa_opts = {
43 .name = "numa",
44 .implied_opt_name = "type",
45 .head = QTAILQ_HEAD_INITIALIZER(qemu_numa_opts.head),
46 .desc = { { 0 } } /* validated with OptsVisitor */
47};
48
7febe36f 49static int have_memdevs = -1;
25712ffe
EH
50static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one.
51 * For all nodes, nodeid < max_numa_nodeid
52 */
de1a7c84 53int nb_numa_nodes;
0f203430 54bool have_numa_distance;
de1a7c84 55NodeInfo numa_info[MAX_NODES];
7febe36f 56
fa9ea81d
BR
57void numa_set_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node)
58{
672558d2 59 struct numa_addr_range *range;
fa9ea81d 60
abafabd8
BR
61 /*
62 * Memory-less nodes can come here with 0 size in which case,
63 * there is nothing to do.
64 */
65 if (!size) {
66 return;
67 }
68
672558d2 69 range = g_malloc0(sizeof(*range));
fa9ea81d
BR
70 range->mem_start = addr;
71 range->mem_end = addr + size - 1;
72 QLIST_INSERT_HEAD(&numa_info[node].addr, range, entry);
73}
74
75void numa_unset_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node)
76{
77 struct numa_addr_range *range, *next;
78
79 QLIST_FOREACH_SAFE(range, &numa_info[node].addr, entry, next) {
80 if (addr == range->mem_start && (addr + size - 1) == range->mem_end) {
81 QLIST_REMOVE(range, entry);
82 g_free(range);
83 return;
84 }
85 }
86}
87
abafabd8
BR
88static void numa_set_mem_ranges(void)
89{
90 int i;
91 ram_addr_t mem_start = 0;
92
93 /*
94 * Deduce start address of each node and use it to store
95 * the address range info in numa_info address range list
96 */
97 for (i = 0; i < nb_numa_nodes; i++) {
98 numa_set_mem_node_id(mem_start, numa_info[i].node_mem, i);
99 mem_start += numa_info[i].node_mem;
100 }
101}
102
e75e2a14
BR
103/*
104 * Check if @addr falls under NUMA @node.
105 */
106static bool numa_addr_belongs_to_node(ram_addr_t addr, uint32_t node)
107{
108 struct numa_addr_range *range;
109
110 QLIST_FOREACH(range, &numa_info[node].addr, entry) {
111 if (addr >= range->mem_start && addr <= range->mem_end) {
112 return true;
113 }
114 }
115 return false;
116}
117
118/*
119 * Given an address, return the index of the NUMA node to which the
120 * address belongs to.
121 */
122uint32_t numa_get_node(ram_addr_t addr, Error **errp)
123{
124 uint32_t i;
125
126 /* For non NUMA configurations, check if the addr falls under node 0 */
127 if (!nb_numa_nodes) {
128 if (numa_addr_belongs_to_node(addr, 0)) {
129 return 0;
130 }
131 }
132
133 for (i = 0; i < nb_numa_nodes; i++) {
134 if (numa_addr_belongs_to_node(addr, i)) {
135 return i;
136 }
137 }
138
139 error_setg(errp, "Address 0x" RAM_ADDR_FMT " doesn't belong to any "
140 "NUMA node", addr);
141 return -1;
142}
143
0f203430 144static void parse_numa_node(NumaNodeOptions *node, QemuOpts *opts, Error **errp)
96d0e26c 145{
0042109a
WG
146 uint16_t nodenr;
147 uint16List *cpus = NULL;
96d0e26c 148
0042109a
WG
149 if (node->has_nodeid) {
150 nodenr = node->nodeid;
96d0e26c 151 } else {
0042109a 152 nodenr = nb_numa_nodes;
96d0e26c
WG
153 }
154
0042109a
WG
155 if (nodenr >= MAX_NODES) {
156 error_setg(errp, "Max number of NUMA nodes reached: %"
01bbbcf4 157 PRIu16 "", nodenr);
0042109a 158 return;
96d0e26c
WG
159 }
160
1945b9d8
EH
161 if (numa_info[nodenr].present) {
162 error_setg(errp, "Duplicate NUMA nodeid: %" PRIu16, nodenr);
163 return;
164 }
165
0042109a 166 for (cpus = node->cpus; cpus; cpus = cpus->next) {
8979c945
EH
167 if (cpus->value >= max_cpus) {
168 error_setg(errp,
169 "CPU index (%" PRIu16 ")"
170 " should be smaller than maxcpus (%d)",
171 cpus->value, max_cpus);
0042109a
WG
172 return;
173 }
174 bitmap_set(numa_info[nodenr].node_cpu, cpus->value, 1);
96d0e26c
WG
175 }
176
7febe36f 177 if (node->has_mem && node->has_memdev) {
01bbbcf4 178 error_setg(errp, "qemu: cannot specify both mem= and memdev=");
7febe36f
PB
179 return;
180 }
181
182 if (have_memdevs == -1) {
183 have_memdevs = node->has_memdev;
184 }
185 if (node->has_memdev != have_memdevs) {
186 error_setg(errp, "qemu: memdev option must be specified for either "
01bbbcf4 187 "all or no nodes");
7febe36f
PB
188 return;
189 }
190
0042109a
WG
191 if (node->has_mem) {
192 uint64_t mem_size = node->mem;
193 const char *mem_str = qemu_opt_get(opts, "mem");
194 /* Fix up legacy suffix-less format */
195 if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) {
196 mem_size <<= 20;
197 }
198 numa_info[nodenr].node_mem = mem_size;
199 }
7febe36f
PB
200 if (node->has_memdev) {
201 Object *o;
202 o = object_resolve_path_type(node->memdev, TYPE_MEMORY_BACKEND, NULL);
203 if (!o) {
204 error_setg(errp, "memdev=%s is ambiguous", node->memdev);
205 return;
206 }
207
208 object_ref(o);
209 numa_info[nodenr].node_mem = object_property_get_int(o, "size", NULL);
210 numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
211 }
1af878e0
EH
212 numa_info[nodenr].present = true;
213 max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
96d0e26c
WG
214}
215
0f203430
HC
216static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
217{
218 uint16_t src = dist->src;
219 uint16_t dst = dist->dst;
220 uint8_t val = dist->val;
221
222 if (src >= MAX_NODES || dst >= MAX_NODES) {
223 error_setg(errp,
224 "Invalid node %" PRIu16
225 ", max possible could be %" PRIu16,
226 MAX(src, dst), MAX_NODES);
227 return;
228 }
229
230 if (!numa_info[src].present || !numa_info[dst].present) {
231 error_setg(errp, "Source/Destination NUMA node is missing. "
232 "Please use '-numa node' option to declare it first.");
233 return;
234 }
235
236 if (val < NUMA_DISTANCE_MIN) {
237 error_setg(errp, "NUMA distance (%" PRIu8 ") is invalid, "
238 "it shouldn't be less than %d.",
239 val, NUMA_DISTANCE_MIN);
240 return;
241 }
242
243 if (src == dst && val != NUMA_DISTANCE_MIN) {
244 error_setg(errp, "Local distance of node %d should be %d.",
245 src, NUMA_DISTANCE_MIN);
246 return;
247 }
248
249 numa_info[src].distance[dst] = val;
250 have_numa_distance = true;
251}
252
28d0de7a 253static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
96d0e26c 254{
0042109a
WG
255 NumaOptions *object = NULL;
256 Error *err = NULL;
96d0e26c 257
0042109a 258 {
09204eac
EB
259 Visitor *v = opts_visitor_new(opts);
260 visit_type_NumaOptions(v, NULL, &object, &err);
261 visit_free(v);
96d0e26c 262 }
96d0e26c 263
0042109a 264 if (err) {
157e94e8 265 goto end;
0042109a 266 }
96d0e26c 267
1fd5d4fe 268 switch (object->type) {
d081a49a 269 case NUMA_OPTIONS_TYPE_NODE:
0f203430 270 parse_numa_node(&object->u.node, opts, &err);
0042109a 271 if (err) {
157e94e8 272 goto end;
96d0e26c 273 }
0042109a
WG
274 nb_numa_nodes++;
275 break;
0f203430
HC
276 case NUMA_OPTIONS_TYPE_DIST:
277 parse_numa_distance(&object->u.dist, &err);
278 if (err) {
279 goto end;
280 }
281 break;
0042109a
WG
282 default:
283 abort();
284 }
96d0e26c 285
157e94e8 286end:
96a1616c 287 qapi_free_NumaOptions(object);
157e94e8
MAL
288 if (err) {
289 error_report_err(err);
290 return -1;
291 }
0042109a 292
157e94e8 293 return 0;
96d0e26c
WG
294}
295
3ef71975
EH
296static char *enumerate_cpus(unsigned long *cpus, int max_cpus)
297{
298 int cpu;
299 bool first = true;
300 GString *s = g_string_new(NULL);
301
302 for (cpu = find_first_bit(cpus, max_cpus);
303 cpu < max_cpus;
304 cpu = find_next_bit(cpus, max_cpus, cpu + 1)) {
305 g_string_append_printf(s, "%s%d", first ? "" : " ", cpu);
306 first = false;
307 }
308 return g_string_free(s, FALSE);
309}
310
311static void validate_numa_cpus(void)
312{
313 int i;
cdda2018 314 unsigned long *seen_cpus = bitmap_new(max_cpus);
3ef71975 315
3ef71975 316 for (i = 0; i < nb_numa_nodes; i++) {
cdda2018 317 if (bitmap_intersects(seen_cpus, numa_info[i].node_cpu, max_cpus)) {
3ef71975 318 bitmap_and(seen_cpus, seen_cpus,
cdda2018 319 numa_info[i].node_cpu, max_cpus);
3ef71975 320 error_report("CPU(s) present in multiple NUMA nodes: %s",
a8f15a27 321 enumerate_cpus(seen_cpus, max_cpus));
cdda2018 322 g_free(seen_cpus);
3ef71975
EH
323 exit(EXIT_FAILURE);
324 }
325 bitmap_or(seen_cpus, seen_cpus,
cdda2018 326 numa_info[i].node_cpu, max_cpus);
3ef71975 327 }
549fc54b
EH
328
329 if (!bitmap_full(seen_cpus, max_cpus)) {
330 char *msg;
331 bitmap_complement(seen_cpus, seen_cpus, max_cpus);
332 msg = enumerate_cpus(seen_cpus, max_cpus);
333 error_report("warning: CPU(s) not present in any NUMA nodes: %s", msg);
334 error_report("warning: All CPU(s) up to maxcpus should be described "
335 "in NUMA config");
336 g_free(msg);
337 }
cdda2018 338 g_free(seen_cpus);
3ef71975
EH
339}
340
0f203430
HC
341/* If all node pair distances are symmetric, then only distances
342 * in one direction are enough. If there is even one asymmetric
343 * pair, though, then all distances must be provided. The
344 * distance from a node to itself is always NUMA_DISTANCE_MIN,
345 * so providing it is never necessary.
346 */
347static void validate_numa_distance(void)
348{
349 int src, dst;
350 bool is_asymmetrical = false;
351
352 for (src = 0; src < nb_numa_nodes; src++) {
353 for (dst = src; dst < nb_numa_nodes; dst++) {
354 if (numa_info[src].distance[dst] == 0 &&
355 numa_info[dst].distance[src] == 0) {
356 if (src != dst) {
357 error_report("The distance between node %d and %d is "
358 "missing, at least one distance value "
359 "between each nodes should be provided.",
360 src, dst);
361 exit(EXIT_FAILURE);
362 }
363 }
364
365 if (numa_info[src].distance[dst] != 0 &&
366 numa_info[dst].distance[src] != 0 &&
367 numa_info[src].distance[dst] !=
368 numa_info[dst].distance[src]) {
369 is_asymmetrical = true;
370 }
371 }
372 }
373
374 if (is_asymmetrical) {
375 for (src = 0; src < nb_numa_nodes; src++) {
376 for (dst = 0; dst < nb_numa_nodes; dst++) {
377 if (src != dst && numa_info[src].distance[dst] == 0) {
378 error_report("At least one asymmetrical pair of "
379 "distances is given, please provide distances "
380 "for both directions of all node pairs.");
381 exit(EXIT_FAILURE);
382 }
383 }
384 }
385 }
386}
387
388static void complete_init_numa_distance(void)
389{
390 int src, dst;
391
392 /* Fixup NUMA distance by symmetric policy because if it is an
393 * asymmetric distance table, it should be a complete table and
394 * there would not be any missing distance except local node, which
395 * is verified by validate_numa_distance above.
396 */
397 for (src = 0; src < nb_numa_nodes; src++) {
398 for (dst = 0; dst < nb_numa_nodes; dst++) {
399 if (numa_info[src].distance[dst] == 0) {
400 if (src == dst) {
401 numa_info[src].distance[dst] = NUMA_DISTANCE_MIN;
402 } else {
403 numa_info[src].distance[dst] = numa_info[dst].distance[src];
404 }
405 }
406 }
407 }
408}
409
57924bcd 410void parse_numa_opts(MachineClass *mc)
96d0e26c 411{
12d6e464
EH
412 int i;
413
cdda2018
IM
414 for (i = 0; i < MAX_NODES; i++) {
415 numa_info[i].node_cpu = bitmap_new(max_cpus);
416 }
417
28d0de7a 418 if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, NULL, NULL)) {
7dcd1d70
EH
419 exit(1);
420 }
421
12d6e464
EH
422 assert(max_numa_nodeid <= MAX_NODES);
423
424 /* No support for sparse NUMA node IDs yet: */
425 for (i = max_numa_nodeid - 1; i >= 0; i--) {
426 /* Report large node IDs first, to make mistakes easier to spot */
427 if (!numa_info[i].present) {
428 error_report("numa: Node ID missing: %d", i);
429 exit(1);
430 }
431 }
432
433 /* This must be always true if all nodes are present: */
434 assert(nb_numa_nodes == max_numa_nodeid);
435
96d0e26c 436 if (nb_numa_nodes > 0) {
2b631ec2 437 uint64_t numa_total;
96d0e26c
WG
438
439 if (nb_numa_nodes > MAX_NODES) {
440 nb_numa_nodes = MAX_NODES;
441 }
442
9851d0fe 443 /* If no memory size is given for any node, assume the default case
96d0e26c
WG
444 * and distribute the available memory equally across all nodes
445 */
446 for (i = 0; i < nb_numa_nodes; i++) {
8c85901e 447 if (numa_info[i].node_mem != 0) {
96d0e26c
WG
448 break;
449 }
450 }
451 if (i == nb_numa_nodes) {
452 uint64_t usedmem = 0;
453
55641213
LV
454 /* Align each node according to the alignment
455 * requirements of the machine class
96d0e26c
WG
456 */
457 for (i = 0; i < nb_numa_nodes - 1; i++) {
8c85901e 458 numa_info[i].node_mem = (ram_size / nb_numa_nodes) &
55641213 459 ~((1 << mc->numa_mem_align_shift) - 1);
8c85901e 460 usedmem += numa_info[i].node_mem;
96d0e26c 461 }
8c85901e 462 numa_info[i].node_mem = ram_size - usedmem;
96d0e26c
WG
463 }
464
2b631ec2
WG
465 numa_total = 0;
466 for (i = 0; i < nb_numa_nodes; i++) {
8c85901e 467 numa_total += numa_info[i].node_mem;
2b631ec2
WG
468 }
469 if (numa_total != ram_size) {
c68233ae
HT
470 error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
471 " should equal RAM size (0x" RAM_ADDR_FMT ")",
2b631ec2
WG
472 numa_total, ram_size);
473 exit(1);
474 }
475
fa9ea81d
BR
476 for (i = 0; i < nb_numa_nodes; i++) {
477 QLIST_INIT(&numa_info[i].addr);
478 }
479
abafabd8
BR
480 numa_set_mem_ranges();
481
96d0e26c 482 for (i = 0; i < nb_numa_nodes; i++) {
cdda2018 483 if (!bitmap_empty(numa_info[i].node_cpu, max_cpus)) {
96d0e26c
WG
484 break;
485 }
486 }
57924bcd
IM
487 /* Historically VCPUs were assigned in round-robin order to NUMA
488 * nodes. However it causes issues with guest not handling it nice
489 * in case where cores/threads from a multicore CPU appear on
490 * different nodes. So allow boards to override default distribution
491 * rule grouping VCPUs by socket so that VCPUs from the same socket
492 * would be on the same node.
96d0e26c
WG
493 */
494 if (i == nb_numa_nodes) {
495 for (i = 0; i < max_cpus; i++) {
57924bcd
IM
496 unsigned node_id = i % nb_numa_nodes;
497 if (mc->cpu_index_to_socket_id) {
498 node_id = mc->cpu_index_to_socket_id(i) % nb_numa_nodes;
499 }
500
501 set_bit(i, numa_info[node_id].node_cpu);
96d0e26c
WG
502 }
503 }
3ef71975
EH
504
505 validate_numa_cpus();
0f203430
HC
506
507 /* QEMU needs at least all unique node pair distances to build
508 * the whole NUMA distance table. QEMU treats the distance table
509 * as symmetric by default, i.e. distance A->B == distance B->A.
510 * Thus, QEMU is able to complete the distance table
511 * initialization even though only distance A->B is provided and
512 * distance B->A is not. QEMU knows the distance of a node to
513 * itself is always 10, so A->A distances may be omitted. When
514 * the distances of two nodes of a pair differ, i.e. distance
515 * A->B != distance B->A, then that means the distance table is
516 * asymmetric. In this case, the distances for both directions
517 * of all node pairs are required.
518 */
519 if (have_numa_distance) {
520 /* Validate enough NUMA distance information was provided. */
521 validate_numa_distance();
522
523 /* Validation succeeded, now fill in any missing distances. */
524 complete_init_numa_distance();
525 }
abafabd8
BR
526 } else {
527 numa_set_mem_node_id(0, ram_size, 0);
96d0e26c
WG
528 }
529}
530
dde11116 531void numa_post_machine_init(void)
96d0e26c
WG
532{
533 CPUState *cpu;
534 int i;
535
536 CPU_FOREACH(cpu) {
537 for (i = 0; i < nb_numa_nodes; i++) {
cdda2018 538 assert(cpu->cpu_index < max_cpus);
8c85901e 539 if (test_bit(cpu->cpu_index, numa_info[i].node_cpu)) {
96d0e26c
WG
540 cpu->numa_node = i;
541 }
542 }
543 }
544}
dfabb8b9 545
7febe36f
PB
546static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner,
547 const char *name,
548 uint64_t ram_size)
549{
0b183fc8
PB
550 if (mem_path) {
551#ifdef __linux__
7f56e740 552 Error *err = NULL;
dbcb8981 553 memory_region_init_ram_from_file(mr, owner, name, ram_size, false,
7f56e740 554 mem_path, &err);
c3ba3095 555 if (err) {
29b762f5 556 error_report_err(err);
fae947b0
LC
557 if (mem_prealloc) {
558 exit(1);
559 }
560
561 /* Legacy behavior: if allocation failed, fall back to
562 * regular RAM allocation.
563 */
f8ed85ac 564 memory_region_init_ram(mr, owner, name, ram_size, &error_fatal);
7f56e740 565 }
0b183fc8
PB
566#else
567 fprintf(stderr, "-mem-path not supported on this host\n");
568 exit(1);
569#endif
570 } else {
f8ed85ac 571 memory_region_init_ram(mr, owner, name, ram_size, &error_fatal);
0b183fc8 572 }
7febe36f
PB
573 vmstate_register_ram_global(mr);
574}
575
dfabb8b9
PB
576void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
577 const char *name,
578 uint64_t ram_size)
579{
7febe36f
PB
580 uint64_t addr = 0;
581 int i;
582
583 if (nb_numa_nodes == 0 || !have_memdevs) {
584 allocate_system_memory_nonnuma(mr, owner, name, ram_size);
585 return;
586 }
587
588 memory_region_init(mr, owner, name, ram_size);
589 for (i = 0; i < MAX_NODES; i++) {
7febe36f
PB
590 uint64_t size = numa_info[i].node_mem;
591 HostMemoryBackend *backend = numa_info[i].node_memdev;
592 if (!backend) {
593 continue;
594 }
007b0657
MA
595 MemoryRegion *seg = host_memory_backend_get_memory(backend,
596 &error_fatal);
7febe36f 597
0462faee
HT
598 if (memory_region_is_mapped(seg)) {
599 char *path = object_get_canonical_path_component(OBJECT(backend));
600 error_report("memory backend %s is used multiple times. Each "
601 "-numa option must use a different memdev value.",
602 path);
603 exit(1);
604 }
605
0b217571 606 host_memory_backend_set_mapped(backend, true);
7febe36f
PB
607 memory_region_add_subregion(mr, addr, seg);
608 vmstate_register_ram_global(seg);
609 addr += size;
610 }
dfabb8b9 611}
76b5d850 612
5b009e40
HZ
613static void numa_stat_memory_devices(uint64_t node_mem[])
614{
615 MemoryDeviceInfoList *info_list = NULL;
616 MemoryDeviceInfoList **prev = &info_list;
617 MemoryDeviceInfoList *info;
618
619 qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
620 for (info = info_list; info; info = info->next) {
621 MemoryDeviceInfo *value = info->value;
622
623 if (value) {
1fd5d4fe 624 switch (value->type) {
5b009e40 625 case MEMORY_DEVICE_INFO_KIND_DIMM:
32bafa8f 626 node_mem[value->u.dimm.data->node] += value->u.dimm.data->size;
5b009e40
HZ
627 break;
628 default:
629 break;
630 }
631 }
632 }
633 qapi_free_MemoryDeviceInfoList(info_list);
634}
635
636void query_numa_node_mem(uint64_t node_mem[])
637{
638 int i;
639
640 if (nb_numa_nodes <= 0) {
641 return;
642 }
643
644 numa_stat_memory_devices(node_mem);
645 for (i = 0; i < nb_numa_nodes; i++) {
646 node_mem[i] += numa_info[i].node_mem;
647 }
648}
649
76b5d850
HT
650static int query_memdev(Object *obj, void *opaque)
651{
652 MemdevList **list = opaque;
b0e90181 653 MemdevList *m = NULL;
76b5d850
HT
654
655 if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
b0e90181 656 m = g_malloc0(sizeof(*m));
76b5d850
HT
657
658 m->value = g_malloc0(sizeof(*m->value));
659
e1ff3c67
IM
660 m->value->id = object_property_get_str(obj, "id", NULL);
661 m->value->has_id = !!m->value->id;
662
76b5d850 663 m->value->size = object_property_get_int(obj, "size",
2f6f826e 664 &error_abort);
76b5d850 665 m->value->merge = object_property_get_bool(obj, "merge",
2f6f826e 666 &error_abort);
76b5d850 667 m->value->dump = object_property_get_bool(obj, "dump",
2f6f826e 668 &error_abort);
76b5d850 669 m->value->prealloc = object_property_get_bool(obj,
2f6f826e
MA
670 "prealloc",
671 &error_abort);
76b5d850
HT
672 m->value->policy = object_property_get_enum(obj,
673 "policy",
a3590dac 674 "HostMemPolicy",
2f6f826e 675 &error_abort);
76b5d850 676 object_property_get_uint16List(obj, "host-nodes",
2f6f826e
MA
677 &m->value->host_nodes,
678 &error_abort);
76b5d850
HT
679
680 m->next = *list;
681 *list = m;
682 }
683
684 return 0;
76b5d850
HT
685}
686
687MemdevList *qmp_query_memdev(Error **errp)
688{
2f6f826e 689 Object *obj = object_get_objects_root();
ecaf54a0 690 MemdevList *list = NULL;
76b5d850 691
2f6f826e 692 object_child_foreach(obj, query_memdev, &list);
76b5d850 693 return list;
76b5d850 694}
6bea1ddf
IM
695
696int numa_get_node_for_cpu(int idx)
697{
698 int i;
699
cdda2018
IM
700 assert(idx < max_cpus);
701
6bea1ddf
IM
702 for (i = 0; i < nb_numa_nodes; i++) {
703 if (test_bit(idx, numa_info[i].node_cpu)) {
704 break;
705 }
706 }
707 return i;
708}
0987d735
PB
709
710void ram_block_notifier_add(RAMBlockNotifier *n)
711{
712 QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);
713}
714
715void ram_block_notifier_remove(RAMBlockNotifier *n)
716{
717 QLIST_REMOVE(n, next);
718}
719
720void ram_block_notify_add(void *host, size_t size)
721{
722 RAMBlockNotifier *notifier;
723
724 QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
725 notifier->ram_block_added(notifier, host, size);
726 }
727}
728
729void ram_block_notify_remove(void *host, size_t size)
730{
731 RAMBlockNotifier *notifier;
732
733 QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
734 notifier->ram_block_removed(notifier, host, size);
735 }
736}