3rdparty: Sync cpuinfo to commit 8df44962d437a0477f07ba6b8843d0b6a48646a4

This commit is contained in:
JordanTheToaster 2024-11-03 03:28:02 +00:00 committed by lightningterror
parent 0bc043a0bb
commit 4ad5dde780
12 changed files with 303 additions and 40 deletions

View File

@ -60,7 +60,7 @@ ssize_t CPUINFO_ABI cpuinfo_mock_read(int fd, void* buffer, size_t capacity);
void CPUINFO_ABI cpuinfo_set_hwcap(uint32_t hwcap); void CPUINFO_ABI cpuinfo_set_hwcap(uint32_t hwcap);
#endif #endif
#if CPUINFO_ARCH_ARM #if CPUINFO_ARCH_ARM
void CPUINFO_ABI cpuinfo_set_hwcap2(uint32_t hwcap2); void CPUINFO_ABI cpuinfo_set_hwcap2(uint64_t hwcap2);
#endif #endif
#endif #endif

View File

@ -496,13 +496,19 @@ enum cpuinfo_uarch {
cpuinfo_uarch_cortex_x2 = 0x00300502, cpuinfo_uarch_cortex_x2 = 0x00300502,
/** ARM Cortex-X3. */ /** ARM Cortex-X3. */
cpuinfo_uarch_cortex_x3 = 0x00300503, cpuinfo_uarch_cortex_x3 = 0x00300503,
/** ARM Cortex-X4. */
cpuinfo_uarch_cortex_x4 = 0x00300504,
/** ARM Cortex-A510. */ /** ARM Cortex-A510. */
cpuinfo_uarch_cortex_a510 = 0x00300551, cpuinfo_uarch_cortex_a510 = 0x00300551,
/** ARM Cortex-A520. */
cpuinfo_uarch_cortex_a520 = 0x00300552,
/** ARM Cortex-A710. */ /** ARM Cortex-A710. */
cpuinfo_uarch_cortex_a710 = 0x00300571, cpuinfo_uarch_cortex_a710 = 0x00300571,
/** ARM Cortex-A715. */ /** ARM Cortex-A715. */
cpuinfo_uarch_cortex_a715 = 0x00300572, cpuinfo_uarch_cortex_a715 = 0x00300572,
/** ARM Cortex-A720. */
cpuinfo_uarch_cortex_a720 = 0x00300573,
/** Qualcomm Scorpion. */ /** Qualcomm Scorpion. */
cpuinfo_uarch_scorpion = 0x00400100, cpuinfo_uarch_scorpion = 0x00400100,
@ -1664,6 +1670,14 @@ struct cpuinfo_arm_isa {
bool sve; bool sve;
bool sve2; bool sve2;
bool i8mm; bool i8mm;
bool sme;
bool sme2;
bool sme2p1;
bool sme_i16i32;
bool sme_bi32i32;
bool sme_b16b16;
bool sme_f16f16;
uint32_t svelen;
#endif #endif
bool rdm; bool rdm;
bool fp16arith; bool fp16arith;
@ -2036,6 +2050,71 @@ static inline bool cpuinfo_has_arm_sve2(void) {
#endif #endif
} }
// Function to get the max SVE vector length on ARM CPU's which support SVE.
static inline uint32_t cpuinfo_get_max_arm_sve_length(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.svelen * 8; // bytes * 8 = bit length(vector length)
#else
return 0;
#endif
}
static inline bool cpuinfo_has_arm_sme(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme2(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme2;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme2p1(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme2p1;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_i16i32(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_i16i32;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_bi32i32(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_bi32i32;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_b16b16(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_b16b16;
#else
return false;
#endif
}
static inline bool cpuinfo_has_arm_sme_f16f16(void) {
#if CPUINFO_ARCH_ARM64
return cpuinfo_isa.sme_f16f16;
#else
return false;
#endif
}
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 #if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
/* This structure is not a part of stable API. Use cpuinfo_has_riscv_* functions /* This structure is not a part of stable API. Use cpuinfo_has_riscv_* functions
* instead. */ * instead. */

View File

@ -64,6 +64,7 @@ enum cpuinfo_arm_chipset_series {
cpuinfo_arm_chipset_series_telechips_tcc, cpuinfo_arm_chipset_series_telechips_tcc,
cpuinfo_arm_chipset_series_texas_instruments_omap, cpuinfo_arm_chipset_series_texas_instruments_omap,
cpuinfo_arm_chipset_series_unisoc_t, cpuinfo_arm_chipset_series_unisoc_t,
cpuinfo_arm_chipset_series_unisoc_ums,
cpuinfo_arm_chipset_series_wondermedia_wm, cpuinfo_arm_chipset_series_wondermedia_wm,
cpuinfo_arm_chipset_series_max, cpuinfo_arm_chipset_series_max,
}; };

View File

@ -24,7 +24,7 @@ void cpuinfo_set_wcid(uint32_t wcid) {
void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo( void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
uint32_t features, uint32_t features,
uint32_t features2, uint64_t features2,
uint32_t midr, uint32_t midr,
uint32_t architecture_version, uint32_t architecture_version,
uint32_t architecture_flags, uint32_t architecture_flags,
@ -147,6 +147,8 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
"VDOT instructions disabled: cause occasional SIGILL on Spreadtrum SC9863A"); "VDOT instructions disabled: cause occasional SIGILL on Spreadtrum SC9863A");
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_t && chipset->model == 310) { } else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_t && chipset->model == 310) {
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc T310"); cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc T310");
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_ums && chipset->model == 312) {
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc UMS312");
} else { } else {
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) { switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
case UINT32_C(0x4100D0B0): /* Cortex-A76 */ case UINT32_C(0x4100D0B0): /* Cortex-A76 */

View File

@ -3,9 +3,11 @@
#include <arm/linux/api.h> #include <arm/linux/api.h>
#include <cpuinfo/log.h> #include <cpuinfo/log.h>
#include <sys/prctl.h>
void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo( void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
uint32_t features, uint32_t features,
uint32_t features2, uint64_t features2,
uint32_t midr, uint32_t midr,
const struct cpuinfo_arm_chipset chipset[restrict static 1], const struct cpuinfo_arm_chipset chipset[restrict static 1],
struct cpuinfo_arm_isa isa[restrict static 1]) { struct cpuinfo_arm_isa isa[restrict static 1]) {
@ -142,6 +144,27 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) { if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) {
isa->sve2 = true; isa->sve2 = true;
} }
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME) {
isa->sme = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2) {
isa->sme2 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2P1) {
isa->sme2p1 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32) {
isa->sme_i16i32 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32) {
isa->sme_bi32i32 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16) {
isa->sme_b16b16 = true;
}
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16) {
isa->sme_f16f16 = true;
}
// SVEBF16 is set iff SVE and BF16 are both supported, but the SVEBF16 // SVEBF16 is set iff SVE and BF16 are both supported, but the SVEBF16
// feature flag was added in Linux kernel before the BF16 feature flag, // feature flag was added in Linux kernel before the BF16 feature flag,
// so we check for either. // so we check for either.
@ -151,4 +174,21 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDFHM) { if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDFHM) {
isa->fhm = true; isa->fhm = true;
} }
#ifndef PR_SVE_GET_VL
#define PR_SVE_GET_VL 51
#endif
#ifndef PR_SVE_VL_LEN_MASK
#define PR_SVE_VL_LEN_MASK 0xffff
#endif
int ret = prctl(PR_SVE_GET_VL);
if (ret < 0) {
cpuinfo_log_warning("No SVE support on this machine");
isa->svelen = 0; // Assume no SVE support if the call fails
} else {
// Mask out the SVE vector length bits
isa->svelen = ret & PR_SVE_VL_LEN_MASK;
}
} }

