1 #include <stddef.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <arm/linux/api.h>
7 #include <cpuinfo.h>
8 #if defined(__ANDROID__)
9 #include <arm/android/api.h>
10 #endif
11 #include <arm/api.h>
12 #include <arm/midr.h>
13 #include <cpuinfo/internal-api.h>
14 #include <cpuinfo/log.h>
15 #include <linux/api.h>
16
bitmask_all(uint32_t bitfield,uint32_t mask)17 static inline bool bitmask_all(uint32_t bitfield, uint32_t mask) {
18 return (bitfield & mask) == mask;
19 }
20
21 /*
22 * Assigns logical processors to clusters of cores using heuristic based on the
23 * typical configuration of clusters for 5, 6, 8, and 10 cores:
24 * - 5 cores (ARM32 Android only): 2 clusters of 4+1 cores
25 * - 6 cores: 2 clusters of 4+2 cores
26 * - 8 cores: 2 clusters of 4+4 cores
27 * - 10 cores: 3 clusters of 4+4+2 cores
28 *
29 * The function must be called after parsing OS-provided information on core
30 * clusters. Its purpose is to detect clusters of cores when OS-provided
31 * information is lacking or incomplete, i.e.
32 * - Linux kernel is not configured to report information in sysfs topology
33 * leaf.
34 * - Linux kernel reports topology information only for online cores, and only
35 * cores on one cluster are online, e.g.:
36 * - Exynos 8890 has 8 cores in 4+4 clusters, but only the first cluster of 4
37 * cores is reported, and cluster configuration of logical processors 4-7 is not
38 * reported (all remaining processors 4-7 form cluster 1)
39 * - MT6797 has 10 cores in 4+4+2, but only the first cluster of 4 cores is
40 * reported, and cluster configuration of logical processors 4-9 is not reported
41 * (processors 4-7 form cluster 1, and processors 8-9 form cluster 2).
42 *
43 * Heuristic assignment of processors to the above pre-defined clusters fails if
44 * such assignment would contradict information provided by the operating
45 * system:
46 * - Any of the OS-reported processor clusters is different than the
47 * corresponding heuristic cluster.
48 * - Processors in a heuristic cluster have no OS-provided cluster siblings
49 * information, but have known and different minimum/maximum frequency.
50 * - Processors in a heuristic cluster have no OS-provided cluster siblings
51 * information, but have known and different MIDR components.
52 *
53 * If the heuristic assignment of processors to clusters of cores fails, all
54 * processors' clusters are unchanged.
55 *
56 * @param usable_processors - number of processors in the @p processors array
57 * with CPUINFO_LINUX_FLAG_VALID flags.
58 * @param max_processors - number of elements in the @p processors array.
59 * @param[in,out] processors - processor descriptors with pre-parsed POSSIBLE
60 * and PRESENT flags, minimum/maximum frequency, MIDR information, and core
61 * cluster (package siblings list) information.
62 *
63 * @retval true if the heuristic successfully assigned all processors into
64 * clusters of cores.
65 * @retval false if known details about processors contradict the heuristic
66 * configuration of core clusters.
67 */
cpuinfo_arm_linux_detect_core_clusters_by_heuristic(uint32_t usable_processors,uint32_t max_processors,struct cpuinfo_arm_linux_processor processors[restrict static max_processors])68 bool cpuinfo_arm_linux_detect_core_clusters_by_heuristic(
69 uint32_t usable_processors,
70 uint32_t max_processors,
71 struct cpuinfo_arm_linux_processor processors[restrict static max_processors]) {
72 uint32_t cluster_processors[3];
73 switch (usable_processors) {
74 case 10:
75 cluster_processors[0] = 4;
76 cluster_processors[1] = 4;
77 cluster_processors[2] = 2;
78 break;
79 case 8:
80 cluster_processors[0] = 4;
81 cluster_processors[1] = 4;
82 break;
83 case 6:
84 cluster_processors[0] = 4;
85 cluster_processors[1] = 2;
86 break;
87 #if defined(__ANDROID__) && CPUINFO_ARCH_ARM
88 case 5:
89 /*
90 * The only processor with 5 cores is Leadcore L1860C
91 * (ARMv7, mobile), but this configuration is not too
92 * unreasonable for a virtualized ARM server.
93 */
94 cluster_processors[0] = 4;
95 cluster_processors[1] = 1;
96 break;
97 #endif
98 default:
99 return false;
100 }
101
102 /*
103 * Assignment of processors to core clusters is done in two passes:
104 * 1. Verify that the clusters proposed by heuristic are compatible with
105 * known details about processors.
106 * 2. If verification passed, update core clusters for the processors.
107 */
108
109 uint32_t cluster = 0;
110 uint32_t expected_cluster_processors = 0;
111 uint32_t cluster_start, cluster_flags, cluster_midr, cluster_max_frequency, cluster_min_frequency;
112 bool expected_cluster_exists;
113 for (uint32_t i = 0; i < max_processors; i++) {
114 if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
115 if (expected_cluster_processors == 0) {
116 /* Expect this processor to start a new cluster
117 */
118
119 expected_cluster_exists = !!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER);
120 if (expected_cluster_exists) {
121 if (processors[i].package_leader_id != i) {
122 cpuinfo_log_debug(
123 "heuristic detection of core clusters failed: "
124 "processor %" PRIu32
125 " is expected to start a new cluster #%" PRIu32 " with %" PRIu32
126 " cores, "
127 "but system siblings lists reported it as a sibling of processor %" PRIu32,
128 i,
129 cluster,
130 cluster_processors[cluster],
131 processors[i].package_leader_id);
132 return false;
133 }
134 } else {
135 cluster_flags = 0;
136 }
137
138 cluster_start = i;
139 expected_cluster_processors = cluster_processors[cluster++];
140 } else {
141 /* Expect this processor to belong to the same
142 * cluster as processor */
143
144 if (expected_cluster_exists) {
145 /*
146 * The cluster suggested by the
147 * heuristic was already parsed from
148 * system siblings lists. For all
149 * processors we expect in the cluster,
150 * check that:
151 * - They have pre-assigned cluster from
152 * siblings lists
153 * (CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER
154 * flag).
155 * - They were assigned to the same
156 * cluster based on siblings lists
157 * (package_leader_id points to the
158 * first processor in the cluster).
159 */
160
161 if ((processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) == 0) {
162 cpuinfo_log_debug(
163 "heuristic detection of core clusters failed: "
164 "processor %" PRIu32
165 " is expected to belong to the cluster of processor %" PRIu32
166 ", "
167 "but system siblings lists did not report it as a sibling of processor %" PRIu32,
168 i,
169 cluster_start,
170 cluster_start);
171 return false;
172 }
173 if (processors[i].package_leader_id != cluster_start) {
174 cpuinfo_log_debug(
175 "heuristic detection of core clusters failed: "
176 "processor %" PRIu32
177 " is expected to belong to the cluster of processor %" PRIu32
178 ", "
179 "but system siblings lists reported it to belong to the cluster of processor %" PRIu32,
180 i,
181 cluster_start,
182 cluster_start);
183 return false;
184 }
185 } else {
186 /*
187 * The cluster suggest by the heuristic
188 * was not parsed from system siblings
189 * lists. For all processors we expect
190 * in the cluster, check that:
191 * - They have no pre-assigned cluster
192 * from siblings lists.
193 * - If their min/max CPU frequency is
194 * known, it is the same.
195 * - If any part of their MIDR
196 * (Implementer, Variant, Part,
197 * Revision) is known, it is the same.
198 */
199
200 if (processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) {
201 cpuinfo_log_debug(
202 "heuristic detection of core clusters failed: "
203 "processor %" PRIu32
204 " is expected to be unassigned to any cluster, "
205 "but system siblings lists reported it to belong to the cluster of processor %" PRIu32,
206 i,
207 processors[i].package_leader_id);
208 return false;
209 }
210
211 if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
212 if (cluster_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
213 if (cluster_min_frequency != processors[i].min_frequency) {
214 cpuinfo_log_debug(
215 "heuristic detection of core clusters failed: "
216 "minimum frequency of processor %" PRIu32
217 " (%" PRIu32
218 " KHz) is different than of its expected cluster (%" PRIu32
219 " KHz)",
220 i,
221 processors[i].min_frequency,
222 cluster_min_frequency);
223 return false;
224 }
225 } else {
226 cluster_min_frequency = processors[i].min_frequency;
227 cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY;
228 }
229 }
230
231 if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
232 if (cluster_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
233 if (cluster_max_frequency != processors[i].max_frequency) {
234 cpuinfo_log_debug(
235 "heuristic detection of core clusters failed: "
236 "maximum frequency of processor %" PRIu32
237 " (%" PRIu32
238 " KHz) is different than of its expected cluster (%" PRIu32
239 " KHz)",
240 i,
241 processors[i].max_frequency,
242 cluster_max_frequency);
243 return false;
244 }
245 } else {
246 cluster_max_frequency = processors[i].max_frequency;
247 cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY;
248 }
249 }
250
251 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
252 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
253 if ((cluster_midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) !=
254 (processors[i].midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK)) {
255 cpuinfo_log_debug(
256 "heuristic detection of core clusters failed: "
257 "CPU Implementer of processor %" PRIu32
258 " (0x%02" PRIx32
259 ") is different than of its expected cluster (0x%02" PRIx32
260 ")",
261 i,
262 midr_get_implementer(processors[i].midr),
263 midr_get_implementer(cluster_midr));
264 return false;
265 }
266 } else {
267 cluster_midr =
268 midr_copy_implementer(cluster_midr, processors[i].midr);
269 cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER;
270 }
271 }
272
273 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
274 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
275 if ((cluster_midr & CPUINFO_ARM_MIDR_VARIANT_MASK) !=
276 (processors[i].midr & CPUINFO_ARM_MIDR_VARIANT_MASK)) {
277 cpuinfo_log_debug(
278 "heuristic detection of core clusters failed: "
279 "CPU Variant of processor %" PRIu32
280 " (0x%" PRIx32
281 ") is different than of its expected cluster (0x%" PRIx32
282 ")",
283 i,
284 midr_get_variant(processors[i].midr),
285 midr_get_variant(cluster_midr));
286 return false;
287 }
288 } else {
289 cluster_midr =
290 midr_copy_variant(cluster_midr, processors[i].midr);
291 cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT;
292 }
293 }
294
295 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) {
296 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_PART) {
297 if ((cluster_midr & CPUINFO_ARM_MIDR_PART_MASK) !=
298 (processors[i].midr & CPUINFO_ARM_MIDR_PART_MASK)) {
299 cpuinfo_log_debug(
300 "heuristic detection of core clusters failed: "
301 "CPU Part of processor %" PRIu32
302 " (0x%03" PRIx32
303 ") is different than of its expected cluster (0x%03" PRIx32
304 ")",
305 i,
306 midr_get_part(processors[i].midr),
307 midr_get_part(cluster_midr));
308 return false;
309 }
310 } else {
311 cluster_midr = midr_copy_part(cluster_midr, processors[i].midr);
312 cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART;
313 }
314 }
315
316 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
317 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
318 if ((cluster_midr & CPUINFO_ARM_MIDR_REVISION_MASK) !=
319 (processors[i].midr & CPUINFO_ARM_MIDR_REVISION_MASK)) {
320 cpuinfo_log_debug(
321 "heuristic detection of core clusters failed: "
322 "CPU Revision of processor %" PRIu32
323 " (0x%" PRIx32
324 ") is different than of its expected cluster (0x%" PRIx32
325 ")",
326 i,
327 midr_get_revision(cluster_midr),
328 midr_get_revision(processors[i].midr));
329 return false;
330 }
331 } else {
332 cluster_midr =
333 midr_copy_revision(cluster_midr, processors[i].midr);
334 cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION;
335 }
336 }
337 }
338 }
339 expected_cluster_processors--;
340 }
341 }
342
343 /* Verification passed, assign all processors to new clusters */
344 cluster = 0;
345 expected_cluster_processors = 0;
346 for (uint32_t i = 0; i < max_processors; i++) {
347 if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
348 if (expected_cluster_processors == 0) {
349 /* Expect this processor to start a new cluster
350 */
351
352 cluster_start = i;
353 expected_cluster_processors = cluster_processors[cluster++];
354 } else {
355 /* Expect this processor to belong to the same
356 * cluster as processor */
357
358 if (!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) {
359 cpuinfo_log_debug(
360 "assigned processor %" PRIu32 " to cluster of processor %" PRIu32
361 " based on heuristic",
362 i,
363 cluster_start);
364 }
365
366 processors[i].package_leader_id = cluster_start;
367 processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
368 }
369 expected_cluster_processors--;
370 }
371 }
372 return true;
373 }
374
375 /*
376 * Assigns logical processors to clusters of cores in sequential manner:
377 * - Clusters detected from OS-provided information are unchanged:
378 * - Processors assigned to these clusters stay assigned to the same clusters
379 * - No new processors are added to these clusters
380 * - Processors without pre-assigned cluster are clustered in one sequential
381 * scan:
382 * - If known details (min/max frequency, MIDR components) of a processor are
383 * compatible with a preceding processor, without pre-assigned cluster, the
384 * processor is assigned to the cluster of the preceding processor.
385 * - If known details (min/max frequency, MIDR components) of a processor are
386 * not compatible with a preceding processor, the processor is assigned to a
387 * newly created cluster.
388 *
389 * The function must be called after parsing OS-provided information on core
390 * clusters, and usually is called only if heuristic assignment of processors to
391 * clusters (cpuinfo_arm_linux_cluster_processors_by_heuristic) failed.
392 *
393 * Its purpose is to detect clusters of cores when OS-provided information is
394 * lacking or incomplete, i.e.
395 * - Linux kernel is not configured to report information in sysfs topology
396 * leaf.
397 * - Linux kernel reports topology information only for online cores, and all
398 * cores on some of the clusters are offline.
399 *
400 * Sequential assignment of processors to clusters always succeeds, and upon
401 * exit, all usable processors in the
402 * @p processors array have cluster information.
403 *
404 * @param max_processors - number of elements in the @p processors array.
405 * @param[in,out] processors - processor descriptors with pre-parsed POSSIBLE
406 * and PRESENT flags, minimum/maximum frequency, MIDR information, and core
407 * cluster (package siblings list) information.
408 *
409 * @retval true if the heuristic successfully assigned all processors into
410 * clusters of cores.
411 * @retval false if known details about processors contradict the heuristic
412 * configuration of core clusters.
413 */
cpuinfo_arm_linux_detect_core_clusters_by_sequential_scan(uint32_t max_processors,struct cpuinfo_arm_linux_processor processors[restrict static max_processors])414 void cpuinfo_arm_linux_detect_core_clusters_by_sequential_scan(
415 uint32_t max_processors,
416 struct cpuinfo_arm_linux_processor processors[restrict static max_processors]) {
417 uint32_t cluster_flags = 0;
418 uint32_t cluster_processors = 0;
419 uint32_t cluster_start, cluster_midr, cluster_max_frequency, cluster_min_frequency;
420 for (uint32_t i = 0; i < max_processors; i++) {
421 if ((processors[i].flags & (CPUINFO_LINUX_FLAG_VALID | CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) ==
422 CPUINFO_LINUX_FLAG_VALID) {
423 if (cluster_processors == 0) {
424 goto new_cluster;
425 }
426
427 if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
428 if (cluster_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
429 if (cluster_min_frequency != processors[i].min_frequency) {
430 cpuinfo_log_info(
431 "minimum frequency of processor %" PRIu32 " (%" PRIu32
432 " KHz) is different than of preceding cluster (%" PRIu32
433 " KHz); "
434 "processor %" PRIu32 " starts to a new cluster",
435 i,
436 processors[i].min_frequency,
437 cluster_min_frequency,
438 i);
439 goto new_cluster;
440 }
441 } else {
442 cluster_min_frequency = processors[i].min_frequency;
443 cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY;
444 }
445 }
446
447 if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
448 if (cluster_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
449 if (cluster_max_frequency != processors[i].max_frequency) {
450 cpuinfo_log_debug(
451 "maximum frequency of processor %" PRIu32 " (%" PRIu32
452 " KHz) is different than of preceding cluster (%" PRIu32
453 " KHz); "
454 "processor %" PRIu32 " starts a new cluster",
455 i,
456 processors[i].max_frequency,
457 cluster_max_frequency,
458 i);
459 goto new_cluster;
460 }
461 } else {
462 cluster_max_frequency = processors[i].max_frequency;
463 cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY;
464 }
465 }
466
467 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
468 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
469 if ((cluster_midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) !=
470 (processors[i].midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK)) {
471 cpuinfo_log_debug(
472 "CPU Implementer of processor %" PRIu32 " (0x%02" PRIx32
473 ") is different than of preceding cluster (0x%02" PRIx32
474 "); "
475 "processor %" PRIu32 " starts to a new cluster",
476 i,
477 midr_get_implementer(processors[i].midr),
478 midr_get_implementer(cluster_midr),
479 i);
480 goto new_cluster;
481 }
482 } else {
483 cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr);
484 cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER;
485 }
486 }
487
488 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
489 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
490 if ((cluster_midr & CPUINFO_ARM_MIDR_VARIANT_MASK) !=
491 (processors[i].midr & CPUINFO_ARM_MIDR_VARIANT_MASK)) {
492 cpuinfo_log_debug(
493 "CPU Variant of processor %" PRIu32 " (0x%" PRIx32
494 ") is different than of its expected cluster (0x%" PRIx32
495 ")"
496 "processor %" PRIu32 " starts to a new cluster",
497 i,
498 midr_get_variant(processors[i].midr),
499 midr_get_variant(cluster_midr),
500 i);
501 goto new_cluster;
502 }
503 } else {
504 cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr);
505 cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT;
506 }
507 }
508
509 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) {
510 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_PART) {
511 if ((cluster_midr & CPUINFO_ARM_MIDR_PART_MASK) !=
512 (processors[i].midr & CPUINFO_ARM_MIDR_PART_MASK)) {
513 cpuinfo_log_debug(
514 "CPU Part of processor %" PRIu32 " (0x%03" PRIx32
515 ") is different than of its expected cluster (0x%03" PRIx32
516 ")"
517 "processor %" PRIu32 " starts to a new cluster",
518 i,
519 midr_get_part(processors[i].midr),
520 midr_get_part(cluster_midr),
521 i);
522 goto new_cluster;
523 }
524 } else {
525 cluster_midr = midr_copy_part(cluster_midr, processors[i].midr);
526 cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART;
527 }
528 }
529
530 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
531 if (cluster_flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
532 if ((cluster_midr & CPUINFO_ARM_MIDR_REVISION_MASK) !=
533 (processors[i].midr & CPUINFO_ARM_MIDR_REVISION_MASK)) {
534 cpuinfo_log_debug(
535 "CPU Revision of processor %" PRIu32 " (0x%" PRIx32
536 ") is different than of its expected cluster (0x%" PRIx32
537 ")"
538 "processor %" PRIu32 " starts to a new cluster",
539 i,
540 midr_get_revision(cluster_midr),
541 midr_get_revision(processors[i].midr),
542 i);
543 goto new_cluster;
544 }
545 } else {
546 cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr);
547 cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION;
548 }
549 }
550
551 /* All checks passed, attach processor to the preceding
552 * cluster */
553 cluster_processors++;
554 processors[i].package_leader_id = cluster_start;
555 processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
556 cpuinfo_log_debug(
557 "assigned processor %" PRIu32 " to preceding cluster of processor %" PRIu32,
558 i,
559 cluster_start);
560 continue;
561
562 new_cluster:
563 /* Create a new cluster starting with processor i */
564 cluster_start = i;
565 processors[i].package_leader_id = i;
566 processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
567 cluster_processors = 1;
568
569 /* Copy known information from processor to cluster, and
570 * set the flags accordingly */
571 cluster_flags = 0;
572 if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) {
573 cluster_min_frequency = processors[i].min_frequency;
574 cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY;
575 }
576 if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) {
577 cluster_max_frequency = processors[i].max_frequency;
578 cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY;
579 }
580 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) {
581 cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr);
582 cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER;
583 }
584 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) {
585 cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr);
586 cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT;
587 }
588 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) {
589 cluster_midr = midr_copy_part(cluster_midr, processors[i].midr);
590 cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART;
591 }
592 if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) {
593 cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr);
594 cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION;
595 }
596 }
597 }
598 }
599
600 /*
601 * Counts the number of logical processors in each core cluster.
602 * This function should be called after all processors are assigned to core
603 * clusters.
604 *
605 * @param max_processors - number of elements in the @p processors array.
606 * @param[in,out] processors - processor descriptors with pre-parsed POSSIBLE
607 * and PRESENT flags, and decoded core cluster (package_leader_id) information.
608 * The function expects the value of
609 * processors[i].package_processor_count to be zero. Upon return,
610 * processors[i].package_processor_count will contain the number of logical
611 * processors in the respective core cluster.
612 */
cpuinfo_arm_linux_count_cluster_processors(uint32_t max_processors,struct cpuinfo_arm_linux_processor processors[restrict static max_processors])613 void cpuinfo_arm_linux_count_cluster_processors(
614 uint32_t max_processors,
615 struct cpuinfo_arm_linux_processor processors[restrict static max_processors]) {
616 /* First pass: accumulate the number of processors at the group leader's
617 * package_processor_count */
618 for (uint32_t i = 0; i < max_processors; i++) {
619 if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
620 const uint32_t package_leader_id = processors[i].package_leader_id;
621 processors[package_leader_id].package_processor_count += 1;
622 }
623 }
624 /* Second pass: copy the package_processor_count from the group leader
625 * processor */
626 for (uint32_t i = 0; i < max_processors; i++) {
627 if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
628 const uint32_t package_leader_id = processors[i].package_leader_id;
629 processors[i].package_processor_count = processors[package_leader_id].package_processor_count;
630 }
631 }
632 }
633