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