View File

@ -137,6 +137,13 @@ struct cpuinfo_arm_linux_proc_cpuinfo_cache {
#define CPUINFO_ARM_LINUX_FEATURE2_DGH UINT32_C(0x00008000) #define CPUINFO_ARM_LINUX_FEATURE2_DGH UINT32_C(0x00008000)
#define CPUINFO_ARM_LINUX_FEATURE2_RNG UINT32_C(0x00010000) #define CPUINFO_ARM_LINUX_FEATURE2_RNG UINT32_C(0x00010000)
#define CPUINFO_ARM_LINUX_FEATURE2_BTI UINT32_C(0x00020000) #define CPUINFO_ARM_LINUX_FEATURE2_BTI UINT32_C(0x00020000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME UINT32_C(0x00800000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME2 UINT64_C(0x0000002000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME2P1 UINT64_C(0x0000004000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32 UINT64_C(0x0000008000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32 UINT64_C(0x0000010000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16 UINT64_C(0x0000020000000000)
#define CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16 UINT64_C(0x0000040000000000)
#endif #endif
#define CPUINFO_ARM_LINUX_VALID_ARCHITECTURE UINT32_C(0x00010000) #define CPUINFO_ARM_LINUX_VALID_ARCHITECTURE UINT32_C(0x00010000)
@ -172,7 +179,7 @@ struct cpuinfo_arm_linux_processor {
struct cpuinfo_arm_linux_proc_cpuinfo_cache proc_cpuinfo_cache; struct cpuinfo_arm_linux_proc_cpuinfo_cache proc_cpuinfo_cache;
#endif #endif
uint32_t features; uint32_t features;
uint32_t features2; uint64_t features2;
/** /**
* Main ID Register value. * Main ID Register value.
*/ */
@ -295,14 +302,14 @@ CPUINFO_INTERNAL bool cpuinfo_arm_linux_parse_proc_cpuinfo(
#if CPUINFO_ARCH_ARM #if CPUINFO_ARCH_ARM
CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_getauxval( CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1], uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]); uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_procfs( CPUINFO_INTERNAL bool cpuinfo_arm_linux_hwcap_from_procfs(
uint32_t hwcap[restrict static 1], uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]); uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo( CPUINFO_INTERNAL void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
uint32_t features, uint32_t features,
uint32_t features2, uint64_t features2,
uint32_t midr, uint32_t midr,
uint32_t architecture_version, uint32_t architecture_version,
uint32_t architecture_flags, uint32_t architecture_flags,
@ -311,11 +318,11 @@ CPUINFO_INTERNAL void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
#elif CPUINFO_ARCH_ARM64 #elif CPUINFO_ARCH_ARM64
CPUINFO_INTERNAL void cpuinfo_arm_linux_hwcap_from_getauxval( CPUINFO_INTERNAL void cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1], uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1]); uint64_t hwcap2[restrict static 1]);
CPUINFO_INTERNAL void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo( CPUINFO_INTERNAL void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
uint32_t features, uint32_t features,
uint32_t features2, uint64_t features2,
uint32_t midr, uint32_t midr,
const struct cpuinfo_arm_chipset chipset[restrict static 1], const struct cpuinfo_arm_chipset chipset[restrict static 1],
struct cpuinfo_arm_isa isa[restrict static 1]); struct cpuinfo_arm_isa isa[restrict static 1]);

