Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
/*
 * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
/*
 * @OSF_COPYRIGHT@
 */

#include <pexpert/pexpert.h>
#include <arm/cpuid.h>
#include <arm/cpuid_internal.h>
#include <arm/cpu_data_internal.h>
#include <arm64/proc_reg.h>
#include <kern/lock_rw.h>
#include <vm/vm_page.h>

#include <libkern/section_keywords.h>

/* Temporary types to aid decoding,
 * Everything in Little Endian */

typedef struct {
	uint32_t
	    Ctype1:3, /* 2:0 */
	    Ctype2:3, /* 5:3 */
	    Ctype3:3, /* 8:6 */
	    Ctypes:15, /* 6:23 - Don't Care */
	    LoC:3, /* 26-24 - Level of Coherency */
	    LoU:3, /* 29:27 - Level of Unification */
	    RAZ:2; /* 31:30 - Read-As-Zero */
} arm_cache_clidr_t;

typedef union {
	arm_cache_clidr_t bits;
	uint32_t          value;
} arm_cache_clidr_info_t;


typedef struct {
	uint32_t
	    LineSize:3, /* 2:0 - Number of words in cache line */
	    Assoc:10, /* 12:3 - Associativity of cache */
	    NumSets:15, /* 27:13 - Number of sets in cache */
	    c_type:4; /* 31:28 - Cache type */
} arm_cache_ccsidr_t;


typedef union {
	arm_cache_ccsidr_t bits;
	uint32_t           value;
} arm_cache_ccsidr_info_t;

/* Statics */

static SECURITY_READ_ONLY_LATE(arm_cpu_info_t) cpuid_cpu_info;
static SECURITY_READ_ONLY_LATE(cache_info_t *) cpuid_cache_info_boot_cpu;
static cache_info_t cpuid_cache_info[MAX_CPU_TYPES] = { 0 };
static _Atomic uint8_t cpuid_cache_info_bitmap = 0;

/* Code */

__private_extern__
void
do_cpuid(void)
{
	cpuid_cpu_info.value = machine_read_midr();
#if (__ARM_ARCH__ == 8)

#if defined(HAS_APPLE_PAC)
	cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8E;
#else /* defined(HAS_APPLE_PAC) */
	cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8;
#endif /* defined(HAS_APPLE_PAC) */

#else /* (__ARM_ARCH__ != 8) */
#error Unsupported arch
#endif /* (__ARM_ARCH__ != 8) */
}

arm_cpu_info_t *
cpuid_info(void)
{
	return &cpuid_cpu_info;
}

