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