View File

@ -85,6 +85,7 @@ static enum cpuinfo_arm_chipset_vendor chipset_series_vendor[cpuinfo_arm_chipset
[cpuinfo_arm_chipset_series_telechips_tcc] = cpuinfo_arm_chipset_vendor_telechips, [cpuinfo_arm_chipset_series_telechips_tcc] = cpuinfo_arm_chipset_vendor_telechips,
[cpuinfo_arm_chipset_series_texas_instruments_omap] = cpuinfo_arm_chipset_vendor_texas_instruments, [cpuinfo_arm_chipset_series_texas_instruments_omap] = cpuinfo_arm_chipset_vendor_texas_instruments,
[cpuinfo_arm_chipset_series_unisoc_t] = cpuinfo_arm_chipset_vendor_unisoc, [cpuinfo_arm_chipset_series_unisoc_t] = cpuinfo_arm_chipset_vendor_unisoc,
[cpuinfo_arm_chipset_series_unisoc_ums] = cpuinfo_arm_chipset_vendor_unisoc,
[cpuinfo_arm_chipset_series_wondermedia_wm] = cpuinfo_arm_chipset_vendor_wondermedia, [cpuinfo_arm_chipset_series_wondermedia_wm] = cpuinfo_arm_chipset_vendor_wondermedia,
}; };
@ -959,6 +960,70 @@ static bool match_t(const char* start, const char* end, struct cpuinfo_arm_chips
return true; return true;
} }
/**
* Tries to match, case-sentitively, /Unisoc UMS\d{3,4}/ signature for Unisoc UMS
* chipset. If match successful, extracts model information into \p chipset
* argument.
*
* @param start - start of the platform identifier (/proc/cpuinfo Hardware
* string, ro.product.board, ro.board.platform, or ro.chipname) to match.
* @param end - end of the platform identifier (/proc/cpuinfo Hardware string,
* ro.product.board, ro.board.platform, or ro.chipname) to match.
* @param[out] chipset - location where chipset information will be stored upon
* a successful match.
*
* @returns true if signature matched, false otherwise.
*/
static bool match_ums(const char* start, const char* end, struct cpuinfo_arm_chipset chipset[restrict static 1]) {
/* Expect 13-14 symbols: "Unisoc UMS" (10 symbols) + 3-4-digit model number
*/
const size_t length = end - start;
switch (length) {
case 13:
case 14:
break;
default:
return false;
}
/* Check that string starts with "Unisoc UMS". The first four characters
* are loaded as 32-bit little endian word */
const uint32_t expected_unis = load_u32le(start);
if (expected_unis != UINT32_C(0x73696E55) /* "sinU" = reverse("Unis") */) {
return false;
}
/* The next four characters are loaded as 32-bit little endian word */
const uint32_t expected_oc_u = load_u32le(start + 4);
if (expected_oc_u != UINT32_C(0x5520636F) /* "U co" = reverse("oc U") */) {
return false;
}
/* The next four characters are loaded as 16-bit little endian word */
const uint16_t expected_ms = load_u16le(start + 8);
if (expected_ms != UINT16_C(0x534D) /* "SM" = reverse("MS") */) {
return false;
}
/* Validate and parse 3-4 digit model number */
uint32_t model = 0;
for (uint32_t i = 10; i < length; i++) {
const uint32_t digit = (uint32_t)(uint8_t)start[i] - '0';
if (digit >= 10) {
/* Not really a digit */
return false;
}
model = model * 10 + digit;
}
*chipset = (struct cpuinfo_arm_chipset){
.vendor = cpuinfo_arm_chipset_vendor_unisoc,
.series = cpuinfo_arm_chipset_series_unisoc_ums,
.model = model,
};
return true;
}
/** /**
* Tries to match /lc\d{4}[a-z]?$/ signature for Leadcore LC chipsets. * Tries to match /lc\d{4}[a-z]?$/ signature for Leadcore LC chipsets.
* If match successful, extracts model information into \p chipset argument. * If match successful, extracts model information into \p chipset argument.
@ -2508,6 +2573,16 @@ struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_ha
return chipset; return chipset;
} }
/* Check Unisoc UMS signature */
if (match_ums(hardware, hardware_end, &chipset)) {
cpuinfo_log_debug(
"matched Unisoc UMS signature in /proc/cpuinfo Hardware string \"%.*s\"",
(int)hardware_length,
hardware);
return chipset;
}
#if CPUINFO_ARCH_ARM #if CPUINFO_ARCH_ARM
/* Check Marvell PXA signature */ /* Check Marvell PXA signature */
if (match_pxa(hardware, hardware_end, &chipset)) { if (match_pxa(hardware, hardware_end, &chipset)) {
@ -3726,6 +3801,7 @@ static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
[cpuinfo_arm_chipset_series_telechips_tcc] = "TCC", [cpuinfo_arm_chipset_series_telechips_tcc] = "TCC",
[cpuinfo_arm_chipset_series_texas_instruments_omap] = "OMAP", [cpuinfo_arm_chipset_series_texas_instruments_omap] = "OMAP",
[cpuinfo_arm_chipset_series_unisoc_t] = "T", [cpuinfo_arm_chipset_series_unisoc_t] = "T",
[cpuinfo_arm_chipset_series_unisoc_ums] = "UMS",
[cpuinfo_arm_chipset_series_wondermedia_wm] = "WM", [cpuinfo_arm_chipset_series_wondermedia_wm] = "WM",
}; };

