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