1#include <asm.h>
2#include <console/printf.h>
3#include <global.h>
4#include <irq/idt.h>
5#include <kassert.h>
6#include <limine.h>
7#include <math/bit_ops.h>
8#include <math/div.h>
9#include <math/min_max.h>
10#include <mem/alloc.h>
11#include <mem/numa.h>
12#include <smp/core.h>
13#include <smp/domain.h>
14#include <smp/smp.h>
15#include <smp/topology.h>
16#include <stdatomic.h>
17#include <sync/spinlock.h>
18
19static struct topology_node *smt_nodes;
20static struct topology_node *core_nodes;
21static struct topology_node *numa_nodes;
22static struct topology_node *package_nodes;
23static struct topology_node *llc_nodes;
24static struct topology_node machine_node;
25
26#define BOLD_STR(__str) ANSI_BOLD __str ANSI_RESET
27
28static void cpu_mask_print(const struct cpu_mask *m) {
29 if (!m->uses_large) {
30 printf(BOLD_STR("0x%llx"), (uint64_t) m->small);
31 } else {
32 size_t nwords = DIV_ROUND_UP(m->nbits, 64);
33 for (size_t i = 0; i < nwords; i++)
34 printf(BOLD_STR("%016llx"), (uint64_t) m->large[nwords - 1 - i]);
35 }
36}
37
38#define TOPO_MAKE_STR(__color, __str) (__color __str ANSI_RESET)
39
40static const char *topo_node_str[TOPOLOGY_LEVEL_MAX] = {
41 [TOPOLOGY_LEVEL_SMT] = TOPO_MAKE_STR(ANSI_MAGENTA, "SMT"),
42 [TOPOLOGY_LEVEL_CORE] = TOPO_MAKE_STR(ANSI_BLUE, "CORE"),
43 [TOPOLOGY_LEVEL_LLC] = TOPO_MAKE_STR(ANSI_CYAN, "LLC"),
44 [TOPOLOGY_LEVEL_PACKAGE] = TOPO_MAKE_STR(ANSI_GREEN, "PACKAGE"),
45 [TOPOLOGY_LEVEL_NUMA] = TOPO_MAKE_STR(ANSI_YELLOW, "NUMA NODE"),
46 [TOPOLOGY_LEVEL_MACHINE] = TOPO_MAKE_STR(ANSI_RED, "MACHINE"),
47};
48
49const char *topology_level_name(enum topology_level l) {
50 return topo_node_str[l];
51}
52
53static void print_topology_node(struct topology_node *node, int depth) {
54 for (int i = 0; i < depth; i++)
55 printf(format: " ");
56
57 const char *level_str = topo_node_str[node->level];
58
59 printf(format: "[%s] ID = " ANSI_BOLD "%d" ANSI_RESET ", CPUs = ", level_str,
60 node->id);
61 cpu_mask_print(m: &node->cpus);
62 printf(format: "\n");
63
64 switch (node->level) {
65 case TOPOLOGY_LEVEL_MACHINE:
66 for (int i = 0; i < global.topology.count[TOPOLOGY_LEVEL_PACKAGE]; i++)
67 if (package_nodes[i].parent == node->id)
68 print_topology_node(node: &package_nodes[i], depth: depth + 1);
69 break;
70
71 case TOPOLOGY_LEVEL_PACKAGE:
72 for (int i = 0; i < global.topology.count[TOPOLOGY_LEVEL_LLC]; i++)
73 if (llc_nodes[i].parent == node->id)
74 print_topology_node(node: &llc_nodes[i], depth: depth + 1);
75 break;
76
77 case TOPOLOGY_LEVEL_LLC:
78 for (int i = 0; i < global.topology.count[TOPOLOGY_LEVEL_NUMA]; i++)
79 if (numa_nodes[i].parent == node->id)
80 print_topology_node(node: &numa_nodes[i], depth: depth + 1);
81 break;
82
83 case TOPOLOGY_LEVEL_NUMA:
84 for (int i = 0; i < global.topology.count[TOPOLOGY_LEVEL_CORE]; i++)
85 if (core_nodes[i].parent == node->id)
86 print_topology_node(node: &core_nodes[i], depth: depth + 1);
87 break;
88
89 case TOPOLOGY_LEVEL_CORE:
90 for (int i = 0; i < global.topology.count[TOPOLOGY_LEVEL_SMT]; i++)
91 if (smt_nodes[i].parent == node->id)
92 print_topology_node(node: &smt_nodes[i], depth: depth + 1);
93 break;
94
95 default: break;
96 }
97}
98
99void cpu_mask_deinit(struct cpu_mask *m) {
100 if (m->uses_large)
101 kfree(m->large);
102
103 m->uses_large = false;
104 m->nbits = 0;
105 atomic_store_explicit(&m->small, 0, memory_order_release);
106}
107
108void cpu_mask_free(struct cpu_mask *m) {
109 kfree(m);
110}
111
112struct cpu_mask *cpu_mask_create(void) {
113 return kmalloc(sizeof(struct cpu_mask), ALLOC_FLAGS_ZERO);
114}
115
116bool cpu_mask_init(struct cpu_mask *m, size_t nbits) {
117 m->nbits = nbits;
118 if (nbits <= 64) {
119 m->small = 0;
120 m->uses_large = false;
121 return true;
122 }
123
124 m->uses_large = true;
125 size_t nwords = DIV_ROUND_UP(nbits, 64);
126 m->large = kmalloc(sizeof(uint64_t) * nwords, ALLOC_FLAGS_ZERO);
127
128 if (!m->large)
129 return false;
130
131 return true;
132}
133
134size_t cpu_mask_popcount(struct cpu_mask *m) {
135 if (!m->uses_large) {
136 return popcount(atomic_load(&m->small));
137 } else {
138 size_t nwords = DIV_ROUND_UP(m->nbits, 64);
139 size_t acc = 0;
140 for (size_t i = 0; i < nwords; i++)
141 acc += popcount(atomic_load(&m->large[i]));
142
143 return acc;
144 }
145}
146
147void cpu_mask_set(struct cpu_mask *m, size_t cpu) {
148 if (!m->uses_large) {
149 atomic_fetch_or(&m->small, 1ULL << cpu);
150 } else {
151 atomic_fetch_or(&m->large[cpu / 64], 1ULL << (cpu % 64));
152 }
153}
154
155void cpu_mask_clear(struct cpu_mask *m, size_t cpu) {
156 if (!m->uses_large) {
157 atomic_fetch_and(&m->small, ~(1ULL << cpu));
158 } else {
159 atomic_fetch_and(&m->large[cpu / 64], ~(1ULL << (cpu % 64)));
160 }
161}
162
163bool cpu_mask_test(const struct cpu_mask *m, size_t cpu) {
164 if (!m->uses_large) {
165 return (atomic_load(&m->small) >> cpu) & 1ULL;
166 } else {
167 return (atomic_load(&m->large[cpu / 64]) >> (cpu % 64)) & 1ULL;
168 }
169}
170
171void cpu_mask_or(struct cpu_mask *dst, const struct cpu_mask *b) {
172 if (!dst->uses_large) {
173 atomic_fetch_or(&dst->small, atomic_load(&b->small));
174 } else {
175 size_t nwords = DIV_ROUND_UP(dst->nbits, 64);
176 for (size_t i = 0; i < nwords; i++)
177 atomic_fetch_or(&dst->large[i], atomic_load(&b->large[i]));
178 }
179}
180
181void cpu_mask_set_all(struct cpu_mask *m) {
182 if (!m->uses_large) {
183 atomic_store(&m->small, UINT64_MAX);
184 } else {
185 size_t nwords = DIV_ROUND_UP(m->nbits, 64);
186 for (size_t i = 0; i < nwords; i++)
187 atomic_store(&m->large[i], UINT64_MAX);
188 }
189}
190
191void cpu_mask_clear_all(struct cpu_mask *m) {
192 if (!m->uses_large) {
193 atomic_store(&m->small, 0);
194 } else {
195 size_t nwords = DIV_ROUND_UP(m->nbits, 64);
196 for (size_t i = 0; i < nwords; i++)
197 atomic_store(&m->large[i], 0);
198 }
199}
200
201bool cpu_mask_empty(const struct cpu_mask *mask) {
202 if (!mask->uses_large)
203 return atomic_load(&mask->small) == 0;
204
205 size_t nwords = DIV_ROUND_UP(mask->nbits, 64);
206 for (size_t i = 0; i < nwords; i++)
207 if (atomic_load(&mask->large[i]) != 0)
208 return false;
209
210 return true;
211}
212
213void topology_dump(void) {
214 log_msg(LOG_INFO, "Processor topology:");
215 print_topology_node(node: &machine_node, depth: 0);
216}
217
218#define PANIC_IF_CPU_MASK_FAILED(op) \
219 do { \
220 if (unlikely(!op)) \
221 panic("CPU mask allocation failed!"); \
222 \
223 } while (0);
224
225static size_t build_smt_nodes(size_t n_cpus) {
226 smt_nodes =
227 kmalloc(n_cpus * sizeof(struct topology_node), ALLOC_FLAGS_ZERO);
228
229 for (size_t i = 0; i < n_cpus; i++) {
230 struct core *c = global.cores[i];
231
232 struct topology_node *node = &smt_nodes[i];
233
234 size_t core_index = 0;
235 size_t j;
236 for_each_cpu_id(j) {
237 if (core_nodes[j].core->core_id == c->core_id &&
238 core_nodes[j].core->package_id == c->package_id) {
239 core_index = j;
240 break;
241 }
242 }
243
244 node->level = TOPOLOGY_LEVEL_SMT;
245 node->id = i;
246 node->parent = core_index;
247 node->core = c;
248 c->topo_node = node;
249 node->first_child = -1;
250
251 node->nr_children = 0;
252
253 cpu_mask_init(m: &node->cpus, nbits: n_cpus);
254 cpu_mask_set(m: &node->cpus, cpu: i);
255 cpu_mask_init(m: &node->idle, nbits: n_cpus);
256 cpu_mask_set(m: &node->idle, cpu: i);
257
258 struct topology_node *parent_core = &core_nodes[core_index];
259
260 node->parent_node = parent_core;
261
262 if (parent_core->first_child == -1)
263 parent_core->first_child = i;
264
265 parent_core->nr_children++;
266 }
267
268 return n_cpus;
269}
270
271static size_t build_core_nodes(size_t n_cpus) {
272 size_t core_count = 0;
273 core_nodes =
274 kmalloc(n_cpus * sizeof(struct topology_node), ALLOC_FLAGS_ZERO);
275
276 for (size_t i = 0; i < n_cpus; i++) {
277 struct core *c = global.cores[i];
278
279 bool exists = false;
280 for (size_t j = 0; j < core_count; j++) {
281 if (core_nodes[j].core->core_id == c->core_id &&
282 core_nodes[j].core->package_id == c->package_id) {
283 exists = true;
284 break;
285 }
286 }
287
288 if (exists)
289 continue;
290
291 struct topology_node *node = &core_nodes[core_count];
292
293 node->level = TOPOLOGY_LEVEL_CORE;
294 node->id = c->core_id;
295 node->first_child = -1;
296 node->nr_children = 0;
297 node->core = c;
298 node->parent = -1;
299 node->parent_node = NULL;
300
301 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->cpus, n_cpus));
302 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->idle, n_cpus));
303
304 for (size_t j = 0; j < n_cpus; j++) {
305 struct core *cj = global.cores[j];
306 if (cj->core_id == c->core_id && cj->package_id == c->package_id) {
307 cpu_mask_set(m: &node->cpus, cpu: j);
308 cpu_mask_set(m: &node->idle, cpu: j);
309 }
310 }
311
312 core_count++;
313 }
314
315 return core_count;
316}
317
318static bool cpu_mask_intersects(const struct cpu_mask *a,
319 const struct cpu_mask *b) {
320 if (!a->uses_large && !b->uses_large) {
321 return (a->small & b->small) != 0;
322 }
323
324 size_t nwords = DIV_ROUND_UP(MAX(a->nbits, b->nbits), 64);
325 for (size_t i = 0; i < nwords; i++) {
326 uint64_t wa = 0, wb = 0;
327
328 if (a->uses_large) {
329 if (i < (a->nbits + 63) / 64)
330 wa = a->large[i];
331 } else if (i == 0) {
332 wa = a->small;
333 }
334 if (b->uses_large) {
335 if (i < (b->nbits + 63) / 64)
336 wb = b->large[i];
337 } else if (i == 0) {
338 wb = b->small;
339 }
340
341 if ((wa & wb) != 0)
342 return true;
343 }
344 return false;
345}
346
347static size_t build_numa_nodes(size_t n_cores, size_t n_llc) {
348 size_t max_numa = 0;
349 for (size_t i = 0; i < n_cores; i++)
350 if (core_nodes[i].core->numa_node > max_numa)
351 max_numa = core_nodes[i].core->numa_node;
352
353 size_t n_numa_nodes = max_numa + 1;
354 numa_nodes =
355 kmalloc(n_numa_nodes * sizeof(struct topology_node), ALLOC_FLAGS_ZERO);
356
357 for (size_t i = 0; i < n_numa_nodes; i++) {
358 struct topology_node *numa = &numa_nodes[i];
359 numa->level = TOPOLOGY_LEVEL_NUMA;
360 numa->id = i;
361 numa->parent = -1;
362 numa->first_child = -1;
363 numa->nr_children = 0;
364 numa->core = NULL;
365
366 /* Initialized if there is actually
367 * NUMA present (these nodes are not fake) */
368 if (global.numa_node_count > 1) {
369 numa->data.numa = &global.numa_nodes[i];
370 global.numa_nodes[i].topo = numa;
371 }
372
373 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&numa->cpus, global.core_count));
374 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&numa->idle, global.core_count));
375 }
376
377 for (size_t i = 0; i < n_cores; i++) {
378 struct core *c = core_nodes[i].core;
379 uint32_t numa_id = c->numa_node;
380 struct topology_node *numa = &numa_nodes[numa_id];
381
382 core_nodes[i].parent = numa_id;
383 core_nodes[i].parent_node = numa;
384
385 if (numa->first_child == -1)
386 numa->first_child = i;
387
388 numa->nr_children++;
389 cpu_mask_or(dst: &numa->cpus, b: &core_nodes[i].cpus);
390 cpu_mask_or(dst: &numa->idle, b: &core_nodes[i].idle);
391 }
392
393 for (size_t i = 0; i < n_numa_nodes; i++) {
394 struct topology_node *numa = &numa_nodes[i];
395 if (numa->first_child == -1)
396 continue;
397
398 for (size_t j = 0; j < n_llc; j++) {
399 struct topology_node *llc = &llc_nodes[j];
400
401 if (cpu_mask_intersects(a: &llc->cpus, b: &numa->cpus)) {
402 numa->parent = llc->id;
403 numa->parent_node = llc;
404 numa->data.cache = llc->data.cache;
405
406 if (llc->first_child == -1)
407 llc->first_child = i;
408
409 llc->nr_children++;
410 break;
411 }
412 }
413 }
414
415 return n_numa_nodes;
416}
417
418static size_t build_llc_nodes(size_t n_cores) {
419 llc_nodes =
420 kmalloc(n_cores * sizeof(struct topology_node), ALLOC_FLAGS_ZERO);
421 size_t llc_count = 0;
422
423 for (size_t i = 0; i < n_cores; i++) {
424 struct core *c = core_nodes[i].core;
425 uint32_t pkg_id = c->package_id;
426
427 if (c->llc.level == 0 || c->llc.type == 0)
428 continue;
429
430 bool exists = false;
431 for (size_t j = 0; j < llc_count; j++) {
432 struct topology_cache_info *existing = llc_nodes[j].data.cache;
433 if (existing->level == c->llc.level &&
434 existing->type == c->llc.type &&
435 existing->size_kb == c->llc.size_kb &&
436 llc_nodes[j].parent == pkg_id) { /* Real */
437 exists = true;
438 cpu_mask_or(dst: &llc_nodes[j].cpus, b: &core_nodes[i].cpus);
439 cpu_mask_or(dst: &llc_nodes[j].idle, b: &core_nodes[i].idle);
440 break;
441 }
442 }
443
444 if (exists)
445 continue;
446
447 struct topology_node *node = &llc_nodes[llc_count];
448 node->level = TOPOLOGY_LEVEL_LLC;
449 node->id = llc_count;
450 node->parent = pkg_id;
451 node->core = NULL;
452 node->data.cache = &c->llc;
453
454 node->first_child = -1;
455 node->nr_children = 0;
456
457 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->cpus, global.core_count));
458 cpu_mask_or(dst: &node->cpus, b: &core_nodes[i].cpus);
459
460 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->idle, global.core_count));
461 cpu_mask_or(dst: &node->idle, b: &core_nodes[i].idle);
462
463 llc_count++;
464 }
465
466 if (llc_count > 0)
467 return llc_count;
468
469 /* no LLC info present, mirror packages */
470 uint32_t max_pkg_id = 0;
471 for (size_t i = 0; i < n_cores; i++)
472 if (core_nodes[i].core->package_id > max_pkg_id)
473 max_pkg_id = core_nodes[i].core->package_id;
474
475 size_t n_packages = max_pkg_id + 1;
476
477 for (size_t p = 0; p < n_packages; p++) {
478 struct topology_node *node = &llc_nodes[llc_count];
479 node->level = TOPOLOGY_LEVEL_LLC;
480 node->id = llc_count;
481 node->parent = p;
482 node->core = NULL;
483 node->data.cache = NULL;
484
485 node->first_child = -1;
486 node->nr_children = 0;
487
488 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->cpus, global.core_count));
489 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&node->idle, global.core_count));
490
491 for (size_t i = 0; i < n_cores; i++) {
492
493 if (core_nodes[i].core->package_id == p) {
494 cpu_mask_or(dst: &node->cpus, b: &core_nodes[i].cpus);
495 cpu_mask_or(dst: &node->idle, b: &core_nodes[i].idle);
496 }
497 }
498
499 llc_count++;
500 }
501
502 return llc_count;
503}
504
505static size_t build_package_nodes(size_t n_cores, size_t n_llc) {
506
507 uint32_t max_pkg_id = 0;
508
509 for (size_t i = 0; i < n_cores; i++)
510 if (core_nodes[i].core->package_id > max_pkg_id)
511 max_pkg_id = core_nodes[i].core->package_id;
512
513 size_t n_packages = max_pkg_id + 1;
514 package_nodes =
515 kmalloc(n_packages * sizeof(struct topology_node), ALLOC_FLAGS_ZERO);
516
517 for (size_t i = 0; i < n_packages; i++) {
518 struct topology_node *pkg = &package_nodes[i];
519 pkg->level = TOPOLOGY_LEVEL_PACKAGE;
520 pkg->id = i;
521 pkg->parent = 0;
522 pkg->first_child = -1;
523 pkg->nr_children = 0;
524 pkg->core = NULL;
525 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&pkg->cpus, global.core_count));
526 PANIC_IF_CPU_MASK_FAILED(cpu_mask_init(&pkg->idle, global.core_count));
527 }
528
529 for (size_t j = 0; j < n_llc; j++) {
530 struct topology_node *llc = &llc_nodes[j];
531 uint32_t pkg_id = llc->parent;
532 if (pkg_id >= n_packages)
533 continue;
534
535 struct topology_node *pkg = &package_nodes[pkg_id];
536
537 if (pkg->first_child == -1)
538 pkg->first_child = j;
539
540 llc->parent_node = pkg;
541 pkg->parent_node = &machine_node;
542 pkg->nr_children++;
543 cpu_mask_or(dst: &pkg->cpus, b: &llc->cpus);
544 cpu_mask_or(dst: &pkg->idle, b: &llc->idle);
545 }
546
547 return n_packages;
548}
549
550static void build_machine_node(size_t n_packages) {
551 machine_node.level = TOPOLOGY_LEVEL_MACHINE;
552 machine_node.id = 0;
553 machine_node.parent = -1;
554 machine_node.first_child = -1;
555 machine_node.nr_children = n_packages;
556 machine_node.core = NULL;
557
558 PANIC_IF_CPU_MASK_FAILED(
559 cpu_mask_init(&machine_node.cpus, global.core_count));
560 PANIC_IF_CPU_MASK_FAILED(
561 cpu_mask_init(&machine_node.idle, global.core_count));
562
563 for (size_t i = 0; i < n_packages; i++) {
564 struct topology_node *pkg = &package_nodes[i];
565
566 if (machine_node.first_child == -1)
567 machine_node.first_child = i;
568
569 cpu_mask_or(dst: &machine_node.cpus, b: &pkg->cpus);
570 cpu_mask_or(dst: &machine_node.idle, b: &pkg->idle);
571 }
572}
573
574void topology_init(void) {
575 size_t n_cpus = global.core_count; /* Logical processor count */
576
577 size_t n_cores = build_core_nodes(n_cpus);
578 size_t n_smt = build_smt_nodes(n_cpus);
579 size_t n_llc = build_llc_nodes(n_cores);
580 size_t n_numa = build_numa_nodes(n_cores, n_llc);
581 size_t n_packages = build_package_nodes(n_cores, n_llc);
582
583 build_machine_node(n_packages);
584
585 global.topology.level[TOPOLOGY_LEVEL_SMT] = smt_nodes;
586 global.topology.count[TOPOLOGY_LEVEL_SMT] = n_smt;
587 global.topology.level[TOPOLOGY_LEVEL_CORE] = core_nodes;
588 global.topology.count[TOPOLOGY_LEVEL_CORE] = n_cores;
589 global.topology.level[TOPOLOGY_LEVEL_NUMA] = numa_nodes;
590 global.topology.count[TOPOLOGY_LEVEL_NUMA] = n_numa;
591 global.topology.level[TOPOLOGY_LEVEL_LLC] = llc_nodes;
592 global.topology.count[TOPOLOGY_LEVEL_LLC] = n_llc;
593 global.topology.level[TOPOLOGY_LEVEL_PACKAGE] = package_nodes;
594 global.topology.count[TOPOLOGY_LEVEL_PACKAGE] = n_packages;
595 global.topology.level[TOPOLOGY_LEVEL_MACHINE] = &machine_node;
596 global.topology.count[TOPOLOGY_LEVEL_MACHINE] = 1;
597
598 topology_dump();
599 domain_dump();
600}
601
602void topology_mark_core_idle(cpu_id_t cpu_id, bool idle) {
603 if (!global.topology.level[TOPOLOGY_LEVEL_MACHINE])
604 return;
605
606 struct topology_node *smt = &smt_nodes[cpu_id];
607
608 struct topology_node *node = smt;
609 while (node) {
610 if (idle)
611 cpu_mask_set(m: &node->idle, cpu: cpu_id);
612 else
613 cpu_mask_clear(m: &node->idle, cpu: cpu_id);
614
615 node = node->parent_node;
616 }
617}
618
619struct core *topology_find_idle_core(struct core *local_core,
620 enum topology_level max_search) {
621 kassert(max_search >
622 TOPOLOGY_LEVEL_SMT); /* 'SMT' will be the core itself.
623 * It has no neighbors, and thus
624 * cannot be searched through (one core) */
625
626 struct topology_node *smt_node = local_core->topo_node; /* Direct node */
627 struct topology_node *core_node = smt_node->parent_node;
628 struct topology_node *numa_node = core_node->parent_node;
629 struct topology_node *llc_node = numa_node->parent_node;
630 struct topology_node *pkg_node = llc_node->parent_node;
631
632 /* First try SMT siblings */
633 for (int32_t i = 0; i < core_node->nr_children; i++) {
634 struct topology_node *sibling = &smt_nodes[core_node->first_child + i];
635 if (!cpu_mask_empty(mask: &sibling->idle))
636 return sibling->core;
637 }
638
639 /* Not allowed to search to NUMA */
640 if (max_search < TOPOLOGY_LEVEL_NUMA)
641 return NULL;
642
643 /* Next try NUMA siblings */
644 for (int32_t i = 0; i < numa_node->nr_children; i++) {
645 struct topology_node *core = &core_nodes[numa_node->first_child + i];
646 if (!cpu_mask_empty(mask: &core->idle))
647 return core->core;
648 }
649
650 if (max_search < TOPOLOGY_LEVEL_LLC)
651 return NULL;
652
653 for (int32_t i = 0; i < llc_node->nr_children; i++) {
654 struct topology_node *core = &core_nodes[llc_node->first_child + i];
655 if (!cpu_mask_empty(mask: &core->idle))
656 return core->core;
657 }
658
659 /* Finally do a full CPU scan */
660 for (int32_t i = 0; i < pkg_node->nr_children; i++) {
661 struct topology_node *llc = &llc_nodes[pkg_node->first_child + i];
662 if (cpu_mask_empty(mask: &llc->idle))
663 continue;
664
665 for (int32_t j = 0; j < smt_nodes->nr_children; j++) {
666 struct topology_node *smt = &smt_nodes[llc->first_child + j];
667 if (!cpu_mask_empty(mask: &smt->idle))
668 return smt->core;
669 }
670 }
671
672 size_t i;
673 for_each_cpu_id(i) {
674 struct topology_node *smt = &smt_nodes[i];
675 if (!cpu_mask_empty(mask: &smt->idle))
676 return smt->core;
677 }
678
679 return NULL;
680}
681