View File

@ -31,8 +31,8 @@ void cpuinfo_set_hwcap(uint32_t hwcap) {
mock_hwcap = hwcap; mock_hwcap = hwcap;
} }
static uint32_t mock_hwcap2 = 0; static uint64_t mock_hwcap2 = 0;
void cpuinfo_set_hwcap2(uint32_t hwcap2) { void cpuinfo_set_hwcap2(uint64_t hwcap2) {
mock_hwcap2 = hwcap2; mock_hwcap2 = hwcap2;
} }
#endif #endif
@ -40,7 +40,7 @@ void cpuinfo_set_hwcap2(uint32_t hwcap2) {
#if CPUINFO_ARCH_ARM #if CPUINFO_ARCH_ARM
typedef unsigned long (*getauxval_function_t)(unsigned long); typedef unsigned long (*getauxval_function_t)(unsigned long);
bool cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) { bool cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK #if CPUINFO_MOCK
*hwcap = mock_hwcap; *hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2; *hwcap2 = mock_hwcap2;
@ -83,13 +83,13 @@ cleanup:
} }
#ifdef __ANDROID__ #ifdef __ANDROID__
bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) { bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK #if CPUINFO_MOCK
*hwcap = mock_hwcap; *hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2; *hwcap2 = mock_hwcap2;
return true; return true;
#else #else
uint32_t hwcaps[2] = {0, 0}; uint64_t hwcaps[2] = {0, 0};
bool result = false; bool result = false;
int file = -1; int file = -1;
@ -113,7 +113,7 @@ bool cpuinfo_arm_linux_hwcap_from_procfs(uint32_t hwcap[restrict static 1], uint
hwcaps[0] = (uint32_t)elf_auxv.a_un.a_val; hwcaps[0] = (uint32_t)elf_auxv.a_un.a_val;
break; break;
case AT_HWCAP2: case AT_HWCAP2:
hwcaps[1] = (uint32_t)elf_auxv.a_un.a_val; hwcaps[1] = (uint64_t)elf_auxv.a_un.a_val;
break; break;
} }
} else { } else {
@ -141,13 +141,13 @@ cleanup:
} }
#endif /* __ANDROID__ */ #endif /* __ANDROID__ */
#elif CPUINFO_ARCH_ARM64 #elif CPUINFO_ARCH_ARM64
void cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint32_t hwcap2[restrict static 1]) { void cpuinfo_arm_linux_hwcap_from_getauxval(uint32_t hwcap[restrict static 1], uint64_t hwcap2[restrict static 1]) {
#if CPUINFO_MOCK #if CPUINFO_MOCK
*hwcap = mock_hwcap; *hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2; *hwcap2 = mock_hwcap2;
#else #else
*hwcap = (uint32_t)getauxval(AT_HWCAP); *hwcap = (uint32_t)getauxval(AT_HWCAP);
*hwcap2 = (uint32_t)getauxval(AT_HWCAP2); *hwcap2 = (uint64_t)getauxval(AT_HWCAP2);
return; return;
#endif #endif
} }