int
cpuid_get_cpufamily(void)
{
	int cpufamily = 0;

	switch (cpuid_info()->arm_info.arm_implementor) {
	case CPU_VID_ARM:
		switch (cpuid_info()->arm_info.arm_part) {
		case CPU_PART_CORTEXA9:
			cpufamily = CPUFAMILY_ARM_14;
			break;
		case CPU_PART_CORTEXA8:
			cpufamily = CPUFAMILY_ARM_13;
			break;
		case CPU_PART_CORTEXA7:
			cpufamily = CPUFAMILY_ARM_15;
			break;
		case CPU_PART_1136JFS:
		case CPU_PART_1176JZFS:
			cpufamily = CPUFAMILY_ARM_11;
			break;
		case CPU_PART_926EJS:
		case CPU_PART_920T:
			cpufamily = CPUFAMILY_ARM_9;
			break;
		default:
			cpufamily = CPUFAMILY_UNKNOWN;
			break;
		}
		break;

	case CPU_VID_INTEL:
		cpufamily = CPUFAMILY_ARM_XSCALE;
		break;

	case CPU_VID_APPLE:
		switch (cpuid_info()->arm_info.arm_part) {
		case CPU_PART_TYPHOON:
		case CPU_PART_TYPHOON_CAPRI:
			cpufamily = CPUFAMILY_ARM_TYPHOON;
			break;
		case CPU_PART_TWISTER:
		case CPU_PART_TWISTER_ELBA_MALTA:
			cpufamily = CPUFAMILY_ARM_TWISTER;
			break;
		case CPU_PART_HURRICANE:
		case CPU_PART_HURRICANE_MYST:
			cpufamily = CPUFAMILY_ARM_HURRICANE;
			break;
		case CPU_PART_MONSOON:
		case CPU_PART_MISTRAL:
			cpufamily = CPUFAMILY_ARM_MONSOON_MISTRAL;
			break;
		case CPU_PART_VORTEX:
		case CPU_PART_TEMPEST:
		case CPU_PART_TEMPEST_M9:
		case CPU_PART_VORTEX_ARUBA:
		case CPU_PART_TEMPEST_ARUBA:
			cpufamily = CPUFAMILY_ARM_VORTEX_TEMPEST;
			break;
		case CPU_PART_LIGHTNING:
		case CPU_PART_THUNDER:
		case CPU_PART_THUNDER_M10:
			cpufamily = CPUFAMILY_ARM_LIGHTNING_THUNDER;
			break;
		case CPU_PART_FIRESTORM_JADE_CHOP:
		case CPU_PART_FIRESTORM_JADE_DIE:
		case CPU_PART_ICESTORM_JADE_CHOP:
		case CPU_PART_ICESTORM_JADE_DIE:
		case CPU_PART_FIRESTORM_SICILY:
		case CPU_PART_ICESTORM_SICILY:
		case CPU_PART_FIRESTORM_TONGA:
		case CPU_PART_ICESTORM_TONGA:
			cpufamily = CPUFAMILY_ARM_FIRESTORM_ICESTORM;
			break;
		case CPU_PART_BLIZZARD_STATEN:
		case CPU_PART_AVALANCHE_STATEN:
		case CPU_PART_BLIZZARD_RHODES_CHOP:
		case CPU_PART_AVALANCHE_RHODES_CHOP:
		case CPU_PART_BLIZZARD_RHODES_DIE:
		case CPU_PART_AVALANCHE_RHODES_DIE:
		case CPU_PART_BLIZZARD_ELLIS:
		case CPU_PART_AVALANCHE_ELLIS:
			cpufamily = CPUFAMILY_ARM_BLIZZARD_AVALANCHE;
			break;
		case CPU_PART_EVEREST:
		case CPU_PART_SAWTOOTH:
		case CPU_PART_SAWTOOTH_M11:
			cpufamily = CPUFAMILY_ARM_EVEREST_SAWTOOTH;
			break;
		case CPU_PART_ECORE_IBIZA:
		case CPU_PART_PCORE_IBIZA:
			cpufamily = CPUFAMILY_ARM_IBIZA;
			break;
		case CPU_PART_ECORE_PALMA:
		case CPU_PART_PCORE_PALMA:
			cpufamily = CPUFAMILY_ARM_PALMA;
			break;
		case CPU_PART_ECORE_COLL:
		case CPU_PART_PCORE_COLL:
			cpufamily = CPUFAMILY_ARM_COLL;
			break;
		case CPU_PART_ECORE_LOBOS:
		case CPU_PART_PCORE_LOBOS:
			cpufamily = CPUFAMILY_ARM_LOBOS;
			break;
		case CPU_PART_ECORE_DONAN:
		case CPU_PART_PCORE_DONAN:
			cpufamily = CPUFAMILY_ARM_DONAN;
			break;
		case CPU_PART_ECORE_BRAVA_S:
		case CPU_PART_PCORE_BRAVA_S:
		case CPU_PART_ECORE_BRAVA_C:
		case CPU_PART_PCORE_BRAVA_C:
			cpufamily = CPUFAMILY_ARM_BRAVA;
			break;
		case CPU_PART_ECORE_TAHITI:
		case CPU_PART_PCORE_TAHITI:
			cpufamily = CPUFAMILY_ARM_TAHITI;
			break;
		case CPU_PART_ECORE_TUPAI:
		case CPU_PART_PCORE_TUPAI:
			cpufamily = CPUFAMILY_ARM_TUPAI;
			break;
		case CPU_PART_ECORE_HIDRA:
		case CPU_PART_PCORE_HIDRA:
			cpufamily = CPUFAMILY_ARM_HIDRA;
			break;
		case CPU_PART_ECORE_THERA:
		case CPU_PART_PCORE_THERA:
			cpufamily = CPUFAMILY_ARM_THERA;
			break;
		case CPU_PART_ECORE_TILOS:
		case CPU_PART_PCORE_TILOS:
			cpufamily = CPUFAMILY_ARM_TILOS;
			break;
		default:
			cpufamily = CPUFAMILY_UNKNOWN;
			break;
		}
		break;

	default:
		cpufamily = CPUFAMILY_UNKNOWN;
		break;
	}

	return cpufamily;
}

