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