| | #include <stdint.h> |
| | #include <stddef.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| |
|
| | #include <cpuinfo.h> |
| | #include <arm/linux/api.h> |
| | #if defined(__ANDROID__) |
| | #include <arm/android/api.h> |
| | #endif |
| | #include <arm/api.h> |
| | #include <arm/midr.h> |
| | #include <linux/api.h> |
| | #include <cpuinfo/internal-api.h> |
| | #include <cpuinfo/log.h> |
| |
|
| | static inline bool bitmask_all(uint32_t bitfield, uint32_t mask) { |
| | return (bitfield & mask) == mask; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool 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]) |
| | { |
| | uint32_t cluster_processors[3]; |
| | switch (usable_processors) { |
| | case 10: |
| | cluster_processors[0] = 4; |
| | cluster_processors[1] = 4; |
| | cluster_processors[2] = 2; |
| | break; |
| | case 8: |
| | cluster_processors[0] = 4; |
| | cluster_processors[1] = 4; |
| | break; |
| | case 6: |
| | cluster_processors[0] = 4; |
| | cluster_processors[1] = 2; |
| | break; |
| | #if defined(__ANDROID__) && CPUINFO_ARCH_ARM |
| | case 5: |
| | |
| | |
| | |
| | |
| | cluster_processors[0] = 4; |
| | cluster_processors[1] = 1; |
| | break; |
| | #endif |
| | default: |
| | return false; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | uint32_t cluster = 0; |
| | uint32_t expected_cluster_processors = 0; |
| | uint32_t cluster_start, cluster_flags, cluster_midr, cluster_max_frequency, cluster_min_frequency; |
| | bool expected_cluster_exists; |
| | for (uint32_t i = 0; i < max_processors; i++) { |
| | if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| | if (expected_cluster_processors == 0) { |
| | |
| |
|
| | expected_cluster_exists = !!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER); |
| | if (expected_cluster_exists) { |
| | if (processors[i].package_leader_id != i) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "processor %"PRIu32" is expected to start a new cluster #%"PRIu32" with %"PRIu32" cores, " |
| | "but system siblings lists reported it as a sibling of processor %"PRIu32, |
| | i, cluster, cluster_processors[cluster], processors[i].package_leader_id); |
| | return false; |
| | } |
| | } else { |
| | cluster_flags = 0; |
| | } |
| |
|
| | cluster_start = i; |
| | expected_cluster_processors = cluster_processors[cluster++]; |
| | } else { |
| | |
| |
|
| | if (expected_cluster_exists) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if ((processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) == 0) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "processor %"PRIu32" is expected to belong to the cluster of processor %"PRIu32", " |
| | "but system siblings lists did not report it as a sibling of processor %"PRIu32, |
| | i, cluster_start, cluster_start); |
| | return false; |
| | } |
| | if (processors[i].package_leader_id != cluster_start) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "processor %"PRIu32" is expected to belong to the cluster of processor %"PRIu32", " |
| | "but system siblings lists reported it to belong to the cluster of processor %"PRIu32, |
| | i, cluster_start, cluster_start); |
| | return false; |
| | } |
| | } else { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "processor %"PRIu32" is expected to be unassigned to any cluster, " |
| | "but system siblings lists reported it to belong to the cluster of processor %"PRIu32, |
| | i, processors[i].package_leader_id); |
| | return false; |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { |
| | if (cluster_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { |
| | if (cluster_min_frequency != processors[i].min_frequency) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "minimum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of its expected cluster (%"PRIu32" KHz)", |
| | i, processors[i].min_frequency, cluster_min_frequency); |
| | return false; |
| | } |
| | } else { |
| | cluster_min_frequency = processors[i].min_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { |
| | if (cluster_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { |
| | if (cluster_max_frequency != processors[i].max_frequency) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "maximum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of its expected cluster (%"PRIu32" KHz)", |
| | i, processors[i].max_frequency, cluster_max_frequency); |
| | return false; |
| | } |
| | } else { |
| | cluster_max_frequency = processors[i].max_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK)) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "CPU Implementer of processor %"PRIu32" (0x%02"PRIx32") is different than of its expected cluster (0x%02"PRIx32")", |
| | i, midr_get_implementer(processors[i].midr), midr_get_implementer(cluster_midr)); |
| | return false; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_VARIANT) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_VARIANT_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_VARIANT_MASK)) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "CPU Variant of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")", |
| | i, midr_get_variant(processors[i].midr), midr_get_variant(cluster_midr)); |
| | return false; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_PART) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_PART_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_PART_MASK)) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "CPU Part of processor %"PRIu32" (0x%03"PRIx32") is different than of its expected cluster (0x%03"PRIx32")", |
| | i, midr_get_part(processors[i].midr), midr_get_part(cluster_midr)); |
| | return false; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_part(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_REVISION) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_REVISION_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_REVISION_MASK)) { |
| | cpuinfo_log_debug( |
| | "heuristic detection of core clusters failed: " |
| | "CPU Revision of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")", |
| | i, midr_get_revision(cluster_midr), midr_get_revision(processors[i].midr)); |
| | return false; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION; |
| | } |
| | } |
| | } |
| | } |
| | expected_cluster_processors--; |
| | } |
| | } |
| |
|
| | |
| | cluster = 0; |
| | expected_cluster_processors = 0; |
| | for (uint32_t i = 0; i < max_processors; i++) { |
| | if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| | if (expected_cluster_processors == 0) { |
| | |
| |
|
| | cluster_start = i; |
| | expected_cluster_processors = cluster_processors[cluster++]; |
| | } else { |
| | |
| |
|
| | if (!(processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) { |
| | cpuinfo_log_debug("assigned processor %"PRIu32" to cluster of processor %"PRIu32" based on heuristic", |
| | i, cluster_start); |
| | } |
| |
|
| | processors[i].package_leader_id = cluster_start; |
| | processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER; |
| | } |
| | expected_cluster_processors--; |
| | } |
| | } |
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void cpuinfo_arm_linux_detect_core_clusters_by_sequential_scan( |
| | uint32_t max_processors, |
| | struct cpuinfo_arm_linux_processor processors[restrict static max_processors]) |
| | { |
| | uint32_t cluster_flags = 0; |
| | uint32_t cluster_processors = 0; |
| | uint32_t cluster_start, cluster_midr, cluster_max_frequency, cluster_min_frequency; |
| | for (uint32_t i = 0; i < max_processors; i++) { |
| | if ((processors[i].flags & (CPUINFO_LINUX_FLAG_VALID | CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) == CPUINFO_LINUX_FLAG_VALID) { |
| | if (cluster_processors == 0) { |
| | goto new_cluster; |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { |
| | if (cluster_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { |
| | if (cluster_min_frequency != processors[i].min_frequency) { |
| | cpuinfo_log_info( |
| | "minimum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of preceding cluster (%"PRIu32" KHz); " |
| | "processor %"PRIu32" starts to a new cluster", |
| | i, processors[i].min_frequency, cluster_min_frequency, i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_min_frequency = processors[i].min_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { |
| | if (cluster_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { |
| | if (cluster_max_frequency != processors[i].max_frequency) { |
| | cpuinfo_log_debug( |
| | "maximum frequency of processor %"PRIu32" (%"PRIu32" KHz) is different than of preceding cluster (%"PRIu32" KHz); " |
| | "processor %"PRIu32" starts a new cluster", |
| | i, processors[i].max_frequency, cluster_max_frequency, i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_max_frequency = processors[i].max_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK)) { |
| | cpuinfo_log_debug( |
| | "CPU Implementer of processor %"PRIu32" (0x%02"PRIx32") is different than of preceding cluster (0x%02"PRIx32"); " |
| | "processor %"PRIu32" starts to a new cluster", |
| | i, midr_get_implementer(processors[i].midr), midr_get_implementer(cluster_midr), i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_VARIANT) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_VARIANT_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_VARIANT_MASK)) { |
| | cpuinfo_log_debug( |
| | "CPU Variant of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")" |
| | "processor %"PRIu32" starts to a new cluster", |
| | i, midr_get_variant(processors[i].midr), midr_get_variant(cluster_midr), i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_PART) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_PART_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_PART_MASK)) { |
| | cpuinfo_log_debug( |
| | "CPU Part of processor %"PRIu32" (0x%03"PRIx32") is different than of its expected cluster (0x%03"PRIx32")" |
| | "processor %"PRIu32" starts to a new cluster", |
| | i, midr_get_part(processors[i].midr), midr_get_part(cluster_midr), i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_part(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART; |
| | } |
| | } |
| |
|
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) { |
| | if (cluster_flags & CPUINFO_ARM_LINUX_VALID_REVISION) { |
| | if ((cluster_midr & CPUINFO_ARM_MIDR_REVISION_MASK) != (processors[i].midr & CPUINFO_ARM_MIDR_REVISION_MASK)) { |
| | cpuinfo_log_debug( |
| | "CPU Revision of processor %"PRIu32" (0x%"PRIx32") is different than of its expected cluster (0x%"PRIx32")" |
| | "processor %"PRIu32" starts to a new cluster", |
| | i, midr_get_revision(cluster_midr), midr_get_revision(processors[i].midr), i); |
| | goto new_cluster; |
| | } |
| | } else { |
| | cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION; |
| | } |
| | } |
| |
|
| | |
| | cluster_processors++; |
| | processors[i].package_leader_id = cluster_start; |
| | processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER; |
| | cpuinfo_log_debug("assigned processor %"PRIu32" to preceding cluster of processor %"PRIu32, i, cluster_start); |
| | continue; |
| |
|
| | new_cluster: |
| | |
| | cluster_start = i; |
| | processors[i].package_leader_id = i; |
| | processors[i].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER; |
| | cluster_processors = 1; |
| |
|
| | |
| | cluster_flags = 0; |
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { |
| | cluster_min_frequency = processors[i].min_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MIN_FREQUENCY; |
| | } |
| | if (processors[i].flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { |
| | cluster_max_frequency = processors[i].max_frequency; |
| | cluster_flags |= CPUINFO_LINUX_FLAG_MAX_FREQUENCY; |
| | } |
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_IMPLEMENTER) { |
| | cluster_midr = midr_copy_implementer(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_IMPLEMENTER; |
| | } |
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_VARIANT) { |
| | cluster_midr = midr_copy_variant(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_VARIANT; |
| | } |
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_PART) { |
| | cluster_midr = midr_copy_part(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_PART; |
| | } |
| | if (processors[i].flags & CPUINFO_ARM_LINUX_VALID_REVISION) { |
| | cluster_midr = midr_copy_revision(cluster_midr, processors[i].midr); |
| | cluster_flags |= CPUINFO_ARM_LINUX_VALID_REVISION; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void cpuinfo_arm_linux_count_cluster_processors( |
| | uint32_t max_processors, |
| | struct cpuinfo_arm_linux_processor processors[restrict static max_processors]) |
| | { |
| | |
| | for (uint32_t i = 0; i < max_processors; i++) { |
| | if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| | const uint32_t package_leader_id = processors[i].package_leader_id; |
| | processors[package_leader_id].package_processor_count += 1; |
| | } |
| | } |
| | |
| | for (uint32_t i = 0; i < max_processors; i++) { |
| | if (bitmask_all(processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| | const uint32_t package_leader_id = processors[i].package_leader_id; |
| | processors[i].package_processor_count = processors[package_leader_id].package_processor_count; |
| | } |
| | } |
| | } |
| |
|