int
cpuid_get_cpusubfamily(void)
{
	int cpusubfamily = CPUSUBFAMILY_UNKNOWN;

	if (cpuid_info()->arm_info.arm_implementor != CPU_VID_APPLE) {
		return cpusubfamily;
	}

	switch (cpuid_info()->arm_info.arm_part) {
	case CPU_PART_TYPHOON:
	case CPU_PART_TWISTER:
	case CPU_PART_HURRICANE:
	case CPU_PART_MONSOON:
	case CPU_PART_MISTRAL:
	case CPU_PART_VORTEX:
	case CPU_PART_TEMPEST:
	case CPU_PART_LIGHTNING:
	case CPU_PART_THUNDER:
	case CPU_PART_FIRESTORM_SICILY:
	case CPU_PART_ICESTORM_SICILY:
	case CPU_PART_BLIZZARD_ELLIS:
	case CPU_PART_AVALANCHE_ELLIS:
	case CPU_PART_SAWTOOTH:
	case CPU_PART_EVEREST:
		cpusubfamily = CPUSUBFAMILY_ARM_HP;
		break;
	case CPU_PART_TYPHOON_CAPRI:
	case CPU_PART_TWISTER_ELBA_MALTA:
	case CPU_PART_HURRICANE_MYST:
	case CPU_PART_VORTEX_ARUBA:
	case CPU_PART_TEMPEST_ARUBA:
	case CPU_PART_FIRESTORM_TONGA:
	case CPU_PART_ICESTORM_TONGA:
	case CPU_PART_BLIZZARD_STATEN:
	case CPU_PART_AVALANCHE_STATEN:
		cpusubfamily = CPUSUBFAMILY_ARM_HG;
		break;
	case CPU_PART_TEMPEST_M9:
	case CPU_PART_THUNDER_M10:
	case CPU_PART_SAWTOOTH_M11:
		cpusubfamily = CPUSUBFAMILY_ARM_M;
		break;
	case CPU_PART_ECORE_IBIZA:
	case CPU_PART_PCORE_IBIZA:
		cpusubfamily = CPUSUBFAMILY_ARM_HG;
		break;
	case CPU_PART_ECORE_COLL:
	case CPU_PART_PCORE_COLL:
		cpusubfamily = CPUSUBFAMILY_ARM_HP;
		break;
	case CPU_PART_ECORE_PALMA:
	case CPU_PART_PCORE_PALMA:
		cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
		break;
	case CPU_PART_ECORE_LOBOS:
	case CPU_PART_PCORE_LOBOS:
		cpusubfamily = CPUSUBFAMILY_ARM_HS;
		break;
	case CPU_PART_FIRESTORM_JADE_CHOP:
	case CPU_PART_ICESTORM_JADE_CHOP:
		cpusubfamily = CPUSUBFAMILY_ARM_HS;
		break;
	case CPU_PART_FIRESTORM_JADE_DIE:
	case CPU_PART_ICESTORM_JADE_DIE:
		cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
		break;
	case CPU_PART_BLIZZARD_RHODES_CHOP:
	case CPU_PART_AVALANCHE_RHODES_CHOP:
		cpusubfamily = CPUSUBFAMILY_ARM_HS;
		break;
	case CPU_PART_BLIZZARD_RHODES_DIE:
	case CPU_PART_AVALANCHE_RHODES_DIE:
		cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
		break;
	case CPU_PART_ECORE_DONAN:
	case CPU_PART_PCORE_DONAN:
		cpusubfamily = CPUSUBFAMILY_ARM_HG;
		break;
	case CPU_PART_ECORE_BRAVA_S:
	case CPU_PART_PCORE_BRAVA_S:
		cpusubfamily = CPUSUBFAMILY_ARM_HS;
		break;
	case CPU_PART_ECORE_BRAVA_C:
	case CPU_PART_PCORE_BRAVA_C:
		cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
		break;
	case CPU_PART_ECORE_TAHITI:
	case CPU_PART_PCORE_TAHITI:
		cpusubfamily = CPUSUBFAMILY_ARM_HP;
		break;
	case CPU_PART_ECORE_TUPAI:
	case CPU_PART_PCORE_TUPAI:
		cpusubfamily = CPUSUBFAMILY_ARM_HA;
		break;
	case CPU_PART_ECORE_HIDRA:
	case CPU_PART_PCORE_HIDRA:
		cpusubfamily = CPUSUBFAMILY_ARM_HG;
		break;
	case CPU_PART_ECORE_THERA:
	case CPU_PART_PCORE_THERA:
		cpusubfamily = CPUSUBFAMILY_ARM_HP;
		break;
	case CPU_PART_ECORE_TILOS:
	case CPU_PART_PCORE_TILOS:
		cpusubfamily = CPUSUBFAMILY_ARM_HA;
		break;
	default:
		cpusubfamily = CPUSUBFAMILY_UNKNOWN;
		break;
	}

	return cpusubfamily;
}