View File

@ -247,7 +247,8 @@ void cpuinfo_arm_linux_init(void) {
#endif #endif
#if CPUINFO_ARCH_ARM #if CPUINFO_ARCH_ARM
uint32_t isa_features = 0, isa_features2 = 0; uint32_t isa_features = 0;
uint64_t isa_features2 = 0;
#ifdef __ANDROID__ #ifdef __ANDROID__
/* /*
* On Android before API 20, libc.so does not provide getauxval * On Android before API 20, libc.so does not provide getauxval
@ -299,7 +300,8 @@ void cpuinfo_arm_linux_init(void) {
&chipset, &chipset,
&cpuinfo_isa); &cpuinfo_isa);
#elif CPUINFO_ARCH_ARM64 #elif CPUINFO_ARCH_ARM64
uint32_t isa_features = 0, isa_features2 = 0; uint32_t isa_features = 0;
uint64_t isa_features2 = 0;
/* getauxval is always available on ARM64 Android */ /* getauxval is always available on ARM64 Android */
cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2); cpuinfo_arm_linux_hwcap_from_getauxval(&isa_features, &isa_features2);
cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo( cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
@ -333,18 +335,52 @@ void cpuinfo_arm_linux_init(void) {
} }
/* Propagate topology group IDs among siblings */ /* Propagate topology group IDs among siblings */
bool detected_core_siblings_list_node = false;
bool detected_cluster_cpus_list_node = false;
for (uint32_t i = 0; i < arm_linux_processors_count; i++) { for (uint32_t i = 0; i < arm_linux_processors_count; i++) {
if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) { if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_VALID)) {
continue; continue;
} }
if (arm_linux_processors[i].flags & CPUINFO_LINUX_FLAG_PACKAGE_ID) { if (!bitmask_all(arm_linux_processors[i].flags, CPUINFO_LINUX_FLAG_PACKAGE_ID)) {
continue;
}
/* Use the cluster_cpus_list topology node if available. If not
* found, cache the result to avoid repeatedly attempting to
* read the non-existent paths.
* */
if (!detected_core_siblings_list_node && !detected_cluster_cpus_list_node) {
if (cpuinfo_linux_detect_cluster_cpus(
arm_linux_processors_count,
i,
(cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors)) {
detected_cluster_cpus_list_node = true;
continue;
} else {
detected_core_siblings_list_node = true;
}
}
/* The cached result above will guarantee only one of the blocks
* below will execute, with a bias towards cluster_cpus_list.
**/
if (detected_core_siblings_list_node) {
cpuinfo_linux_detect_core_siblings( cpuinfo_linux_detect_core_siblings(
arm_linux_processors_count, arm_linux_processors_count,
i, i,
(cpuinfo_siblings_callback)cluster_siblings_parser, (cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors); arm_linux_processors);
} }
if (detected_cluster_cpus_list_node) {
cpuinfo_linux_detect_cluster_cpus(
arm_linux_processors_count,
i,
(cpuinfo_siblings_callback)cluster_siblings_parser,
arm_linux_processors);
}
} }
/* Propagate all cluster IDs */ /* Propagate all cluster IDs */

