xref: /xnu-8792.81.2/osfmk/arm/cpuid.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1 /*
2  * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 
32 #include <pexpert/pexpert.h>
33 #include <arm/cpuid.h>
34 #include <arm/cpuid_internal.h>
35 #include <arm/cpu_data_internal.h>
36 #include <arm64/proc_reg.h>
37 #include <vm/vm_page.h>
38 
39 #include <libkern/section_keywords.h>
40 
41 /* Temporary types to aid decoding,
42  * Everything in Little Endian */
43 
44 typedef struct {
45 	uint32_t
46 	    Ctype1:3, /* 2:0 */
47 	    Ctype2:3, /* 5:3 */
48 	    Ctype3:3, /* 8:6 */
49 	    Ctypes:15, /* 6:23 - Don't Care */
50 	    LoC:3, /* 26-24 - Level of Coherency */
51 	    LoU:3, /* 29:27 - Level of Unification */
52 	    RAZ:2; /* 31:30 - Read-As-Zero */
53 } arm_cache_clidr_t;
54 
55 typedef union {
56 	arm_cache_clidr_t bits;
57 	uint32_t          value;
58 } arm_cache_clidr_info_t;
59 
60 
61 typedef struct {
62 	uint32_t
63 	    LineSize:3, /* 2:0 - Number of words in cache line */
64 	    Assoc:10, /* 12:3 - Associativity of cache */
65 	    NumSets:15, /* 27:13 - Number of sets in cache */
66 	    c_type:4; /* 31:28 - Cache type */
67 } arm_cache_ccsidr_t;
68 
69 
70 typedef union {
71 	arm_cache_ccsidr_t bits;
72 	uint32_t           value;
73 } arm_cache_ccsidr_info_t;
74 
75 /* Statics */
76 
77 static SECURITY_READ_ONLY_LATE(arm_cpu_info_t) cpuid_cpu_info;
78 static SECURITY_READ_ONLY_LATE(cache_info_t *) cpuid_cache_info_boot_cpu;
79 static cache_info_t cpuid_cache_info[MAX_CPU_TYPES] = { 0 };
80 static _Atomic uint8_t cpuid_cache_info_bitmap = 0;
81 
82 /* Code */
83 
84 __private_extern__
85 void
do_cpuid(void)86 do_cpuid(void)
87 {
88 	cpuid_cpu_info.value = machine_read_midr();
89 #if (__ARM_ARCH__ == 8)
90 
91 #if defined(HAS_APPLE_PAC)
92 	cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8E;
93 #else /* defined(HAS_APPLE_PAC) */
94 	cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8;
95 #endif /* defined(HAS_APPLE_PAC) */
96 
97 #else /* (__ARM_ARCH__ != 8) */
98 #error Unsupported arch
99 #endif /* (__ARM_ARCH__ != 8) */
100 }
101 
102 arm_cpu_info_t *
cpuid_info(void)103 cpuid_info(void)
104 {
105 	return &cpuid_cpu_info;
106 }
107 
108 int
cpuid_get_cpufamily(void)109 cpuid_get_cpufamily(void)
110 {
111 	int cpufamily = 0;
112 
113 	switch (cpuid_info()->arm_info.arm_implementor) {
114 	case CPU_VID_ARM:
115 		switch (cpuid_info()->arm_info.arm_part) {
116 		case CPU_PART_CORTEXA9:
117 			cpufamily = CPUFAMILY_ARM_14;
118 			break;
119 		case CPU_PART_CORTEXA8:
120 			cpufamily = CPUFAMILY_ARM_13;
121 			break;
122 		case CPU_PART_CORTEXA7:
123 			cpufamily = CPUFAMILY_ARM_15;
124 			break;
125 		case CPU_PART_1136JFS:
126 		case CPU_PART_1176JZFS:
127 			cpufamily = CPUFAMILY_ARM_11;
128 			break;
129 		case CPU_PART_926EJS:
130 		case CPU_PART_920T:
131 			cpufamily = CPUFAMILY_ARM_9;
132 			break;
133 		default:
134 			cpufamily = CPUFAMILY_UNKNOWN;
135 			break;
136 		}
137 		break;
138 
139 	case CPU_VID_INTEL:
140 		cpufamily = CPUFAMILY_ARM_XSCALE;
141 		break;
142 
143 	case CPU_VID_APPLE:
144 		switch (cpuid_info()->arm_info.arm_part) {
145 		case CPU_PART_TYPHOON:
146 		case CPU_PART_TYPHOON_CAPRI:
147 			cpufamily = CPUFAMILY_ARM_TYPHOON;
148 			break;
149 		case CPU_PART_TWISTER:
150 		case CPU_PART_TWISTER_ELBA_MALTA:
151 			cpufamily = CPUFAMILY_ARM_TWISTER;
152 			break;
153 		case CPU_PART_HURRICANE:
154 		case CPU_PART_HURRICANE_MYST:
155 			cpufamily = CPUFAMILY_ARM_HURRICANE;
156 			break;
157 		case CPU_PART_MONSOON:
158 		case CPU_PART_MISTRAL:
159 			cpufamily = CPUFAMILY_ARM_MONSOON_MISTRAL;
160 			break;
161 		case CPU_PART_VORTEX:
162 		case CPU_PART_TEMPEST:
163 		case CPU_PART_TEMPEST_M9:
164 		case CPU_PART_VORTEX_ARUBA:
165 		case CPU_PART_TEMPEST_ARUBA:
166 			cpufamily = CPUFAMILY_ARM_VORTEX_TEMPEST;
167 			break;
168 		case CPU_PART_LIGHTNING:
169 		case CPU_PART_THUNDER:
170 #ifndef RC_HIDE_XNU_FIRESTORM
171 		case CPU_PART_THUNDER_M10:
172 #endif
173 			cpufamily = CPUFAMILY_ARM_LIGHTNING_THUNDER;
174 			break;
175 		case CPU_PART_FIRESTORM_JADE_CHOP:
176 		case CPU_PART_FIRESTORM_JADE_DIE:
177 		case CPU_PART_ICESTORM_JADE_CHOP:
178 		case CPU_PART_ICESTORM_JADE_DIE:
179 #ifndef RC_HIDE_XNU_FIRESTORM
180 		case CPU_PART_FIRESTORM:
181 		case CPU_PART_ICESTORM:
182 		case CPU_PART_FIRESTORM_TONGA:
183 		case CPU_PART_ICESTORM_TONGA:
184 			cpufamily = CPUFAMILY_ARM_FIRESTORM_ICESTORM;
185 			break;
186 #endif
187 		default:
188 			cpufamily = CPUFAMILY_UNKNOWN;
189 			break;
190 		}
191 		break;
192 
193 	default:
194 		cpufamily = CPUFAMILY_UNKNOWN;
195 		break;
196 	}
197 
198 	return cpufamily;
199 }
200 
201 int
cpuid_get_cpusubfamily(void)202 cpuid_get_cpusubfamily(void)
203 {
204 	int cpusubfamily = CPUSUBFAMILY_UNKNOWN;
205 
206 	if (cpuid_info()->arm_info.arm_implementor != CPU_VID_APPLE) {
207 		return cpusubfamily;
208 	}
209 
210 	switch (cpuid_info()->arm_info.arm_part) {
211 	case CPU_PART_TYPHOON:
212 	case CPU_PART_TWISTER:
213 	case CPU_PART_HURRICANE:
214 	case CPU_PART_MONSOON:
215 	case CPU_PART_MISTRAL:
216 	case CPU_PART_VORTEX:
217 	case CPU_PART_TEMPEST:
218 	case CPU_PART_LIGHTNING:
219 	case CPU_PART_THUNDER:
220 #ifndef RC_HIDE_XNU_FIRESTORM
221 	case CPU_PART_FIRESTORM:
222 	case CPU_PART_ICESTORM:
223 #endif
224 		cpusubfamily = CPUSUBFAMILY_ARM_HP;
225 		break;
226 	case CPU_PART_TYPHOON_CAPRI:
227 	case CPU_PART_TWISTER_ELBA_MALTA:
228 	case CPU_PART_HURRICANE_MYST:
229 	case CPU_PART_VORTEX_ARUBA:
230 	case CPU_PART_TEMPEST_ARUBA:
231 #ifndef RC_HIDE_XNU_FIRESTORM
232 	case CPU_PART_FIRESTORM_TONGA:
233 	case CPU_PART_ICESTORM_TONGA:
234 #endif
235 		cpusubfamily = CPUSUBFAMILY_ARM_HG;
236 		break;
237 	case CPU_PART_TEMPEST_M9:
238 #ifndef RC_HIDE_XNU_FIRESTORM
239 	case CPU_PART_THUNDER_M10:
240 #endif
241 		cpusubfamily = CPUSUBFAMILY_ARM_M;
242 		break;
243 	case CPU_PART_FIRESTORM_JADE_CHOP:
244 	case CPU_PART_ICESTORM_JADE_CHOP:
245 		cpusubfamily = CPUSUBFAMILY_ARM_HS;
246 		break;
247 	case CPU_PART_FIRESTORM_JADE_DIE:
248 	case CPU_PART_ICESTORM_JADE_DIE:
249 		cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
250 		break;
251 	default:
252 		cpusubfamily = CPUFAMILY_UNKNOWN;
253 		break;
254 	}
255 
256 	return cpusubfamily;
257 }
258 
259 void
do_debugid(void)260 do_debugid(void)
261 {
262 	machine_do_debugid();
263 }
264 
265 arm_debug_info_t *
arm_debug_info(void)266 arm_debug_info(void)
267 {
268 	return machine_arm_debug_info();
269 }
270 
271 void
do_mvfpid(void)272 do_mvfpid(void)
273 {
274 	return machine_do_mvfpid();
275 }
276 
277 arm_mvfp_info_t
278 *
arm_mvfp_info(void)279 arm_mvfp_info(void)
280 {
281 	return machine_arm_mvfp_info();
282 }
283 
284 void
do_cacheid(void)285 do_cacheid(void)
286 {
287 	arm_cache_clidr_info_t arm_cache_clidr_info;
288 	arm_cache_ccsidr_info_t arm_cache_ccsidr_info;
289 
290 	/*
291 	 * We only need to parse cache geometry parameters once per cluster type.
292 	 * Skip this if some other core of the same type has already parsed them.
293 	 */
294 	cluster_type_t cluster_type = ml_get_topology_info()->cpus[ml_get_cpu_number_local()].cluster_type;
295 	uint8_t prev_cpuid_cache_info_bitmap = os_atomic_or_orig(&cpuid_cache_info_bitmap,
296 	    (uint8_t)(1 << cluster_type), acq_rel);
297 	if (prev_cpuid_cache_info_bitmap & (1 << cluster_type)) {
298 		return;
299 	}
300 
301 	cache_info_t *cpuid_cache_info_p = &cpuid_cache_info[cluster_type];
302 
303 	arm_cache_clidr_info.value = machine_read_clidr();
304 
305 	/*
306 	 * For compatibility purposes with existing callers, let's cache the boot CPU
307 	 * cache parameters and return those upon any call to cache_info();
308 	 */
309 	if (prev_cpuid_cache_info_bitmap == 0) {
310 		cpuid_cache_info_boot_cpu = cpuid_cache_info_p;
311 	}
312 
313 	/* Select L1 data/unified cache */
314 
315 	machine_write_csselr(CSSELR_L1, CSSELR_DATA_UNIFIED);
316 	arm_cache_ccsidr_info.value = machine_read_ccsidr();
317 
318 	cpuid_cache_info_p->c_unified = (arm_cache_clidr_info.bits.Ctype1 == 0x4) ? 1 : 0;
319 
320 	switch (arm_cache_ccsidr_info.bits.c_type) {
321 	case 0x1:
322 		cpuid_cache_info_p->c_type = CACHE_WRITE_ALLOCATION;
323 		break;
324 	case 0x2:
325 		cpuid_cache_info_p->c_type = CACHE_READ_ALLOCATION;
326 		break;
327 	case 0x4:
328 		cpuid_cache_info_p->c_type = CACHE_WRITE_BACK;
329 		break;
330 	case 0x8:
331 		cpuid_cache_info_p->c_type = CACHE_WRITE_THROUGH;
332 		break;
333 	default:
334 		cpuid_cache_info_p->c_type = CACHE_UNKNOWN;
335 	}
336 
337 	cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
338 	cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
339 
340 	/* I cache size */
341 	cpuid_cache_info_p->c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
342 
343 	/* D cache size */
344 	cpuid_cache_info_p->c_dsize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
345 
346 
347 	if ((arm_cache_clidr_info.bits.Ctype3 == 0x4) ||
348 	    (arm_cache_clidr_info.bits.Ctype2 == 0x4) || (arm_cache_clidr_info.bits.Ctype2 == 0x2)) {
349 		if (arm_cache_clidr_info.bits.Ctype3 == 0x4) {
350 			/* Select L3 (LLC) if the SoC is new enough to have that.
351 			 * This will be the second-level cache for the highest-performing ACC. */
352 			machine_write_csselr(CSSELR_L3, CSSELR_DATA_UNIFIED);
353 		} else {
354 			/* Select L2 data cache */
355 			machine_write_csselr(CSSELR_L2, CSSELR_DATA_UNIFIED);
356 		}
357 		arm_cache_ccsidr_info.value = machine_read_ccsidr();
358 
359 		cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
360 		cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
361 		cpuid_cache_info_p->c_l2size = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
362 		cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
363 		cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_l2size;
364 
365 		/* capri has a 2MB L2 cache unlike every other SoC up to this
366 		 * point with a 1MB L2 cache, so to get the same performance
367 		 * gain from coloring, we have to double the number of colors.
368 		 * Note that in general (and in fact as it's implemented in
369 		 * i386/cpuid.c), the number of colors is calculated as the
370 		 * cache line size * the number of sets divided by the page
371 		 * size. Also note that for H8 devices and up, the page size
372 		 * will be 16k instead of 4, which will reduce the number of
373 		 * colors required. Thus, this is really a temporary solution
374 		 * for capri specifically that we may want to generalize later:
375 		 *
376 		 * TODO: Are there any special considerations for our unusual
377 		 * cache geometries (3MB)?
378 		 */
379 		vm_cache_geometry_colors = ((arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz) / PAGE_SIZE;
380 		kprintf(" vm_cache_geometry_colors: %d\n", vm_cache_geometry_colors);
381 	} else {
382 		cpuid_cache_info_p->c_l2size = 0;
383 
384 		cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
385 		cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_dsize;
386 	}
387 
388 	if (cpuid_cache_info_p->c_unified == 0) {
389 		machine_write_csselr(CSSELR_L1, CSSELR_INSTR);
390 		arm_cache_ccsidr_info.value = machine_read_ccsidr();
391 		uint32_t c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
392 		uint32_t c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
393 		/* I cache size */
394 		cpuid_cache_info_p->c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * c_linesz * c_assoc;
395 	}
396 
397 	kprintf("%s() - %u bytes %s cache (I:%u D:%u (%s)), %u-way assoc, %u bytes/line\n",
398 	    __FUNCTION__,
399 	    cpuid_cache_info_p->c_dsize + cpuid_cache_info_p->c_isize,
400 	    ((cpuid_cache_info_p->c_type == CACHE_WRITE_BACK) ? "WB" :
401 	    (cpuid_cache_info_p->c_type == CACHE_WRITE_THROUGH ? "WT" : "Unknown")),
402 	    cpuid_cache_info_p->c_isize,
403 	    cpuid_cache_info_p->c_dsize,
404 	    (cpuid_cache_info_p->c_unified) ? "unified" : "separate",
405 	    cpuid_cache_info_p->c_assoc,
406 	    cpuid_cache_info_p->c_linesz);
407 }
408 
409 cache_info_t   *
cache_info(void)410 cache_info(void)
411 {
412 	return cpuid_cache_info_boot_cpu;
413 }
414 
415 cache_info_t   *
cache_info_type(cluster_type_t cluster_type)416 cache_info_type(cluster_type_t cluster_type)
417 {
418 	assert((cluster_type >= 0) && (cluster_type < MAX_CPU_TYPES));
419 	return &cpuid_cache_info[cluster_type];
420 }
421