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
17
18 struct cpuinfo_arm_isa cpuinfo_isa = { 0 };
19
20 static struct cpuinfo_package package = { { 0 } };
21
bitmask_all(uint32_t bitfield,uint32_t mask)22 static inline bool bitmask_all(uint32_t bitfield, uint32_t mask) {
23 return (bitfield & mask) == mask;
24 }
25
min(uint32_t a,uint32_t b)26 static inline uint32_t min(uint32_t a, uint32_t b) {
27 return a < b ? a : b;
28 }
29
cmp(uint32_t a,uint32_t b)30 static inline int cmp(uint32_t a, uint32_t b) {
31 return (a > b) - (a < b);
32 }
33
cluster_siblings_parser(uint32_t processor,uint32_t siblings_start,uint32_t siblings_end,struct cpuinfo_arm_linux_processor * processors)34 static bool cluster_siblings_parser(
35 uint32_t processor, uint32_t siblings_start, uint32_t siblings_end,
36 struct cpuinfo_arm_linux_processor* processors)
37 {
38 processors[processor].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
39 uint32_t package_leader_id = processors[processor].package_leader_id;
40
41 for (uint32_t sibling = siblings_start; sibling < siblings_end; sibling++) {
42 if (!bitmask_all(processors[sibling].flags, CPUINFO_LINUX_FLAG_VALID)) {
43 cpuinfo_log_info("invalid processor %"PRIu32" reported as a sibling for processor %"PRIu32,
44 sibling, processor);
45 continue;
46 }
47
48 const uint32_t sibling_package_leader_id = processors[sibling].package_leader_id;
49 if (sibling_package_leader_id < package_leader_id) {
50 package_leader_id = sibling_package_leader_id;
51 }
52
53 processors[sibling].package_leader_id = package_leader_id;
54 processors[sibling].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER;
55 }
56
57 processors[processor].package_leader_id = package_leader_id;
58
59 return true;
60 }
61
cmp_arm_linux_processor(const void * ptr_a,const void * ptr_b)62 static int cmp_arm_linux_processor(const void* ptr_a, const void* ptr_b) {
63 const struct cpuinfo_arm_linux_processor* processor_a = (const struct cpuinfo_arm_linux_processor*) ptr_a;
64 const struct cpuinfo_arm_linux_processor* processor_b = (const struct cpuinfo_arm_linux_processor*) ptr_b;
65
66 /* Move usable processors towards the start of the array */
67 const bool usable_a = bitmask_all(processor_a->flags, CPUINFO_LINUX_FLAG_VALID);
68 const bool usable_b = bitmask_all(processor_b->flags, CPUINFO_LINUX_FLAG_VALID);
69 if (usable_a != usable_b) {
70 return (int) usable_b - (int) usable_a;
71 }
72
73 /* Compare based on core type (e.g. Cortex-A57 < Cortex-A53) */
74 const uint32_t midr_a = processor_a->midr;
75 const uint32_t midr_b = processor_b->midr;
76 if (midr_a != midr_b) {
77 const uint32_t score_a = midr_score_core(midr_a);
78 const uint32_t score_b = midr_score_core(midr_b);
79 if (score_a != score_b) {
80 return score_a > score_b ? -1 : 1;
81 }
82 }
83
84 /* Compare based on core frequency (e.g. 2.0 GHz < 1.2 GHz) */
85 const uint32_t frequency_a = processor_a->max_frequency;
86 const uint32_t frequency_b = processor_b->max_frequency;
87 if (frequency_a != frequency_b) {
88 return frequency_a > frequency_b ? -1 : 1;
89 }
90
91 /* Compare based on cluster leader id (i.e. cluster 1 < cluster 0) */
92 const uint32_t cluster_a = processor_a->package_leader_id;
93 const uint32_t cluster_b = processor_b->package_leader_id;
94 if (cluster_a != cluster_b) {
95 return cluster_a > cluster_b ? -1 : 1;
96 }
97
98 /* Compare based on system processor id (i.e. processor 0 < processor 1) */
99 const uint32_t id_a = processor_a->system_processor_id;
100 const uint32_t id_b = processor_b->system_processor_id;
101 return cmp(id_a, id_b);
102 }
103
cpuinfo_arm_linux_init(void)104 void cpuinfo_arm_linux_init(void) {
105 struct cpuinfo_arm_linux_processor* arm_linux_processors = NULL;
106 struct cpuinfo_processor* processors = NULL;
107 struct cpuinfo_core* cores = NULL;
108 struct cpuinfo_cluster* clusters = NULL;
109 struct cpuinfo_uarch_info* uarchs = NULL;
110 struct cpuinfo_cache* l1i = NULL;
111 struct cpuinfo_cache* l1d = NULL;
112 struct cpuinfo_cache* l2 = NULL;
113 struct cpuinfo_cache* l3 = NULL;
114 const struct cpuinfo_processor** linux_cpu_to_processor_map = NULL;
115 const struct cpuinfo_core** linux_cpu_to_core_map = NULL;
116 uint32_t* linux_cpu_to_uarch_index_map = NULL;
117
118 const uint32_t max_processors_count = cpuinfo_linux_get_max_processors_count();
119 cpuinfo_log_debug("system maximum processors count: %"PRIu32, max_processors_count);
120
121 const uint32_t max_possible_processors_count = 1 +
122 cpuinfo_linux_get_max_possible_processor(max_processors_count);
123 cpuinfo_log_debug("maximum possible processors count: %"PRIu32, max_possible_processors_count);
124 const uint32_t max_present_processors_count = 1 +
125 cpuinfo_linux_get_max_present_processor(max_processors_count);
126 cpuinfo_log_debug("maximum present processors count: %"PRIu32, max_present_processors_count);
127
128 uint32_t valid_processor_mask = 0;
129 uint32_t arm_linux_processors_count = max_processors_count;
130 if (max_present_processors_count != 0) {
131 arm_linux_processors_count = min(arm_linux_processors_count, max_present_processors_count);
132 valid_processor_mask = CPUINFO_LINUX_FLAG_PRESENT;
133 }
134 if (max_possible_processors_count != 0) {
135 arm_linux_processors_count = min(arm_linux_processors_count, max_possible_processors_count);
136 valid_processor_mask |= CPUINFO_LINUX_FLAG_POSSIBLE;
137 }
138 if ((max_present_processors_count | max_possible_processors_count) == 0) {
139 cpuinfo_log_error("failed to parse both lists of possible and present processors");
140 return;
141 }
142
143 arm_linux_processors = calloc(arm_linux_processors_count, sizeof(struct cpuinfo_arm_linux_processor));
144 if (arm_linux_processors == NULL) {
145 cpuinfo_log_error(
146 "failed to allocate %zu bytes for descriptions of %"PRIu32" ARM logical processors",
147 arm_linux_processors_count * sizeof(struct cpuinfo_arm_linux_processor),
148 arm_linux_processors_count);
149 return;
150 }
151
152 if (max_possible_processors_count) {
153 cpuinfo_linux_detect_possible_processors(
154 arm_linux_processors_count, &arm_linux_processors->flags,
155 sizeof(struct cpuinfo_arm_linux_processor),
156 CPUINFO_LINUX_FLAG_POSSIBLE);
157 }
158
159 if (max_present_processors_count) {
160 cpuinfo_linux_detect_present_processors(
161 arm_linux_processors_count, &arm_linux_processors->flags,
162 sizeof(struct cpuinfo_arm_linux_processor),
163 CPUINFO_LINUX_FLAG_PRESENT);
164 }
165
166 #if defined(__ANDROID__)
167 struct cpuinfo_android_properties android_properties;
168 cpuinfo_arm_android_parse_properties(&android_properties);
169 #else
170 char proc_cpuinfo_hardware[CPUINFO_HARDWARE_VALUE_MAX];
171 #endif
172 char proc_cpuinfo_revision[CPUINFO_REVISION_VALUE_MAX];
173
174 if (!cpuinfo_arm_linux_parse_proc_cpuinfo(
175 #if defined(__ANDROID__)
176 android_properties.proc_cpuinfo_hardware,
177 #else
178 proc_cpuinfo_hardware,
179 #endif
180 proc_cpuinfo_revision,
181 arm_linux_processors_count,
182 arm_linux_processors)) {
183 cpuinfo_log_error("failed to parse processor information from /proc/cpuinfo");
184 return;
185 }
186
187 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
188 if (bitmask_all(arm_linux_processors[i].flags, valid_processor_mask)) {
189 arm_linux_processors[i].flags |= CPUINFO_LINUX_FLAG_VALID;
190 cpuinfo_log_debug("parsed processor %"PRIu32" MIDR 0x%08"PRIx32,
191 i, arm_linux_processors[i].midr);
192 }
193 }
194
195 uint32_t valid_processors = 0, last_midr = 0;
196 #if CPUINFO_ARCH_ARM
197 uint32_t last_architecture_version = 0, last_architecture_flags = 0;
198 #endif
199 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
200 arm_linux_processors[i].system_processor_id = i;
201 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
202 valid_processors += 1;
203
204 if (!(arm_linux_processors[i].flags & CPUINFO_ARM_LINUX_VALID_PROCESSOR)) {
205 /*
206 * Processor is in possible and present lists, but not reported in /proc/cpuinfo.
207 * This is fairly common: high-index processors can be not reported if they are offline.
208 */
209 cpuinfo_log_info("processor %"PRIu32" is not listed in /proc/cpuinfo", i);
210 }
211
212 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_ARM_LINUX_VALID_MIDR)) {
213 last_midr = arm_linux_processors[i].midr;
214 }
215 #if CPUINFO_ARCH_ARM
216 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_ARM_LINUX_VALID_ARCHITECTURE)) {
217 last_architecture_version = arm_linux_processors[i].architecture_version;
218 last_architecture_flags = arm_linux_processors[i].architecture_flags;
219 }
220 #endif
221 } else {
222 /* Processor reported in /proc/cpuinfo, but not in possible and/or present lists: log and ignore */
223 if (!(arm_linux_processors[i].flags & CPUINFO_ARM_LINUX_VALID_PROCESSOR)) {
224 cpuinfo_log_warning("invalid processor %"PRIu32" reported in /proc/cpuinfo", i);
225 }
226 }
227 }
228
229 #if defined(__ANDROID__)
230 const struct cpuinfo_arm_chipset chipset =
231 cpuinfo_arm_android_decode_chipset(&android_properties, valid_processors, 0);
232 #else
233 const struct cpuinfo_arm_chipset chipset =
234 cpuinfo_arm_linux_decode_chipset(proc_cpuinfo_hardware, proc_cpuinfo_revision, valid_processors, 0);
235 #endif
236
237 #if CPUINFO_ARCH_ARM
238 uint32_t isa_features = 0, isa_features2 = 0;
239 #ifdef __ANDROID__
240 /*
241 * On Android before API 20, libc.so does not provide getauxval function.
242 * Thus, we try to dynamically find it, or use two fallback mechanisms:
243 * 1. dlopen libc.so, and try to find getauxval
244 * 2. Parse /proc/self/auxv procfs file
245 * 3. Use features reported in /proc/cpuinfo
246 */
247 if (!cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2)) {
248 /* getauxval can't be used, fall back to parsing /proc/self/auxv */
249 if (!cpuinfo_arm_linux_hwcap_from_procfs(&isa_features, &isa_features2)) {
250 /*
251 * Reading /proc/self/auxv failed, probably due to file permissions.
252 * Use information from /proc/cpuinfo to detect ISA.
253 *
254 * If different processors report different ISA features, take the intersection.
255 */
256 uint32_t processors_with_features = 0;
257 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
258 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID | CPUINFO_ARM_LINUX_VALID_FEATURES)) {
259 if (processors_with_features == 0) {
260 isa_features = arm_linux_processors[i].features;
261 isa_features2 = arm_linux_processors[i].features2;
262 } else {
263 isa_features &= arm_linux_processors[i].features;
264 isa_features2 &= arm_linux_processors[i].features2;
265 }
266 processors_with_features += 1;
267 }
268 }
269 }
270 }
271 #else
272 /* On GNU/Linux getauxval is always available */
273 cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2);
274 #endif
275 cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
276 isa_features, isa_features2,
277 last_midr, last_architecture_version, last_architecture_flags,
278 &chipset, &cpuinfo_isa);
279 #elif CPUINFO_ARCH_ARM64
280 uint32_t isa_features = 0, isa_features2 = 0;
281 /* getauxval is always available on ARM64 Android */
282 cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2);
283 cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
284 isa_features, isa_features2, last_midr, &chipset, &cpuinfo_isa);
285 #endif
286
287 /* Detect min/max frequency and package ID */
288 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
289 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
290 const uint32_t max_frequency = cpuinfo_linux_get_processor_max_frequency(i);
291 if (max_frequency != 0) {
292 arm_linux_processors[i].max_frequency = max_frequency;
293 arm_linux_processors[i].flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY;
294 }
295
296 const uint32_t min_frequency = cpuinfo_linux_get_processor_min_frequency(i);
297 if (min_frequency != 0) {
298 arm_linux_processors[i].min_frequency = min_frequency;
299 arm_linux_processors[i].flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY;
300 }
301
302 if (cpuinfo_linux_get_processor_package_id(i, &arm_linux_processors[i].package_id)) {
303 arm_linux_processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_ID;
304 }
305 }
306 }
307
308 /* Initialize topology group IDs */
309 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
310 arm_linux_processors[i].package_leader_id = i;
311 }
312
313 /* Propagate topology group IDs among siblings */
314 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
315 if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
316 continue;
317 }
318
319 if (arm_linux_processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_ID) {
320 cpuinfo_linux_detect_core_siblings(
321 arm_linux_processors_count, i,
322 (cpuinfo_siblings_callback) cluster_siblings_parser,
323 arm_linux_processors);
324 }
325 }
326
327 /* Propagate all cluster IDs */
328 uint32_t clustered_processors = 0;
329 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
330 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID | CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) {
331 clustered_processors += 1;
332
333 const uint32_t package_leader_id = arm_linux_processors[i].package_leader_id;
334 if (package_leader_id < i) {
335 arm_linux_processors[i].package_leader_id = arm_linux_processors[package_leader_id].package_leader_id;
336 }
337
338 cpuinfo_log_debug("processor %"PRIu32" clustered with processor %"PRIu32" as inferred from system siblings lists",
339 i, arm_linux_processors[i].package_leader_id);
340 }
341 }
342
343 if (clustered_processors != valid_processors) {
344 /*
345 * Topology information about some or all logical processors may be unavailable, for the following reasons:
346 * - Linux kernel is too old, or configured without support for topology information in sysfs.
347 * - Core is offline, and Linux kernel is configured to not report topology for offline cores.
348 *
349 * In this case, we assign processors to clusters using two methods:
350 * - Try heuristic cluster configurations (e.g. 6-core SoC usually has 4+2 big.LITTLE configuration).
351 * - If heuristic failed, assign processors to core clusters in a sequential scan.
352 */
353 if (!cpuinfo_arm_linux_detect_core_clusters_by_heuristic(valid_processors, arm_linux_processors_count, arm_linux_processors)) {
354 cpuinfo_arm_linux_detect_core_clusters_by_sequential_scan(arm_linux_processors_count, arm_linux_processors);
355 }
356 }
357
358 cpuinfo_arm_linux_count_cluster_processors(arm_linux_processors_count, arm_linux_processors);
359
360 const uint32_t cluster_count = cpuinfo_arm_linux_detect_cluster_midr(
361 &chipset,
362 arm_linux_processors_count, valid_processors, arm_linux_processors);
363
364 /* Initialize core vendor, uarch, MIDR, and frequency for every logical processor */
365 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
366 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
367 const uint32_t cluster_leader = arm_linux_processors[i].package_leader_id;
368 if (cluster_leader == i) {
369 /* Cluster leader: decode core vendor and uarch */
370 cpuinfo_arm_decode_vendor_uarch(
371 arm_linux_processors[cluster_leader].midr,
372 #if CPUINFO_ARCH_ARM
373 !!(arm_linux_processors[cluster_leader].features & CPUINFO_ARM_LINUX_FEATURE_VFPV4),
374 #endif
375 &arm_linux_processors[cluster_leader].vendor,
376 &arm_linux_processors[cluster_leader].uarch);
377 } else {
378 /* Cluster non-leader: copy vendor, uarch, MIDR, and frequency from cluster leader */
379 arm_linux_processors[i].flags |= arm_linux_processors[cluster_leader].flags &
380 (CPUINFO_ARM_LINUX_VALID_MIDR | CPUINFO_LINUX_FLAG_MAX_FREQUENCY);
381 arm_linux_processors[i].midr = arm_linux_processors[cluster_leader].midr;
382 arm_linux_processors[i].vendor = arm_linux_processors[cluster_leader].vendor;
383 arm_linux_processors[i].uarch = arm_linux_processors[cluster_leader].uarch;
384 arm_linux_processors[i].max_frequency = arm_linux_processors[cluster_leader].max_frequency;
385 }
386 }
387 }
388
389 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
390 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
391 cpuinfo_log_debug("post-analysis processor %"PRIu32": MIDR %08"PRIx32" frequency %"PRIu32,
392 i, arm_linux_processors[i].midr, arm_linux_processors[i].max_frequency);
393 }
394 }
395
396 qsort(arm_linux_processors, arm_linux_processors_count,
397 sizeof(struct cpuinfo_arm_linux_processor), cmp_arm_linux_processor);
398
399 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
400 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
401 cpuinfo_log_debug("post-sort processor %"PRIu32": system id %"PRIu32" MIDR %08"PRIx32" frequency %"PRIu32,
402 i, arm_linux_processors[i].system_processor_id, arm_linux_processors[i].midr, arm_linux_processors[i].max_frequency);
403 }
404 }
405
406 uint32_t uarchs_count = 0;
407 enum cpuinfo_uarch last_uarch;
408 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
409 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
410 if (uarchs_count == 0 || arm_linux_processors[i].uarch != last_uarch) {
411 last_uarch = arm_linux_processors[i].uarch;
412 uarchs_count += 1;
413 }
414 arm_linux_processors[i].uarch_index = uarchs_count - 1;
415 }
416 }
417
418 /*
419 * Assumptions:
420 * - No SMP (i.e. each core supports only one hardware thread).
421 * - Level 1 instruction and data caches are private to the core clusters.
422 * - Level 2 and level 3 cache is shared between cores in the same cluster.
423 */
424 cpuinfo_arm_chipset_to_string(&chipset, package.name);
425 package.processor_count = valid_processors;
426 package.core_count = valid_processors;
427 package.cluster_count = cluster_count;
428
429 processors = calloc(valid_processors, sizeof(struct cpuinfo_processor));
430 if (processors == NULL) {
431 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors",
432 valid_processors * sizeof(struct cpuinfo_processor), valid_processors);
433 goto cleanup;
434 }
435
436 cores = calloc(valid_processors, sizeof(struct cpuinfo_core));
437 if (cores == NULL) {
438 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores",
439 valid_processors * sizeof(struct cpuinfo_core), valid_processors);
440 goto cleanup;
441 }
442
443 clusters = calloc(cluster_count, sizeof(struct cpuinfo_cluster));
444 if (clusters == NULL) {
445 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters",
446 cluster_count * sizeof(struct cpuinfo_cluster), cluster_count);
447 goto cleanup;
448 }
449
450 uarchs = calloc(uarchs_count, sizeof(struct cpuinfo_uarch_info));
451 if (uarchs == NULL) {
452 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" microarchitectures",
453 uarchs_count * sizeof(struct cpuinfo_uarch_info), uarchs_count);
454 goto cleanup;
455 }
456
457 linux_cpu_to_processor_map = calloc(arm_linux_processors_count, sizeof(struct cpuinfo_processor*));
458 if (linux_cpu_to_processor_map == NULL) {
459 cpuinfo_log_error("failed to allocate %zu bytes for %"PRIu32" logical processor mapping entries",
460 arm_linux_processors_count * sizeof(struct cpuinfo_processor*), arm_linux_processors_count);
461 goto cleanup;
462 }
463
464 linux_cpu_to_core_map = calloc(arm_linux_processors_count, sizeof(struct cpuinfo_core*));
465 if (linux_cpu_to_core_map == NULL) {
466 cpuinfo_log_error("failed to allocate %zu bytes for %"PRIu32" core mapping entries",
467 arm_linux_processors_count * sizeof(struct cpuinfo_core*), arm_linux_processors_count);
468 goto cleanup;
469 }
470
471 if (uarchs_count > 1) {
472 linux_cpu_to_uarch_index_map = calloc(arm_linux_processors_count, sizeof(uint32_t));
473 if (linux_cpu_to_uarch_index_map == NULL) {
474 cpuinfo_log_error("failed to allocate %zu bytes for %"PRIu32" uarch index mapping entries",
475 arm_linux_processors_count * sizeof(uint32_t), arm_linux_processors_count);
476 goto cleanup;
477 }
478 }
479
480 l1i = calloc(valid_processors, sizeof(struct cpuinfo_cache));
481 if (l1i == NULL) {
482 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1I caches",
483 valid_processors * sizeof(struct cpuinfo_cache), valid_processors);
484 goto cleanup;
485 }
486
487 l1d = calloc(valid_processors, sizeof(struct cpuinfo_cache));
488 if (l1d == NULL) {
489 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1D caches",
490 valid_processors * sizeof(struct cpuinfo_cache), valid_processors);
491 goto cleanup;
492 }
493
494 uint32_t uarchs_index = 0;
495 for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
496 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
497 if (uarchs_index == 0 || arm_linux_processors[i].uarch != last_uarch) {
498 last_uarch = arm_linux_processors[i].uarch;
499 uarchs[uarchs_index] = (struct cpuinfo_uarch_info) {
500 .uarch = arm_linux_processors[i].uarch,
501 .midr = arm_linux_processors[i].midr,
502 };
503 uarchs_index += 1;
504 }
505 uarchs[uarchs_index - 1].processor_count += 1;
506 uarchs[uarchs_index - 1].core_count += 1;
507 }
508 }
509
510 uint32_t l2_count = 0, l3_count = 0, big_l3_size = 0, cluster_id = UINT32_MAX;
511 /* Indication whether L3 (if it exists) is shared between all cores */
512 bool shared_l3 = true;
513 /* Populate cache information structures in l1i, l1d */
514 for (uint32_t i = 0; i < valid_processors; i++) {
515 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
516 cluster_id += 1;
517 clusters[cluster_id] = (struct cpuinfo_cluster) {
518 .processor_start = i,
519 .processor_count = arm_linux_processors[i].package_processor_count,
520 .core_start = i,
521 .core_count = arm_linux_processors[i].package_processor_count,
522 .cluster_id = cluster_id,
523 .package = &package,
524 .vendor = arm_linux_processors[i].vendor,
525 .uarch = arm_linux_processors[i].uarch,
526 .midr = arm_linux_processors[i].midr,
527 };
528 }
529
530 processors[i].smt_id = 0;
531 processors[i].core = cores + i;
532 processors[i].cluster = clusters + cluster_id;
533 processors[i].package = &package;
534 processors[i].linux_id = (int) arm_linux_processors[i].system_processor_id;
535 processors[i].cache.l1i = l1i + i;
536 processors[i].cache.l1d = l1d + i;
537 linux_cpu_to_processor_map[arm_linux_processors[i].system_processor_id] = &processors[i];
538
539 cores[i].processor_start = i;
540 cores[i].processor_count = 1;
541 cores[i].core_id = i;
542 cores[i].cluster = clusters + cluster_id;
543 cores[i].package = &package;
544 cores[i].vendor = arm_linux_processors[i].vendor;
545 cores[i].uarch = arm_linux_processors[i].uarch;
546 cores[i].midr = arm_linux_processors[i].midr;
547 linux_cpu_to_core_map[arm_linux_processors[i].system_processor_id] = &cores[i];
548
549 if (linux_cpu_to_uarch_index_map != NULL) {
550 linux_cpu_to_uarch_index_map[arm_linux_processors[i].system_processor_id] =
551 arm_linux_processors[i].uarch_index;
552 }
553
554 struct cpuinfo_cache temp_l2 = { 0 }, temp_l3 = { 0 };
555 cpuinfo_arm_decode_cache(
556 arm_linux_processors[i].uarch,
557 arm_linux_processors[i].package_processor_count,
558 arm_linux_processors[i].midr,
559 &chipset,
560 cluster_id,
561 arm_linux_processors[i].architecture_version,
562 &l1i[i], &l1d[i], &temp_l2, &temp_l3);
563 l1i[i].processor_start = l1d[i].processor_start = i;
564 l1i[i].processor_count = l1d[i].processor_count = 1;
565 #if CPUINFO_ARCH_ARM
566 /* L1I reported in /proc/cpuinfo overrides defaults */
567 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_ARM_LINUX_VALID_ICACHE)) {
568 l1i[i] = (struct cpuinfo_cache) {
569 .size = arm_linux_processors[i].proc_cpuinfo_cache.i_size,
570 .associativity = arm_linux_processors[i].proc_cpuinfo_cache.i_assoc,
571 .sets = arm_linux_processors[i].proc_cpuinfo_cache.i_sets,
572 .partitions = 1,
573 .line_size = arm_linux_processors[i].proc_cpuinfo_cache.i_line_length
574 };
575 }
576 /* L1D reported in /proc/cpuinfo overrides defaults */
577 if (bitmask_all(arm_linux_processors[i].flags, CPUINFO_ARM_LINUX_VALID_DCACHE)) {
578 l1d[i] = (struct cpuinfo_cache) {
579 .size = arm_linux_processors[i].proc_cpuinfo_cache.d_size,
580 .associativity = arm_linux_processors[i].proc_cpuinfo_cache.d_assoc,
581 .sets = arm_linux_processors[i].proc_cpuinfo_cache.d_sets,
582 .partitions = 1,
583 .line_size = arm_linux_processors[i].proc_cpuinfo_cache.d_line_length
584 };
585 }
586 #endif
587
588 if (temp_l3.size != 0) {
589 /*
590 * Assumptions:
591 * - L2 is private to each core
592 * - L3 is shared by cores in the same cluster
593 * - If cores in different clusters report the same L3, it is shared between all cores.
594 */
595 l2_count += 1;
596 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
597 if (cluster_id == 0) {
598 big_l3_size = temp_l3.size;
599 l3_count = 1;
600 } else if (temp_l3.size != big_l3_size) {
601 /* If some cores have different L3 size, L3 is not shared between all cores */
602 shared_l3 = false;
603 l3_count += 1;
604 }
605 }
606 } else {
607 /* If some cores don't have L3 cache, L3 is not shared between all cores */
608 shared_l3 = false;
609 if (temp_l2.size != 0) {
610 /* Assume L2 is shared by cores in the same cluster */
611 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
612 l2_count += 1;
613 }
614 }
615 }
616 }
617
618 if (l2_count != 0) {
619 l2 = calloc(l2_count, sizeof(struct cpuinfo_cache));
620 if (l2 == NULL) {
621 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L2 caches",
622 l2_count * sizeof(struct cpuinfo_cache), l2_count);
623 goto cleanup;
624 }
625
626 if (l3_count != 0) {
627 l3 = calloc(l3_count, sizeof(struct cpuinfo_cache));
628 if (l3 == NULL) {
629 cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L3 caches",
630 l3_count * sizeof(struct cpuinfo_cache), l3_count);
631 goto cleanup;
632 }
633 }
634 }
635
636 cluster_id = UINT32_MAX;
637 uint32_t l2_index = UINT32_MAX, l3_index = UINT32_MAX;
638 for (uint32_t i = 0; i < valid_processors; i++) {
639 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
640 cluster_id++;
641 }
642
643 struct cpuinfo_cache dummy_l1i, dummy_l1d, temp_l2 = { 0 }, temp_l3 = { 0 };
644 cpuinfo_arm_decode_cache(
645 arm_linux_processors[i].uarch,
646 arm_linux_processors[i].package_processor_count,
647 arm_linux_processors[i].midr,
648 &chipset,
649 cluster_id,
650 arm_linux_processors[i].architecture_version,
651 &dummy_l1i, &dummy_l1d, &temp_l2, &temp_l3);
652
653 if (temp_l3.size != 0) {
654 /*
655 * Assumptions:
656 * - L2 is private to each core
657 * - L3 is shared by cores in the same cluster
658 * - If cores in different clusters report the same L3, it is shared between all cores.
659 */
660 l2_index += 1;
661 l2[l2_index] = (struct cpuinfo_cache) {
662 .size = temp_l2.size,
663 .associativity = temp_l2.associativity,
664 .sets = temp_l2.sets,
665 .partitions = 1,
666 .line_size = temp_l2.line_size,
667 .flags = temp_l2.flags,
668 .processor_start = i,
669 .processor_count = 1,
670 };
671 processors[i].cache.l2 = l2 + l2_index;
672 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
673 l3_index += 1;
674 if (l3_index < l3_count) {
675 l3[l3_index] = (struct cpuinfo_cache) {
676 .size = temp_l3.size,
677 .associativity = temp_l3.associativity,
678 .sets = temp_l3.sets,
679 .partitions = 1,
680 .line_size = temp_l3.line_size,
681 .flags = temp_l3.flags,
682 .processor_start = i,
683 .processor_count =
684 shared_l3 ? valid_processors : arm_linux_processors[i].package_processor_count,
685 };
686 }
687 }
688 if (shared_l3) {
689 processors[i].cache.l3 = l3;
690 } else if (l3_index < l3_count) {
691 processors[i].cache.l3 = l3 + l3_index;
692 }
693 } else if (temp_l2.size != 0) {
694 /* Assume L2 is shared by cores in the same cluster */
695 if (arm_linux_processors[i].package_leader_id == arm_linux_processors[i].system_processor_id) {
696 l2_index += 1;
697 l2[l2_index] = (struct cpuinfo_cache) {
698 .size = temp_l2.size,
699 .associativity = temp_l2.associativity,
700 .sets = temp_l2.sets,
701 .partitions = 1,
702 .line_size = temp_l2.line_size,
703 .flags = temp_l2.flags,
704 .processor_start = i,
705 .processor_count = arm_linux_processors[i].package_processor_count,
706 };
707 }
708 processors[i].cache.l2 = l2 + l2_index;
709 }
710 }
711
712 /* Commit */
713 cpuinfo_processors = processors;
714 cpuinfo_cores = cores;
715 cpuinfo_clusters = clusters;
716 cpuinfo_packages = &package;
717 cpuinfo_uarchs = uarchs;
718 cpuinfo_cache[cpuinfo_cache_level_1i] = l1i;
719 cpuinfo_cache[cpuinfo_cache_level_1d] = l1d;
720 cpuinfo_cache[cpuinfo_cache_level_2] = l2;
721 cpuinfo_cache[cpuinfo_cache_level_3] = l3;
722
723 cpuinfo_processors_count = valid_processors;
724 cpuinfo_cores_count = valid_processors;
725 cpuinfo_clusters_count = cluster_count;
726 cpuinfo_packages_count = 1;
727 cpuinfo_uarchs_count = uarchs_count;
728 cpuinfo_cache_count[cpuinfo_cache_level_1i] = valid_processors;
729 cpuinfo_cache_count[cpuinfo_cache_level_1d] = valid_processors;
730 cpuinfo_cache_count[cpuinfo_cache_level_2] = l2_count;
731 cpuinfo_cache_count[cpuinfo_cache_level_3] = l3_count;
732 cpuinfo_max_cache_size = cpuinfo_arm_compute_max_cache_size(&processors[0]);
733
734 cpuinfo_linux_cpu_max = arm_linux_processors_count;
735 cpuinfo_linux_cpu_to_processor_map = linux_cpu_to_processor_map;
736 cpuinfo_linux_cpu_to_core_map = linux_cpu_to_core_map;
737 cpuinfo_linux_cpu_to_uarch_index_map = linux_cpu_to_uarch_index_map;
738
739 __sync_synchronize();
740
741 cpuinfo_is_initialized = true;
742
743 processors = NULL;
744 cores = NULL;
745 clusters = NULL;
746 uarchs = NULL;
747 l1i = l1d = l2 = l3 = NULL;
748 linux_cpu_to_processor_map = NULL;
749 linux_cpu_to_core_map = NULL;
750 linux_cpu_to_uarch_index_map = NULL;
751
752 cleanup:
753 free(arm_linux_processors);
754 free(processors);
755 free(cores);
756 free(clusters);
757 free(uarchs);
758 free(l1i);
759 free(l1d);
760 free(l2);
761 free(l3);
762 free(linux_cpu_to_processor_map);
763 free(linux_cpu_to_core_map);
764 free(linux_cpu_to_uarch_index_map);
765 }
766