• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdint.h>
2 
3 #include <arm/linux/api.h>
4 #include <cpuinfo/log.h>
5 
6 #include <sys/prctl.h>
7 
cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(uint32_t features,uint64_t features2,uint32_t midr,const struct cpuinfo_arm_chipset chipset[restrict static1],struct cpuinfo_arm_isa isa[restrict static1])8 void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
9 	uint32_t features,
10 	uint64_t features2,
11 	uint32_t midr,
12 	const struct cpuinfo_arm_chipset chipset[restrict static 1],
13 	struct cpuinfo_arm_isa isa[restrict static 1]) {
14 	if (features & CPUINFO_ARM_LINUX_FEATURE_AES) {
15 		isa->aes = true;
16 	}
17 	if (features & CPUINFO_ARM_LINUX_FEATURE_PMULL) {
18 		isa->pmull = true;
19 	}
20 	if (features & CPUINFO_ARM_LINUX_FEATURE_SHA1) {
21 		isa->sha1 = true;
22 	}
23 	if (features & CPUINFO_ARM_LINUX_FEATURE_SHA2) {
24 		isa->sha2 = true;
25 	}
26 	if (features & CPUINFO_ARM_LINUX_FEATURE_CRC32) {
27 		isa->crc32 = true;
28 	}
29 	if (features & CPUINFO_ARM_LINUX_FEATURE_ATOMICS) {
30 		isa->atomics = true;
31 	}
32 
33 	/*
34 	 * Some phones ship with an old kernel configuration that doesn't report
35 	 * NEON FP16 compute extension and SQRDMLAH/SQRDMLSH/UQRDMLAH/UQRDMLSH
36 	 * instructions. Use a MIDR-based heuristic to whitelist processors
37 	 * known to support it:
38 	 * - Processors with Cortex-A55 cores
39 	 * - Processors with Cortex-A65 cores
40 	 * - Processors with Cortex-A75 cores
41 	 * - Processors with Cortex-A76 cores
42 	 * - Processors with Cortex-A77 cores
43 	 * - Processors with Exynos M4 cores
44 	 * - Processors with Exynos M5 cores
45 	 * - Neoverse N1 cores
46 	 * - Neoverse V1 cores
47 	 * - Neoverse N2 cores
48 	 * - Neoverse V2 cores
49 	 */
50 	if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
51 		/* Exynos 9810 reports that it supports FP16 compute, but in
52 		 * fact only little cores do */
53 		cpuinfo_log_warning(
54 			"FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
55 	} else {
56 		const uint32_t fp16arith_mask = CPUINFO_ARM_LINUX_FEATURE_FPHP | CPUINFO_ARM_LINUX_FEATURE_ASIMDHP;
57 		switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
58 			case UINT32_C(0x4100D050): /* Cortex-A55 */
59 			case UINT32_C(0x4100D060): /* Cortex-A65 */
60 			case UINT32_C(0x4100D0A0): /* Cortex-A75 */
61 			case UINT32_C(0x4100D0B0): /* Cortex-A76 */
62 			case UINT32_C(0x4100D0C0): /* Neoverse N1 */
63 			case UINT32_C(0x4100D0D0): /* Cortex-A77 */
64 			case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
65 			case UINT32_C(0x4100D400): /* Neoverse V1 */
66 			case UINT32_C(0x4100D490): /* Neoverse N2 */
67 			case UINT32_C(0x4100D4F0): /* Neoverse V2 */
68 			case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
69 			case UINT32_C(0x51008020): /* Kryo 385 Gold (Cortex-A75) */
70 			case UINT32_C(0x51008030): /* Kryo 385 Silver (Cortex-A55) */
71 			case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
72 			case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
73 			case UINT32_C(0x53000030): /* Exynos M4 */
74 			case UINT32_C(0x53000040): /* Exynos M5 */
75 				isa->fp16arith = true;
76 				isa->rdm = true;
77 				break;
78 			default:
79 				if ((features & fp16arith_mask) == fp16arith_mask) {
80 					isa->fp16arith = true;
81 				} else if (features & CPUINFO_ARM_LINUX_FEATURE_FPHP) {
82 					cpuinfo_log_warning(
83 						"FP16 arithmetics disabled: detected support only for scalar operations");
84 				} else if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDHP) {
85 					cpuinfo_log_warning(
86 						"FP16 arithmetics disabled: detected support only for SIMD operations");
87 				}
88 				if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM) {
89 					isa->rdm = true;
90 				}
91 				break;
92 		}
93 	}
94 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_I8MM) {
95 		isa->i8mm = true;
96 	}
97 
98 	/*
99 	 * Many phones ship with an old kernel configuration that doesn't report
100 	 * UDOT/SDOT instructions. Use a MIDR-based heuristic to whitelist
101 	 * processors known to support it.
102 	 */
103 	switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
104 		case UINT32_C(0x4100D060): /* Cortex-A65 */
105 		case UINT32_C(0x4100D0B0): /* Cortex-A76 */
106 		case UINT32_C(0x4100D0C0): /* Neoverse N1 */
107 		case UINT32_C(0x4100D0D0): /* Cortex-A77 */
108 		case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
109 		case UINT32_C(0x4100D400): /* Neoverse V1 */
110 		case UINT32_C(0x4100D490): /* Neoverse N2 */
111 		case UINT32_C(0x4100D4A0): /* Neoverse E1 */
112 		case UINT32_C(0x4100D4F0): /* Neoverse V2 */
113 		case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
114 		case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
115 		case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
116 		case UINT32_C(0x53000030): /* Exynos-M4 */
117 		case UINT32_C(0x53000040): /* Exynos-M5 */
118 			isa->dot = true;
119 			break;
120 		case UINT32_C(0x4100D050): /* Cortex A55: revision 1 or later only */
121 			isa->dot = !!(midr_get_variant(midr) >= 1);
122 			break;
123 		case UINT32_C(0x4100D0A0): /* Cortex A75: revision 2 or later only */
124 			isa->dot = !!(midr_get_variant(midr) >= 2);
125 			break;
126 		default:
127 			if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDDP) {
128 				isa->dot = true;
129 			}
130 			break;
131 	}
132 	if (features & CPUINFO_ARM_LINUX_FEATURE_JSCVT) {
133 		isa->jscvt = true;
134 	}
135 	if (features & CPUINFO_ARM_LINUX_FEATURE_JSCVT) {
136 		isa->jscvt = true;
137 	}
138 	if (features & CPUINFO_ARM_LINUX_FEATURE_FCMA) {
139 		isa->fcma = true;
140 	}
141 	if (features & CPUINFO_ARM_LINUX_FEATURE_SVE) {
142 		isa->sve = true;
143 	}
144 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) {
145 		isa->sve2 = true;
146 	}
147 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME) {
148 		isa->sme = true;
149 	}
150 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2) {
151 		isa->sme2 = true;
152 	}
153 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2P1) {
154 		isa->sme2p1 = true;
155 	}
156 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32) {
157 		isa->sme_i16i32 = true;
158 	}
159 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32) {
160 		isa->sme_bi32i32 = true;
161 	}
162 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16) {
163 		isa->sme_b16b16 = true;
164 	}
165 	if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16) {
166 		isa->sme_f16f16 = true;
167 	}
168 	// SVEBF16 is set iff SVE and BF16 are both supported, but the SVEBF16
169 	// feature flag was added in Linux kernel before the BF16 feature flag,
170 	// so we check for either.
171 	if (features2 & (CPUINFO_ARM_LINUX_FEATURE2_BF16 | CPUINFO_ARM_LINUX_FEATURE2_SVEBF16)) {
172 		isa->bf16 = true;
173 	}
174 	if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDFHM) {
175 		isa->fhm = true;
176 	}
177 
178 #ifndef PR_SVE_GET_VL
179 #define PR_SVE_GET_VL 51
180 #endif
181 
182 #ifndef PR_SVE_VL_LEN_MASK
183 #define PR_SVE_VL_LEN_MASK 0xffff
184 #endif
185 
186 	int ret = prctl(PR_SVE_GET_VL);
187 	if (ret < 0) {
188 		cpuinfo_log_warning("No SVE support on this machine");
189 		isa->svelen = 0; // Assume no SVE support if the call fails
190 	} else {
191 		// Mask out the SVE vector length bits
192 		isa->svelen = ret & PR_SVE_VL_LEN_MASK;
193 	}
194 }
195