View File

@ -399,6 +399,16 @@ void cpuinfo_arm_mach_init(void) {
cpuinfo_isa.i8mm = true; cpuinfo_isa.i8mm = true;
} }
const uint32_t has_feat_sme = get_sys_info_by_name("hw.optional.arm.FEAT_SME");
if (has_feat_sme != 0) {
cpuinfo_isa.sme = true;
}
const uint32_t has_feat_sme2 = get_sys_info_by_name("hw.optional.arm.FEAT_SME2");
if (has_feat_sme2 != 0) {
cpuinfo_isa.sme2 = true;
}
uint32_t num_clusters = 1; uint32_t num_clusters = 1;
for (uint32_t i = 0; i < mach_topology.cores; i++) { for (uint32_t i = 0; i < mach_topology.cores; i++) {
cores[i] = (struct cpuinfo_core){ cores[i] = (struct cpuinfo_core){

View File

@ -24,8 +24,10 @@ static char* sysctl_str(const char* name) {
size_t value_size = 0; size_t value_size = 0;
if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) { if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno)); cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
return NULL;
} else if (value_size <= 0) { } else if (value_size <= 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size); cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
return NULL;
} }
value_size += 1; value_size += 1;
char* value = calloc(value_size, 1); char* value = calloc(value_size, 1);
@ -52,29 +54,22 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
if (!topology_spec) { if (!topology_spec) {
return topology; return topology;
} }
const char* group_tag = "<group level=\"1\" cache-level=\"0\">"; const char* group_tags[] = {"<group level=\"2\" cache-level=\"0\">", "<group level=\"1\" "};
char* p = strstr(topology_spec, group_tag); for (size_t i = 0; i < sizeof(group_tags) / sizeof(group_tags[0]); i++) {
while (p) { const char* group_tag = group_tags[i];
const char* cpu_tag = "cpu count=\"";
char* q = strstr(p, cpu_tag);
if (q) {
p = q + strlen(cpu_tag);
topology.packages += atoi(p);
} else {
break;
}
}
if (topology.packages == 0) {
const char* group_tag = "<group level=\"1\"";
char* p = strstr(topology_spec, group_tag); char* p = strstr(topology_spec, group_tag);
while (p) { while (p) {
topology.packages += 1; topology.packages += 1;
p++; p++;
p = strstr(p, group_tag); p = strstr(p, group_tag);
} }
if (topology.packages > 0) {
break;
}
} }
if (topology.packages == 0) { if (topology.packages == 0) {
cpuinfo_log_error("failed to parse topology_spec:%s", topology_spec); cpuinfo_log_error("failed to parse topology_spec: %s", topology_spec);
free(topology_spec); free(topology_spec);
goto fail; goto fail;
} }
@ -84,6 +79,7 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
goto fail; goto fail;
} }
if (topology.cores < topology.packages) { if (topology.cores < topology.packages) {
cpuinfo_log_error("invalid numbers of package and core: %d %d", topology.packages, topology.cores);
goto fail; goto fail;
} }
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core"); topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");

View File