void
do_debugid(void)
{
	machine_do_debugid();
}

arm_debug_info_t *
arm_debug_info(void)
{
	return machine_arm_debug_info();
}

void
do_mvfpid(void)
{
	return machine_do_mvfpid();
}

arm_mvfp_info_t
*
arm_mvfp_info(void)
{
	return machine_arm_mvfp_info();
}


void
do_cacheid(void)
{
	arm_cache_clidr_info_t arm_cache_clidr_info;
	arm_cache_ccsidr_info_t arm_cache_ccsidr_info;

	/*
	 * We only need to parse cache geometry parameters once per cluster type.
	 * Skip this if some other core of the same type has already parsed them.
	 */
	cluster_type_t cluster_type = ml_get_topology_info()->cpus[ml_get_cpu_number_local()].cluster_type;
	uint8_t prev_cpuid_cache_info_bitmap = os_atomic_or_orig(&cpuid_cache_info_bitmap,
	    (uint8_t)(1 << cluster_type), acq_rel);
	if (prev_cpuid_cache_info_bitmap & (1 << cluster_type)) {
		return;
	}

	cache_info_t *cpuid_cache_info_p = &cpuid_cache_info[cluster_type];

	arm_cache_clidr_info.value = machine_read_clidr();


	/*
	 * For compatibility purposes with existing callers, let's cache the boot CPU
	 * cache parameters and return those upon any call to cache_info();
	 */
	if (prev_cpuid_cache_info_bitmap == 0) {
		cpuid_cache_info_boot_cpu = cpuid_cache_info_p;
	}

	/* Select L1 data/unified cache */

	machine_write_csselr(CSSELR_L1, CSSELR_DATA_UNIFIED);
	arm_cache_ccsidr_info.value = machine_read_ccsidr();

	cpuid_cache_info_p->c_unified = (arm_cache_clidr_info.bits.Ctype1 == 0x4) ? 1 : 0;

	switch (arm_cache_ccsidr_info.bits.c_type) {
	case 0x1:
		cpuid_cache_info_p->c_type = CACHE_WRITE_ALLOCATION;
		break;
	case 0x2:
		cpuid_cache_info_p->c_type = CACHE_READ_ALLOCATION;
		break;
	case 0x4:
		cpuid_cache_info_p->c_type = CACHE_WRITE_BACK;
		break;
	case 0x8:
		cpuid_cache_info_p->c_type = CACHE_WRITE_THROUGH;
		break;
	default:
		cpuid_cache_info_p->c_type = CACHE_UNKNOWN;
	}

	cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
	cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);

	/* I cache size */
	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;

	/* D cache size */
	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;


	if ((arm_cache_clidr_info.bits.Ctype3 == 0x4) ||
	    (arm_cache_clidr_info.bits.Ctype2 == 0x4) || (arm_cache_clidr_info.bits.Ctype2 == 0x2)) {
		if (arm_cache_clidr_info.bits.Ctype3 == 0x4) {
			/* Select L3 (LLC) if the SoC is new enough to have that.
			 * This will be the second-level cache for the highest-performing ACC. */
			machine_write_csselr(CSSELR_L3, CSSELR_DATA_UNIFIED);
		} else {
			/* Select L2 data cache */
			machine_write_csselr(CSSELR_L2, CSSELR_DATA_UNIFIED);
		}
		arm_cache_ccsidr_info.value = machine_read_ccsidr();

		cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
		cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
		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;
		cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
		cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_l2size;

		/* capri has a 2MB L2 cache unlike every other SoC up to this
		 * point with a 1MB L2 cache, so to get the same performance
		 * gain from coloring, we have to double the number of colors.
		 * Note that in general (and in fact as it's implemented in
		 * i386/cpuid.c), the number of colors is calculated as the
		 * cache line size * the number of sets divided by the page
		 * size. Also note that for H8 devices and up, the page size
		 * will be 16k instead of 4, which will reduce the number of
		 * colors required. Thus, this is really a temporary solution
		 * for capri specifically that we may want to generalize later:
		 *
		 * TODO: Are there any special considerations for our unusual
		 * cache geometries (3MB)?
		 */
		vm_cache_geometry_colors = ((arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz) / PAGE_SIZE;
		kprintf(" vm_cache_geometry_colors: %d\n", vm_cache_geometry_colors);
	} else {
		cpuid_cache_info_p->c_l2size = 0;

		cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
		cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_dsize;
	}

	if (cpuid_cache_info_p->c_unified == 0) {
		machine_write_csselr(CSSELR_L1, CSSELR_INSTR);
		arm_cache_ccsidr_info.value = machine_read_ccsidr();
		uint32_t c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
		uint32_t c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
		/* I cache size */
		cpuid_cache_info_p->c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * c_linesz * c_assoc;
	}

	if (cpuid_cache_info_p == cpuid_cache_info_boot_cpu) {
		cpuid_cache_info_p->c_valid = true;
	} else {
		os_atomic_store(&cpuid_cache_info_p->c_valid, true, release);
		thread_wakeup((event_t)&cpuid_cache_info_p->c_valid);
	}

	kprintf("%s() - %u bytes %s cache (I:%u D:%u (%s)), %u-way assoc, %u bytes/line\n",
	    __FUNCTION__,
	    cpuid_cache_info_p->c_dsize + cpuid_cache_info_p->c_isize,
	    ((cpuid_cache_info_p->c_type == CACHE_WRITE_BACK) ? "WB" :
	    (cpuid_cache_info_p->c_type == CACHE_WRITE_THROUGH ? "WT" : "Unknown")),
	    cpuid_cache_info_p->c_isize,
	    cpuid_cache_info_p->c_dsize,
	    (cpuid_cache_info_p->c_unified) ? "unified" : "separate",
	    cpuid_cache_info_p->c_assoc,
	    cpuid_cache_info_p->c_linesz);
}

cache_info_t   *
cache_info(void)
{
	return cpuid_cache_info_boot_cpu;
}

cache_info_t   *
cache_info_type(cluster_type_t cluster_type)
{
	assert((cluster_type >= 0) && (cluster_type < MAX_CPU_TYPES));
	cache_info_t *ret = &cpuid_cache_info[cluster_type];

	/*
	 * cpuid_cache_info_boot_cpu is always populated by the time
	 * cache_info_type() is callable.  Other clusters may not have completed
	 * do_cacheid() yet.
	 */
	if (ret == cpuid_cache_info_boot_cpu) {
		return ret;
	}

	while (!os_atomic_load(&ret->c_valid, acquire)) {
		assert_wait((event_t)&ret->c_valid, THREAD_UNINT);
		if (os_atomic_load(&ret->c_valid, relaxed)) {
			clear_wait(current_thread(), THREAD_AWAKENED);
		} else {
			thread_block(THREAD_CONTINUE_NULL);
		}
	}

	return ret;
}