From a8fb3dd0aa41013e8ec5c93900a1c81e26ef6552 Mon Sep 17 00:00:00 2001 From: Marat Dukhan Date: Wed, 9 Aug 2017 13:49:39 -0700 Subject: Detect big.LITTLE ARM systems --- src/arm/linux/api.h | 303 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 217 insertions(+), 86 deletions(-) (limited to 'src/arm/linux/api.h') diff --git a/src/arm/linux/api.h b/src/arm/linux/api.h index cd62700..6ccadb2 100644 --- a/src/arm/linux/api.h +++ b/src/arm/linux/api.h @@ -4,18 +4,18 @@ #include #include +#include +#include -#define PROC_CPUINFO_ARCH_T UINT32_C(0x00000001) -#define PROC_CPUINFO_ARCH_E UINT32_C(0x00000002) -#define PROC_CPUINFO_ARCH_J UINT32_C(0x00000004) +#define CPUINFO_ARM_LINUX_ARCH_T UINT32_C(0x00000001) +#define CPUINFO_ARM_LINUX_ARCH_E UINT32_C(0x00000002) +#define CPUINFO_ARM_LINUX_ARCH_J UINT32_C(0x00000004) -struct proc_cpuinfo_arch { - uint32_t version; - uint32_t flags; -}; +#define CPUINFO_ARM_LINUX_ARCH_TE UINT32_C(0x00000003) +#define CPUINFO_ARM_LINUX_ARCH_TEJ UINT32_C(0x00000007) -struct proc_cpuinfo_cache { +struct cpuinfo_arm_linux_proc_cpuinfo_cache { uint32_t i_size; uint32_t i_assoc; uint32_t i_line_length; @@ -29,107 +29,238 @@ struct proc_cpuinfo_cache { #if CPUINFO_ARCH_ARM /* arch/arm/include/uapi/asm/hwcap.h */ - #define PROC_CPUINFO_FEATURE_SWP UINT32_C(0x00000001) - #define PROC_CPUINFO_FEATURE_HALF UINT32_C(0x00000002) - #define PROC_CPUINFO_FEATURE_THUMB UINT32_C(0x00000004) - #define PROC_CPUINFO_FEATURE_26BIT UINT32_C(0x00000008) - #define PROC_CPUINFO_FEATURE_FASTMULT UINT32_C(0x00000010) - #define PROC_CPUINFO_FEATURE_FPA UINT32_C(0x00000020) - #define PROC_CPUINFO_FEATURE_VFP UINT32_C(0x00000040) - #define PROC_CPUINFO_FEATURE_EDSP UINT32_C(0x00000080) - #define PROC_CPUINFO_FEATURE_JAVA UINT32_C(0x00000100) - #define PROC_CPUINFO_FEATURE_IWMMXT UINT32_C(0x00000200) - #define PROC_CPUINFO_FEATURE_CRUNCH UINT32_C(0x00000400) - #define PROC_CPUINFO_FEATURE_THUMBEE UINT32_C(0x00000800) - #define PROC_CPUINFO_FEATURE_NEON UINT32_C(0x00001000) - #define PROC_CPUINFO_FEATURE_VFPV3 UINT32_C(0x00002000) - #define PROC_CPUINFO_FEATURE_VFPV3D16 UINT32_C(0x00004000) /* Also set for VFPv4 with 16 double-precision registers */ - #define PROC_CPUINFO_FEATURE_TLS UINT32_C(0x00008000) - #define PROC_CPUINFO_FEATURE_VFPV4 UINT32_C(0x00010000) - #define PROC_CPUINFO_FEATURE_IDIVA UINT32_C(0x00020000) - #define PROC_CPUINFO_FEATURE_IDIVT UINT32_C(0x00040000) - #define PROC_CPUINFO_FEATURE_IDIV UINT32_C(0x00060000) - #define PROC_CPUINFO_FEATURE_VFPD32 UINT32_C(0x00080000) - #define PROC_CPUINFO_FEATURE_LPAE UINT32_C(0x00100000) - #define PROC_CPUINFO_FEATURE_EVTSTRM UINT32_C(0x00200000) - - #define PROC_CPUINFO_FEATURE2_AES UINT32_C(0x00000001) - #define PROC_CPUINFO_FEATURE2_PMULL UINT32_C(0x00000002) - #define PROC_CPUINFO_FEATURE2_SHA1 UINT32_C(0x00000004) - #define PROC_CPUINFO_FEATURE2_SHA2 UINT32_C(0x00000008) - #define PROC_CPUINFO_FEATURE2_CRC32 UINT32_C(0x00000010) + #define CPUINFO_ARM_LINUX_FEATURE_SWP UINT32_C(0x00000001) + #define CPUINFO_ARM_LINUX_FEATURE_HALF UINT32_C(0x00000002) + #define CPUINFO_ARM_LINUX_FEATURE_THUMB UINT32_C(0x00000004) + #define CPUINFO_ARM_LINUX_FEATURE_26BIT UINT32_C(0x00000008) + #define CPUINFO_ARM_LINUX_FEATURE_FASTMULT UINT32_C(0x00000010) + #define CPUINFO_ARM_LINUX_FEATURE_FPA UINT32_C(0x00000020) + #define CPUINFO_ARM_LINUX_FEATURE_VFP UINT32_C(0x00000040) + #define CPUINFO_ARM_LINUX_FEATURE_EDSP UINT32_C(0x00000080) + #define CPUINFO_ARM_LINUX_FEATURE_JAVA UINT32_C(0x00000100) + #define CPUINFO_ARM_LINUX_FEATURE_IWMMXT UINT32_C(0x00000200) + #define CPUINFO_ARM_LINUX_FEATURE_CRUNCH UINT32_C(0x00000400) + #define CPUINFO_ARM_LINUX_FEATURE_THUMBEE UINT32_C(0x00000800) + #define CPUINFO_ARM_LINUX_FEATURE_NEON UINT32_C(0x00001000) + #define CPUINFO_ARM_LINUX_FEATURE_VFPV3 UINT32_C(0x00002000) + #define CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 UINT32_C(0x00004000) /* Also set for VFPv4 with 16 double-precision registers */ + #define CPUINFO_ARM_LINUX_FEATURE_TLS UINT32_C(0x00008000) + #define CPUINFO_ARM_LINUX_FEATURE_VFPV4 UINT32_C(0x00010000) + #define CPUINFO_ARM_LINUX_FEATURE_IDIVA UINT32_C(0x00020000) + #define CPUINFO_ARM_LINUX_FEATURE_IDIVT UINT32_C(0x00040000) + #define CPUINFO_ARM_LINUX_FEATURE_IDIV UINT32_C(0x00060000) + #define CPUINFO_ARM_LINUX_FEATURE_VFPD32 UINT32_C(0x00080000) + #define CPUINFO_ARM_LINUX_FEATURE_LPAE UINT32_C(0x00100000) + #define CPUINFO_ARM_LINUX_FEATURE_EVTSTRM UINT32_C(0x00200000) + + #define CPUINFO_ARM_LINUX_FEATURE2_AES UINT32_C(0x00000001) + #define CPUINFO_ARM_LINUX_FEATURE2_PMULL UINT32_C(0x00000002) + #define CPUINFO_ARM_LINUX_FEATURE2_SHA1 UINT32_C(0x00000004) + #define CPUINFO_ARM_LINUX_FEATURE2_SHA2 UINT32_C(0x00000008) + #define CPUINFO_ARM_LINUX_FEATURE2_CRC32 UINT32_C(0x00000010) #elif CPUINFO_ARCH_ARM64 /* arch/arm64/include/uapi/asm/hwcap.h */ - #define PROC_CPUINFO_FEATURE_FP UINT32_C(0x00000001) - #define PROC_CPUINFO_FEATURE_ASIMD UINT32_C(0x00000002) - #define PROC_CPUINFO_FEATURE_EVTSTRM UINT32_C(0x00000004) - #define PROC_CPUINFO_FEATURE_AES UINT32_C(0x00000008) - #define PROC_CPUINFO_FEATURE_PMULL UINT32_C(0x00000010) - #define PROC_CPUINFO_FEATURE_SHA1 UINT32_C(0x00000020) - #define PROC_CPUINFO_FEATURE_SHA2 UINT32_C(0x00000040) - #define PROC_CPUINFO_FEATURE_CRC32 UINT32_C(0x00000080) - #define PROC_CPUINFO_FEATURE_ATOMICS UINT32_C(0x00000100) - #define PROC_CPUINFO_FEATURE_FPHP UINT32_C(0x00000200) - #define PROC_CPUINFO_FEATURE_ASIMDHP UINT32_C(0x00000400) - #define PROC_CPUINFO_FEATURE_CPUID UINT32_C(0x00000800) - #define PROC_CPUINFO_FEATURE_ASIMDRDM UINT32_C(0x00001000) - #define PROC_CPUINFO_FEATURE_JSCVT UINT32_C(0x00002000) - #define PROC_CPUINFO_FEATURE_FCMA UINT32_C(0x00004000) - #define PROC_CPUINFO_FEATURE_LRCPC UINT32_C(0x00008000) + #define CPUINFO_ARM_LINUX_FEATURE_FP UINT32_C(0x00000001) + #define CPUINFO_ARM_LINUX_FEATURE_ASIMD UINT32_C(0x00000002) + #define CPUINFO_ARM_LINUX_FEATURE_EVTSTRM UINT32_C(0x00000004) + #define CPUINFO_ARM_LINUX_FEATURE_AES UINT32_C(0x00000008) + #define CPUINFO_ARM_LINUX_FEATURE_PMULL UINT32_C(0x00000010) + #define CPUINFO_ARM_LINUX_FEATURE_SHA1 UINT32_C(0x00000020) + #define CPUINFO_ARM_LINUX_FEATURE_SHA2 UINT32_C(0x00000040) + #define CPUINFO_ARM_LINUX_FEATURE_CRC32 UINT32_C(0x00000080) + #define CPUINFO_ARM_LINUX_FEATURE_ATOMICS UINT32_C(0x00000100) + #define CPUINFO_ARM_LINUX_FEATURE_FPHP UINT32_C(0x00000200) + #define CPUINFO_ARM_LINUX_FEATURE_ASIMDHP UINT32_C(0x00000400) + #define CPUINFO_ARM_LINUX_FEATURE_CPUID UINT32_C(0x00000800) + #define CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM UINT32_C(0x00001000) + #define CPUINFO_ARM_LINUX_FEATURE_JSCVT UINT32_C(0x00002000) + #define CPUINFO_ARM_LINUX_FEATURE_FCMA UINT32_C(0x00004000) + #define CPUINFO_ARM_LINUX_FEATURE_LRCPC UINT32_C(0x00008000) #endif - -#define PROC_CPUINFO_VALID_ARCHITECTURE UINT32_C(0x00000001) -#define PROC_CPUINFO_VALID_IMPLEMENTER UINT32_C(0x00000002) -#define PROC_CPUINFO_VALID_VARIANT UINT32_C(0x00000004) -#define PROC_CPUINFO_VALID_PART UINT32_C(0x00000008) -#define PROC_CPUINFO_VALID_REVISION UINT32_C(0x00000010) -#define PROC_CPUINFO_VALID_FEATURES UINT32_C(0x00000020) +#define CPUINFO_ARM_LINUX_VALID_ARCHITECTURE UINT32_C(0x00010000) +#define CPUINFO_ARM_LINUX_VALID_IMPLEMENTER UINT32_C(0x00020000) +#define CPUINFO_ARM_LINUX_VALID_VARIANT UINT32_C(0x00040000) +#define CPUINFO_ARM_LINUX_VALID_PART UINT32_C(0x00080000) +#define CPUINFO_ARM_LINUX_VALID_REVISION UINT32_C(0x00100000) +#define CPUINFO_ARM_LINUX_VALID_PROCESSOR UINT32_C(0x00200000) +#define CPUINFO_ARM_LINUX_VALID_FEATURES UINT32_C(0x00400000) #if CPUINFO_ARCH_ARM - #define PROC_CPUINFO_VALID_ICACHE_SIZE UINT32_C(0x00000100) - #define PROC_CPUINFO_VALID_ICACHE_SETS UINT32_C(0x00000200) - #define PROC_CPUINFO_VALID_ICACHE_WAYS UINT32_C(0x00000400) - #define PROC_CPUINFO_VALID_ICACHE_LINE UINT32_C(0x00000800) - #define PROC_CPUINFO_VALID_DCACHE_SIZE UINT32_C(0x00001000) - #define PROC_CPUINFO_VALID_DCACHE_SETS UINT32_C(0x00002000) - #define PROC_CPUINFO_VALID_DCACHE_WAYS UINT32_C(0x00004000) - #define PROC_CPUINFO_VALID_DCACHE_LINE UINT32_C(0x00008000) + #define CPUINFO_ARM_LINUX_VALID_ICACHE_SIZE UINT32_C(0x01000000) + #define CPUINFO_ARM_LINUX_VALID_ICACHE_SETS UINT32_C(0x02000000) + #define CPUINFO_ARM_LINUX_VALID_ICACHE_WAYS UINT32_C(0x04000000) + #define CPUINFO_ARM_LINUX_VALID_ICACHE_LINE UINT32_C(0x08000000) + #define CPUINFO_ARM_LINUX_VALID_DCACHE_SIZE UINT32_C(0x10000000) + #define CPUINFO_ARM_LINUX_VALID_DCACHE_SETS UINT32_C(0x20000000) + #define CPUINFO_ARM_LINUX_VALID_DCACHE_WAYS UINT32_C(0x40000000) + #define CPUINFO_ARM_LINUX_VALID_DCACHE_LINE UINT32_C(0x80000000) #endif -#define PROC_CPUINFO_VALID_INFO UINT32_C(0x0000003F) +#define CPUINFO_ARM_LINUX_VALID_INFO UINT32_C(0x007F0000) +#define CPUINFO_ARM_LINUX_VALID_MIDR UINT32_C(0x003F0000) #if CPUINFO_ARCH_ARM - #define PROC_CPUINFO_VALID_ICACHE UINT32_C(0x00000F00) - #define PROC_CPUINFO_VALID_DCACHE UINT32_C(0x0000F000) - #define PROC_CPUINFO_VALID_CACHE_LINE UINT32_C(0x00008800) + #define CPUINFO_ARM_LINUX_VALID_ICACHE UINT32_C(0x0F000000) + #define CPUINFO_ARM_LINUX_VALID_DCACHE UINT32_C(0xF0000000) + #define CPUINFO_ARM_LINUX_VALID_CACHE_LINE UINT32_C(0x88000000) #endif -struct proc_cpuinfo { - struct proc_cpuinfo_arch architecture; +struct cpuinfo_arm_linux_processor { + uint32_t architecture_version; #if CPUINFO_ARCH_ARM - struct proc_cpuinfo_cache cache; + uint32_t architecture_flags; + struct cpuinfo_arm_linux_proc_cpuinfo_cache proc_cpuinfo_cache; #endif uint32_t features; #if CPUINFO_ARCH_ARM uint32_t features2; #endif - uint32_t cpuid; - uint32_t implementer; - uint32_t variant; - uint32_t part; - uint32_t revision; - uint32_t valid_mask; + /** + * Main ID Register value. + */ + uint32_t midr; + enum cpuinfo_vendor vendor; + enum cpuinfo_uarch uarch; + /** + * ID of the core which includes this logical processor. + * The value is parsed from /sys/devices/system/cpu/cpu/topology/core_id + */ + uint32_t core_id; + /** + * Maximum processor ID on the core which includes this logical processor. + * This value can serve as an ID for the cluster of logical processors: it is the + * same for all logical processors on the same core. + */ + uint32_t core_group_max; + /** + * Minimum processor ID on the core which includes this logical processor. + * This value can serve as an ID for the cluster of logical processors: it is the + * same for all logical processors on the same core. + */ + uint32_t core_group_min; + /** + * ID of the physical package which includes this logical processor. + * The value is parsed from /sys/devices/system/cpu/cpu/topology/physical_package_id + */ + uint32_t package_id; + /** + * Maximum processor ID on the package which includes this logical processor. + * This value can serve as an ID for the cluster of logical processors: it is the + * same for all logical processors on the same package. + */ + uint32_t package_group_max; + /** + * Minimum processor ID on the package which includes this logical processor. + * This value can serve as an ID for the cluster of logical processors: it is the + * same for all logical processors on the same package. + */ + uint32_t package_group_min; + /** + * Number of logical processors in the package. + */ + uint32_t package_processor_count; + /** + * Maximum frequency, in kHZ. + * The value is parsed from /sys/devices/system/cpu/cpu/cpufreq/cpuinfo_max_freq + * If failed to read or parse the file, the value is 0. + */ + uint32_t max_frequency; + /** + * Minimum frequency, in kHZ. + * The value is parsed from /sys/devices/system/cpu/cpu/cpufreq/cpuinfo_min_freq + * If failed to read or parse the file, the value is 0. + */ + uint32_t min_frequency; + /** + * Normalized processor number. + */ + uint32_t processor_id; + /** + * Linux processor ID + */ + uint32_t system_processor_id; + uint32_t flags; }; -struct proc_cpuinfo* cpuinfo_arm_linux_parse_proc_cpuinfo( - uint32_t processors_count[restrict static 1]); +struct cpuinfo_arm_linux_cluster { + uint32_t processor_id_min; + uint32_t processor_id_max; +}; + +/* Returns true if the two processors do belong to the same cluster */ +static bool cpuinfo_arm_linux_processor_equals( + struct cpuinfo_arm_linux_processor processor_i[restrict static 1], + struct cpuinfo_arm_linux_processor processor_j[restrict static 1]) +{ + const uint32_t joint_flags = processor_i->flags & processor_j->flags; + + bool same_max_frequency = false; + if (joint_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { + if (processor_i->max_frequency != processor_j->max_frequency) { + return false; + } else { + same_max_frequency = true; + } + } + + bool same_min_frequency = false; + if (joint_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { + if (processor_j->min_frequency != processor_j->min_frequency) { + return false; + } else { + same_min_frequency = true; + } + } + + if ((joint_flags & CPUINFO_ARM_LINUX_VALID_MIDR) == CPUINFO_ARM_LINUX_VALID_MIDR) { + if (processor_i->midr == processor_j->midr) { + if (midr_is_cortex_a53(processor_i->midr)) { + return same_min_frequency & same_max_frequency; + } else { + return true; + } + } + } + + return same_max_frequency && same_min_frequency; +} + +/* Returns true if the two processors certainly don't belong to the same cluster */ +static bool cpuinfo_arm_linux_processor_not_equals( + struct cpuinfo_arm_linux_processor processor_i[restrict static 1], + struct cpuinfo_arm_linux_processor processor_j[restrict static 1]) +{ + const uint32_t joint_flags = processor_i->flags & processor_j->flags; + + if (joint_flags & CPUINFO_LINUX_FLAG_MAX_FREQUENCY) { + if (processor_i->max_frequency != processor_j->max_frequency) { + return true; + } + } + + if (joint_flags & CPUINFO_LINUX_FLAG_MIN_FREQUENCY) { + if (processor_j->min_frequency != processor_j->min_frequency) { + return true; + } + } + + if ((joint_flags & CPUINFO_ARM_LINUX_VALID_MIDR) == CPUINFO_ARM_LINUX_VALID_MIDR) { + if (processor_i->midr != processor_j->midr) { + return true; + } + } + + return false; +} + +bool cpuinfo_arm_linux_parse_proc_cpuinfo(uint32_t max_processors_count, + struct cpuinfo_arm_linux_processor processors[restrict static max_processors_count]); #if CPUINFO_ARCH_ARM void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo( - const struct proc_cpuinfo proc_cpuinfo[restrict static 1], - uint32_t proc_cpuinfo_count, + const struct cpuinfo_arm_linux_processor processors[restrict static 1], struct cpuinfo_arm_isa isa[restrict static 1]); #elif CPUINFO_ARCH_ARM64 void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo( - const struct proc_cpuinfo proc_cpuinfo[restrict static 1], + const struct cpuinfo_arm_linux_processor processors[restrict static 1], struct cpuinfo_arm_isa isa[restrict static 1]); #endif -- cgit v1.2.3