@ -135,6 +135,10 @@ void cpuinfo_x86_freebsd_init(void) {
if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) { if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) {
/* Assume that threads on the same core share L1 */ /* Assume that threads on the same core share L1 */
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores; threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
if (threads_per_l1 == 0) {
cpuinfo_log_error("failed to detect threads_per_l1");
goto cleanup;
}
cpuinfo_log_warning( cpuinfo_log_warning(
"freebsd kernel did not report number of " "freebsd kernel did not report number of "
"threads sharing L1 cache; assume %" PRIu32, "threads sharing L1 cache; assume %" PRIu32,
@ -154,6 +158,10 @@ void cpuinfo_x86_freebsd_init(void) {
* the same package share L2 */ * the same package share L2 */
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages; threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
} }
if (threads_per_l2 == 0) {
cpuinfo_log_error("failed to detect threads_per_l1");
goto cleanup;
}
cpuinfo_log_warning( cpuinfo_log_warning(
"freebsd kernel did not report number of " "freebsd kernel did not report number of "
"threads sharing L2 cache; assume %" PRIu32, "threads sharing L2 cache; assume %" PRIu32,
@ -170,6 +178,10 @@ void cpuinfo_x86_freebsd_init(void) {
* may be L4 cache as well) * may be L4 cache as well)
*/ */
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages; threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
if (threads_per_l3 == 0) {
cpuinfo_log_error("failed to detect threads_per_l3");
goto cleanup;
}
cpuinfo_log_warning( cpuinfo_log_warning(
"freebsd kernel did not report number of " "freebsd kernel did not report number of "
"threads sharing L3 cache; assume %" PRIu32, "threads sharing L3 cache; assume %" PRIu32,
@ -187,6 +199,10 @@ void cpuinfo_x86_freebsd_init(void) {
* shared L4 (like on IBM POWER8). * shared L4 (like on IBM POWER8).
*/ */
threads_per_l4 = freebsd_topology.threads; threads_per_l4 = freebsd_topology.threads;
if (threads_per_l4 == 0) {
cpuinfo_log_error("failed to detect threads_per_l4");
goto cleanup;
}
cpuinfo_log_warning( cpuinfo_log_warning(
"freebsd kernel did not report number of " "freebsd kernel did not report number of "
"threads sharing L4 cache; assume %" PRIu32, "threads sharing L4 cache; assume %" PRIu32,
@ -203,7 +219,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L1I caches", "%" PRIu32 " L1I caches",
l1_count * sizeof(struct cpuinfo_cache), l1_count * sizeof(struct cpuinfo_cache),
l1_count); l1_count);
return; goto cleanup;
} }
for (uint32_t c = 0; c < l1_count; c++) { for (uint32_t c = 0; c < l1_count; c++) {
l1i[c] = (struct cpuinfo_cache){ l1i[c] = (struct cpuinfo_cache){
@ -230,7 +246,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L1D caches", "%" PRIu32 " L1D caches",
l1_count * sizeof(struct cpuinfo_cache), l1_count * sizeof(struct cpuinfo_cache),
l1_count); l1_count);
return; goto cleanup;
} }
for (uint32_t c = 0; c < l1_count; c++) { for (uint32_t c = 0; c < l1_count; c++) {
l1d[c] = (struct cpuinfo_cache){ l1d[c] = (struct cpuinfo_cache){
@ -257,7 +273,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L2 caches", "%" PRIu32 " L2 caches",
l2_count * sizeof(struct cpuinfo_cache), l2_count * sizeof(struct cpuinfo_cache),
l2_count); l2_count);
return; goto cleanup;
} }
for (uint32_t c = 0; c < l2_count; c++) { for (uint32_t c = 0; c < l2_count; c++) {
l2[c] = (struct cpuinfo_cache){ l2[c] = (struct cpuinfo_cache){
@ -284,7 +300,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L3 caches", "%" PRIu32 " L3 caches",
l3_count * sizeof(struct cpuinfo_cache), l3_count * sizeof(struct cpuinfo_cache),
l3_count); l3_count);
return; goto cleanup;
} }
for (uint32_t c = 0; c < l3_count; c++) { for (uint32_t c = 0; c < l3_count; c++) {
l3[c] = (struct cpuinfo_cache){ l3[c] = (struct cpuinfo_cache){
@ -311,7 +327,7 @@ void cpuinfo_x86_freebsd_init(void) {
"%" PRIu32 " L4 caches", "%" PRIu32 " L4 caches",
l4_count * sizeof(struct cpuinfo_cache), l4_count * sizeof(struct cpuinfo_cache),
l4_count); l4_count);
return; goto cleanup;
} }
for (uint32_t c = 0; c < l4_count; c++) { for (uint32_t c = 0; c < l4_count; c++) {
l4[c] = (struct cpuinfo_cache){ l4[c] = (struct cpuinfo_cache){