xref: /titanic_51/usr/src/uts/sun4v/os/fillsysinfo.c (revision c5f9a89643b6d7175323dcb29f1a665661143c67)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/cpu.h>
30 #include <sys/cpuvar.h>
31 #include <sys/clock.h>
32 #include <sys/promif.h>
33 #include <sys/promimpl.h>
34 #include <sys/systm.h>
35 #include <sys/machsystm.h>
36 #include <sys/debug.h>
37 #include <sys/sunddi.h>
38 #include <sys/modctl.h>
39 #include <sys/cpu_module.h>
40 #include <sys/kobj.h>
41 #include <sys/cmp.h>
42 #include <sys/async.h>
43 #include <vm/page.h>
44 #include <vm/vm_dep.h>
45 #include <vm/hat_sfmmu.h>
46 #include <sys/sysmacros.h>
47 #include <sys/mach_descrip.h>
48 #include <sys/mdesc.h>
49 #include <sys/archsystm.h>
50 #include <sys/error.h>
51 #include <sys/mmu.h>
52 #include <sys/bitmap.h>
53 #include <sys/intreg.h>
54 
55 struct cpu_node cpunodes[NCPU];
56 
57 uint64_t cpu_q_entries;
58 uint64_t dev_q_entries;
59 uint64_t cpu_rq_entries;
60 uint64_t cpu_nrq_entries;
61 uint64_t ncpu_guest_max;
62 
63 void fill_cpu(md_t *, mde_cookie_t);
64 
65 static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t);
66 static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t);
67 static uint64_t	get_mmu_shcontexts(md_t *, mde_cookie_t);
68 static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t);
69 static int check_mmu_pgsz_search(md_t *, mde_cookie_t);
70 static char *construct_isalist(md_t *, mde_cookie_t, char **);
71 static void init_md_broken(md_t *, mde_cookie_t *);
72 static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *,
73     uint64_t *);
74 static void get_hwcaps(md_t *, mde_cookie_t);
75 static void get_q_sizes(md_t *, mde_cookie_t);
76 static void get_va_bits(md_t *, mde_cookie_t);
77 static size_t get_ra_limit(md_t *);
78 static int get_l2_cache_node_count(md_t *);
79 static unsigned long names2bits(char *tokens, size_t tokenslen,
80     char *bit_formatter, char *warning);
81 
82 uint64_t	system_clock_freq;
83 uint_t		niommu_tsbs = 0;
84 
85 static int n_l2_caches = 0;
86 
87 /* prevent compilation with VAC defined */
88 #ifdef VAC
89 #error "The sun4v architecture does not support VAC"
90 #endif
91 
92 #define	S_VAC_SIZE	MMU_PAGESIZE
93 #define	S_VAC_SHIFT	MMU_PAGESHIFT
94 
95 int		vac_size = S_VAC_SIZE;
96 uint_t		vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1);
97 int		vac_shift = S_VAC_SHIFT;
98 uintptr_t	shm_alignment = S_VAC_SIZE;
99 
100 void
101 map_wellknown_devices()
102 {
103 }
104 
105 void
106 fill_cpu(md_t *mdp, mde_cookie_t cpuc)
107 {
108 	struct cpu_node *cpunode;
109 	uint64_t cpuid;
110 	uint64_t clk_freq;
111 	char *namebuf;
112 	char *namebufp;
113 	int namelen;
114 	uint64_t associativity = 0, linesize = 0, size = 0;
115 
116 	if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) {
117 		return;
118 	}
119 
120 	/* All out-of-range cpus will be stopped later. */
121 	if (cpuid >= NCPU) {
122 		cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - "
123 		    "cpu excluded from configuration\n", cpuid);
124 
125 		return;
126 	}
127 
128 	cpunode = &cpunodes[cpuid];
129 	cpunode->cpuid = (int)cpuid;
130 	cpunode->device_id = cpuid;
131 
132 	if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI))
133 		(void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI);
134 
135 	if (md_get_prop_data(mdp, cpuc,
136 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
137 		cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible "
138 		    "property");
139 	}
140 	namebufp = namebuf;
141 	if (strncmp(namebufp, "SUNW,", 5) == 0)
142 		namebufp += 5;
143 	if (strlen(namebufp) > sizeof (cpunode->name))
144 		cmn_err(CE_PANIC, "Compatible property too big to "
145 		    "fit into the cpunode name buffer");
146 	(void) strcpy(cpunode->name, namebufp);
147 
148 	if (md_get_prop_val(mdp, cpuc,
149 	    "clock-frequency", &clk_freq)) {
150 			clk_freq = 0;
151 	}
152 	cpunode->clock_freq = clk_freq;
153 
154 	ASSERT(cpunode->clock_freq != 0);
155 	/*
156 	 * Compute scaling factor based on rate of %tick. This is used
157 	 * to convert from ticks derived from %tick to nanoseconds. See
158 	 * comment in sun4u/sys/clock.h for details.
159 	 */
160 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
161 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
162 
163 	/*
164 	 * The nodeid is not used in sun4v at all. Setting it
165 	 * to positive value to make starting of slave CPUs
166 	 * code happy.
167 	 */
168 	cpunode->nodeid = cpuid + 1;
169 
170 	/*
171 	 * Obtain the L2 cache information from MD.
172 	 * If "Cache" node exists, then set L2 cache properties
173 	 * as read from MD.
174 	 * If node does not exists, then set the L2 cache properties
175 	 * in individual CPU module.
176 	 */
177 	if ((!get_l2_cache_info(mdp, cpuc,
178 	    &associativity, &size, &linesize)) ||
179 	    associativity == 0 || size == 0 || linesize == 0) {
180 		cpu_fiximp(cpunode);
181 	} else {
182 		/*
183 		 * Do not expect L2 cache properties to be bigger
184 		 * than 32-bit quantity.
185 		 */
186 		cpunode->ecache_associativity = (int)associativity;
187 		cpunode->ecache_size = (int)size;
188 		cpunode->ecache_linesize = (int)linesize;
189 	}
190 
191 	cpunode->ecache_setsize =
192 	    cpunode->ecache_size / cpunode->ecache_associativity;
193 
194 	/*
195 	 * Initialize the mapping for exec unit, chip and core.
196 	 */
197 	cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND;
198 	cpunode->l2_cache_mapping = NO_MAPPING_FOUND;
199 	cpunode->core_mapping = NO_CORE_MAPPING_FOUND;
200 
201 	if (ecache_setsize == 0)
202 		ecache_setsize = cpunode->ecache_setsize;
203 	if (ecache_alignsize == 0)
204 		ecache_alignsize = cpunode->ecache_linesize;
205 
206 }
207 
208 void
209 empty_cpu(int cpuid)
210 {
211 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
212 }
213 
214 /*
215  * Use L2 cache node to derive the chip mapping.
216  */
217 void
218 setup_chip_mappings(md_t *mdp)
219 {
220 	int ncache, ncpu;
221 	mde_cookie_t *node, *cachelist;
222 	int i, j;
223 	processorid_t cpuid;
224 	int idx = 0;
225 
226 	ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache",
227 	    "fwd", &cachelist);
228 
229 	/*
230 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
231 	 */
232 	if (ncache < 1) {
233 		return;
234 	}
235 
236 	for (i = 0; i < ncache; i++) {
237 		uint64_t cache_level;
238 		uint64_t lcpuid;
239 
240 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
241 			continue;
242 
243 		if (cache_level != 2)
244 			continue;
245 
246 		/*
247 		 * Found a l2 cache node. Find out the cpu nodes it
248 		 * points to.
249 		 */
250 		ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu",
251 		    "back", &node);
252 
253 		if (ncpu < 1)
254 			continue;
255 
256 		for (j = 0; j < ncpu; j++) {
257 			if (md_get_prop_val(mdp, node[j], "id", &lcpuid))
258 				continue;
259 			if (lcpuid >= NCPU)
260 				continue;
261 			cpuid = (processorid_t)lcpuid;
262 			cpunodes[cpuid].l2_cache_mapping = idx;
263 		}
264 		md_free_scan_dag(mdp, &node);
265 
266 		idx++;
267 	}
268 
269 	md_free_scan_dag(mdp, &cachelist);
270 }
271 
272 void
273 setup_exec_unit_mappings(md_t *mdp)
274 {
275 	int num, num_eunits;
276 	mde_cookie_t cpus_node;
277 	mde_cookie_t *node, *eunit;
278 	int idx, i, j;
279 	processorid_t cpuid;
280 	char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit";
281 	enum eu_type { INTEGER, FPU } etype;
282 
283 	/*
284 	 * Find the cpu integer exec units - and
285 	 * setup the mappings appropriately.
286 	 */
287 	num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node);
288 	if (num < 1)
289 		cmn_err(CE_PANIC, "No cpus node in machine description");
290 	if (num > 1)
291 		cmn_err(CE_PANIC, "More than 1 cpus node in machine"
292 		    " description");
293 
294 	cpus_node = node[0];
295 	md_free_scan_dag(mdp, &node);
296 
297 	num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name,
298 	    "fwd", &eunit);
299 	if (num_eunits > 0) {
300 		char *int_str = broken_md_flag ? "int" : "integer";
301 		char *fpu_str = "fp";
302 
303 		/* Spin through and find all the integer exec units */
304 		for (i = 0; i < num_eunits; i++) {
305 			char *p;
306 			char *val;
307 			int vallen;
308 			uint64_t lcpuid;
309 
310 			/* ignore nodes with no type */
311 			if (md_get_prop_data(mdp, eunit[i], "type",
312 			    (uint8_t **)&val, &vallen))
313 				continue;
314 
315 			for (p = val; *p != '\0'; p += strlen(p) + 1) {
316 				if (strcmp(p, int_str) == 0) {
317 					etype = INTEGER;
318 					goto found;
319 				}
320 				if (strcmp(p, fpu_str) == 0) {
321 					etype = FPU;
322 					goto found;
323 				}
324 			}
325 
326 			continue;
327 found:
328 			idx = NCPU + i;
329 			/*
330 			 * find the cpus attached to this EU and
331 			 * update their mapping indices
332 			 */
333 			num = md_alloc_scan_dag(mdp, eunit[i], "cpu",
334 			    "back", &node);
335 
336 			if (num < 1)
337 				cmn_err(CE_PANIC, "exec-unit node in MD"
338 				    " not attached to a cpu node");
339 
340 			for (j = 0; j < num; j++) {
341 				if (md_get_prop_val(mdp, node[j], "id",
342 				    &lcpuid))
343 					continue;
344 				if (lcpuid >= NCPU)
345 					continue;
346 				cpuid = (processorid_t)lcpuid;
347 				switch (etype) {
348 				case INTEGER:
349 					cpunodes[cpuid].exec_unit_mapping = idx;
350 					break;
351 				case FPU:
352 					cpunodes[cpuid].fpu_mapping = idx;
353 					break;
354 				}
355 			}
356 			md_free_scan_dag(mdp, &node);
357 		}
358 		md_free_scan_dag(mdp, &eunit);
359 	}
360 }
361 
362 /*
363  * Setup instruction cache coherency.  The "memory-coherent" property
364  * is optional.  Default for Icache_coherency is 1 (I$ is coherent).
365  * If we find an Icache with coherency == 0, then enable non-coherent
366  * Icache support.
367  */
368 void
369 setup_icache_coherency(md_t *mdp)
370 {
371 	int ncache;
372 	mde_cookie_t *cachelist;
373 	int i;
374 
375 	ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache",
376 	    "fwd", &cachelist);
377 
378 	/*
379 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
380 	 */
381 	if (ncache < 1) {
382 		return;
383 	}
384 
385 	for (i = 0; i < ncache; i++) {
386 		uint64_t cache_level;
387 		uint64_t memory_coherent;
388 		uint8_t *type;
389 		int typelen;
390 
391 		if (md_get_prop_val(mdp, cachelist[i], "level",
392 		    &cache_level))
393 			continue;
394 
395 		if (cache_level != 1)
396 			continue;
397 
398 		if (md_get_prop_data(mdp, cachelist[i], "type",
399 		    &type, &typelen))
400 			continue;
401 
402 		if (strcmp((char *)type, "instn") != 0)
403 			continue;
404 
405 		if (md_get_prop_val(mdp, cachelist[i], "memory-coherent",
406 		    &memory_coherent))
407 			continue;
408 
409 		if (memory_coherent != 0)
410 			continue;
411 
412 		mach_setup_icache(memory_coherent);
413 		break;
414 	}
415 
416 	md_free_scan_dag(mdp, &cachelist);
417 }
418 
419 /*
420  * All the common setup of sun4v CPU modules is done by this routine.
421  */
422 void
423 cpu_setup_common(char **cpu_module_isa_set)
424 {
425 	extern int mmu_exported_pagesize_mask;
426 	int nocpus, i;
427 	size_t ra_limit;
428 	mde_cookie_t *cpulist;
429 	md_t *mdp;
430 
431 	if ((mdp = md_get_handle()) == NULL)
432 		cmn_err(CE_PANIC, "Unable to initialize machine description");
433 
434 	boot_ncpus = nocpus = md_alloc_scan_dag(mdp,
435 	    md_root_node(mdp), "cpu", "fwd", &cpulist);
436 	if (nocpus < 1) {
437 		cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation "
438 		    "failed or incorrect number of CPUs in MD");
439 	}
440 
441 	init_md_broken(mdp, cpulist);
442 
443 	if (use_page_coloring) {
444 		do_pg_coloring = 1;
445 	}
446 
447 	/*
448 	 * Get the valid mmu page sizes mask, Q sizes and isalist/r
449 	 * from the MD for the first available CPU in cpulist.
450 	 *
451 	 * Do not expect the MMU page sizes mask to be more than 32-bit.
452 	 */
453 	mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]);
454 
455 	/*
456 	 * Get the number of contexts and tsbs supported.
457 	 */
458 	if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS &&
459 	    get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) {
460 		shctx_on = 1;
461 	}
462 
463 	/*
464 	 *  Get and check page search register properties.
465 	 */
466 	pgsz_search_on = check_mmu_pgsz_search(mdp, cpulist[0]);
467 
468 	for (i = 0; i < nocpus; i++)
469 		fill_cpu(mdp, cpulist[i]);
470 
471 	/* setup l2 cache count. */
472 	n_l2_caches = get_l2_cache_node_count(mdp);
473 
474 	setup_chip_mappings(mdp);
475 	setup_exec_unit_mappings(mdp);
476 	setup_icache_coherency(mdp);
477 
478 	/*
479 	 * If MD is broken then append the passed ISA set,
480 	 * otherwise trust the MD.
481 	 */
482 
483 	if (broken_md_flag)
484 		isa_list = construct_isalist(mdp, cpulist[0],
485 		    cpu_module_isa_set);
486 	else
487 		isa_list = construct_isalist(mdp, cpulist[0], NULL);
488 
489 	get_hwcaps(mdp, cpulist[0]);
490 	get_q_sizes(mdp, cpulist[0]);
491 	get_va_bits(mdp, cpulist[0]);
492 
493 	/*
494 	 * ra_limit is the highest real address in the machine.
495 	 */
496 	ra_limit = get_ra_limit(mdp);
497 
498 	md_free_scan_dag(mdp, &cpulist);
499 
500 	(void) md_fini_handle(mdp);
501 
502 	/*
503 	 * Block stores invalidate all pages of the d$ so pagecopy
504 	 * et. al. do not need virtual translations with virtual
505 	 * coloring taken into consideration.
506 	 */
507 	pp_consistent_coloring = 0;
508 
509 	/*
510 	 * The kpm mapping window.
511 	 * kpm_size:
512 	 *	The size of a single kpm range.
513 	 *	The overall size will be: kpm_size * vac_colors.
514 	 * kpm_vbase:
515 	 *	The virtual start address of the kpm range within the kernel
516 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
517 	 */
518 
519 	/*
520 	 * Make kpm_vbase, kpm_size aligned to kpm_size_shift.
521 	 * To do this find the nearest power of 2 size that the
522 	 * actual ra_limit fits within.
523 	 * If it is an even power of two use that, otherwise use the
524 	 * next power of two larger than ra_limit.
525 	 */
526 
527 	ASSERT(ra_limit != 0);
528 
529 	kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ?
530 	    highbit(ra_limit) : highbit(ra_limit) - 1;
531 
532 	/*
533 	 * No virtual caches on sun4v so size matches size shift
534 	 */
535 	kpm_size = 1ul << kpm_size_shift;
536 
537 	if (va_bits < VA_ADDRESS_SPACE_BITS) {
538 		/*
539 		 * In case of VA hole
540 		 * kpm_base = hole_end + 1TB
541 		 * Starting 1TB beyond where VA hole ends because on Niagara
542 		 * processor software must not use pages within 4GB of the
543 		 * VA hole as instruction pages to avoid problems with
544 		 * prefetching into the VA hole.
545 		 */
546 		kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) +
547 		    (1ull << 40));
548 	} else {		/* Number of VA bits 64 ... no VA hole */
549 		kpm_vbase = (caddr_t)0x8000000000000000ull;	/* 8 EB */
550 	}
551 
552 	/*
553 	 * The traptrace code uses either %tick or %stick for
554 	 * timestamping.  The sun4v require use of %stick.
555 	 */
556 	traptrace_use_stick = 1;
557 }
558 
559 /*
560  * Get the nctxs from MD. If absent panic.
561  */
562 static uint64_t
563 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
564 {
565 	uint64_t ctx_bits;
566 
567 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits",
568 	    &ctx_bits))
569 		ctx_bits = 0;
570 
571 	if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS)
572 		cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits "
573 		    "returned by MD", ctx_bits);
574 
575 	return (ctx_bits);
576 }
577 
578 /*
579  * Get the number of tsbs from MD. If absent the default value is 0.
580  */
581 static uint64_t
582 get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie)
583 {
584 	uint64_t number_tsbs;
585 
586 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs",
587 	    &number_tsbs))
588 		number_tsbs = 0;
589 
590 	return (number_tsbs);
591 }
592 
593 /*
594  * Get the number of shared contexts from MD. If absent the default value is 0.
595  *
596  */
597 static uint64_t
598 get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie)
599 {
600 	uint64_t number_contexts;
601 
602 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts",
603 	    &number_contexts))
604 		number_contexts = 0;
605 
606 	return (number_contexts);
607 }
608 
609 /*
610  * Initalize supported page sizes information.
611  * Set to 0, if the page sizes mask information is absent in MD.
612  */
613 static uint64_t
614 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
615 {
616 	uint64_t mmu_page_size_list;
617 
618 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list",
619 	    &mmu_page_size_list))
620 		mmu_page_size_list = 0;
621 
622 	if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK)
623 		cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned"
624 		    "by MD", mmu_page_size_list);
625 
626 	return (mmu_page_size_list);
627 }
628 
629 /*
630  * This routine gets the isalist information from MD and appends
631  * the CPU module ISA set if required.
632  */
633 static char *
634 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie,
635     char **cpu_module_isa_set)
636 {
637 	extern int at_flags;
638 	char *md_isalist;
639 	int md_isalen;
640 	char *isabuf;
641 	int isalen;
642 	char **isa_set;
643 	char *p, *q;
644 	int cpu_module_isalen = 0, found = 0;
645 
646 	(void) md_get_prop_data(mdp, cpu_node_cookie,
647 	    "isalist", (uint8_t **)&isabuf, &isalen);
648 
649 	/*
650 	 * We support binaries for all the cpus that have shipped so far.
651 	 * The kernel emulates instructions that are not supported by hardware.
652 	 */
653 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
654 
655 	/*
656 	 * Construct the space separated isa_list.
657 	 */
658 	if (cpu_module_isa_set != NULL) {
659 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
660 		    isa_set++) {
661 			cpu_module_isalen += strlen(*isa_set);
662 			cpu_module_isalen++;	/* for space character */
663 		}
664 	}
665 
666 	/*
667 	 * Allocate the buffer of MD isa buffer length + CPU module
668 	 * isa buffer length.
669 	 */
670 	md_isalen = isalen + cpu_module_isalen + 2;
671 	md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0);
672 	if (md_isalist == NULL)
673 		cmn_err(CE_PANIC, "construct_isalist: Allocation failed for "
674 		    "md_isalist");
675 
676 	md_isalist[0] = '\0'; /* create an empty string to start */
677 	for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) {
678 		(void) strlcat(md_isalist, p, md_isalen);
679 		(void) strcat(md_isalist, " ");
680 	}
681 
682 	/*
683 	 * Check if the isa_set is present in isalist returned by MD.
684 	 * If yes, then no need to append it, if no then append it to
685 	 * isalist returned by MD.
686 	 */
687 	if (cpu_module_isa_set != NULL) {
688 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
689 		    isa_set++) {
690 			found = 0;
691 			for (p = isabuf, q = p + isalen; p < q;
692 			    p += strlen(p) + 1) {
693 				if (strcmp(p, *isa_set) == 0) {
694 					found = 1;
695 					break;
696 				}
697 			}
698 			if (!found) {
699 				(void) strlcat(md_isalist, *isa_set, md_isalen);
700 				(void) strcat(md_isalist, " ");
701 			}
702 		}
703 	}
704 
705 	/* Get rid of any trailing white spaces */
706 	md_isalist[strlen(md_isalist) - 1] = '\0';
707 
708 	return (md_isalist);
709 }
710 
711 static void
712 get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie)
713 {
714 	char *hwcapbuf;
715 	int hwcaplen;
716 
717 	if (md_get_prop_data(mdp, cpu_node_cookie,
718 	    "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) {
719 		/* Property not found */
720 		return;
721 	}
722 
723 	cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC,
724 	    "unrecognized token: %s");
725 }
726 
727 
728 /*
729  * Does the opposite of cmn_err(9f) "%b" conversion specification:
730  * Given a list of strings, converts them to a bit-vector.
731  *
732  *  tokens - is a buffer of [NUL-terminated] strings.
733  *  tokenslen - length of tokenbuf in bytes.
734  *  bit_formatter - is a %b format string, such as FMT_AV_SPARC
735  *    from /usr/include/sys/auxv_SPARC.h, of the form:
736  *    <base-char>[<bit-char><token-string>]...
737  *        <base-char> is ignored.
738  *        <bit-char>  is [1-32], as per cmn_err(9f).
739  *  warning - is a printf-style format string containing "%s",
740  *    which is used to print a warning message when an unrecognized
741  *    token is found.  If warning is NULL, no warning is printed.
742  * Returns a bit-vector corresponding to the specified tokens.
743  */
744 
745 static unsigned long
746 names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning)
747 {
748 	char *cur;
749 	size_t  curlen;
750 	unsigned long ul = 0;
751 	char *hit;
752 	char *bs;
753 
754 	bit_formatter++;	/* skip base; not needed for input */
755 	cur = tokens;
756 	while (tokenslen) {
757 		curlen = strlen(cur);
758 		bs = bit_formatter;
759 		/*
760 		 * We need a complicated while loop and the >=32 check,
761 		 * instead of a simple "if (strstr())" so that when the
762 		 * token is "vis", we don't match on "vis2" (for example).
763 		 */
764 		/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
765 		while ((hit = strstr(bs, cur)) &&
766 		    *(hit + curlen) >= 32) {
767 			/*
768 			 * We're still in the middle of a word, i.e., not
769 			 * pointing at a <bit-char>.  So advance ptr
770 			 * to ensure forward progress.
771 			 */
772 			bs = hit + curlen + 1;
773 		}
774 
775 		if (hit != NULL) {
776 			ul |= (1<<(*(hit-1) - 1));
777 		} else {
778 			/* The token wasn't found in bit_formatter */
779 			if (warning != NULL)
780 				cmn_err(CE_WARN, warning, cur);
781 		}
782 		tokenslen -= curlen + 1;
783 		cur += curlen + 1;
784 	}
785 	return (ul);
786 }
787 
788 
789 uint64_t
790 get_ra_limit(md_t *mdp)
791 {
792 	mde_cookie_t *mem_list;
793 	mde_cookie_t *mblock_list;
794 	int i;
795 	int memnodes;
796 	int nmblock;
797 	uint64_t base;
798 	uint64_t size;
799 	uint64_t ra_limit = 0, new_limit = 0;
800 
801 	memnodes = md_alloc_scan_dag(mdp,
802 	    md_root_node(mdp), "memory", "fwd", &mem_list);
803 
804 	ASSERT(memnodes == 1);
805 
806 	nmblock = md_alloc_scan_dag(mdp,
807 	    mem_list[0], "mblock", "fwd", &mblock_list);
808 	if (nmblock < 1)
809 		cmn_err(CE_PANIC, "cannot find mblock nodes in MD");
810 
811 	for (i = 0; i < nmblock; i++) {
812 		if (md_get_prop_val(mdp, mblock_list[i], "base", &base))
813 			cmn_err(CE_PANIC, "base property missing from MD"
814 			    " mblock node");
815 		if (md_get_prop_val(mdp, mblock_list[i], "size", &size))
816 			cmn_err(CE_PANIC, "size property missing from MD"
817 			    " mblock node");
818 
819 		ASSERT(size != 0);
820 
821 		new_limit = base + size;
822 
823 		if (base > new_limit)
824 			cmn_err(CE_PANIC, "mblock in MD wrapped around");
825 
826 		if (new_limit > ra_limit)
827 			ra_limit = new_limit;
828 	}
829 
830 	ASSERT(ra_limit != 0);
831 
832 	if (ra_limit > MAX_REAL_ADDRESS) {
833 		cmn_err(CE_WARN, "Highest real address in MD too large"
834 		    " clipping to %llx\n", MAX_REAL_ADDRESS);
835 		ra_limit = MAX_REAL_ADDRESS;
836 	}
837 
838 	md_free_scan_dag(mdp, &mblock_list);
839 
840 	md_free_scan_dag(mdp, &mem_list);
841 
842 	return (ra_limit);
843 }
844 
845 /*
846  * This routine sets the globals for CPU and DEV mondo queue entries and
847  * resumable and non-resumable error queue entries.
848  *
849  * First, look up the number of bits available to pass an entry number.
850  * This can vary by platform and may result in allocating an unreasonably
851  * (or impossibly) large amount of memory for the corresponding table,
852  * so we clamp it by 'max_entries'.  Finally, since the q size is used when
853  * calling contig_mem_alloc(), which expects a power of 2, clamp the q size
854  * down to a power of 2.  If the prop is missing, use 'default_entries'.
855  */
856 static uint64_t
857 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie,
858     char *qnamep, uint64_t default_entries, uint64_t max_entries)
859 {
860 	uint64_t entries;
861 
862 	if (default_entries > max_entries)
863 		cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > "
864 		    "max %ld for %s\n", default_entries, max_entries, qnamep);
865 
866 	if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) {
867 		if (!broken_md_flag)
868 			cmn_err(CE_PANIC, "Missing %s property in MD cpu node",
869 			    qnamep);
870 		entries = default_entries;
871 	} else {
872 		entries = 1 << entries;
873 	}
874 
875 	entries = MIN(entries, max_entries);
876 	/* If not a power of 2, truncate to a power of 2. */
877 	if ((entries & (entries - 1)) != 0) {
878 		entries = 1 << (highbit(entries) - 1);
879 	}
880 
881 	return (entries);
882 }
883 
884 /* Scaling constant used to compute size of cpu mondo queue */
885 #define	CPU_MONDO_Q_MULTIPLIER	8
886 
887 static void
888 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
889 {
890 	uint64_t max_qsize;
891 	mde_cookie_t *platlist;
892 	int nrnode;
893 
894 	/*
895 	 * Compute the maximum number of entries for the cpu mondo queue.
896 	 * Use the appropriate property in the platform node, if it is
897 	 * available.  Else, base it on NCPU.
898 	 */
899 	nrnode = md_alloc_scan_dag(mdp,
900 	    md_root_node(mdp), "platform", "fwd", &platlist);
901 
902 	ASSERT(nrnode == 1);
903 
904 	ncpu_guest_max = NCPU;
905 	(void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max);
906 	max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER;
907 
908 	md_free_scan_dag(mdp, &platlist);
909 
910 	cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie,
911 	    "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize);
912 
913 	dev_q_entries = get_single_q_size(mdp, cpu_node_cookie,
914 	    "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM);
915 
916 	cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie,
917 	    "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES);
918 
919 	cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie,
920 	    "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES);
921 }
922 
923 
924 static void
925 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
926 {
927 	uint64_t value = VA_ADDRESS_SPACE_BITS;
928 
929 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value))
930 		cmn_err(CE_PANIC, "mmu-#va-bits property  not found in MD");
931 
932 
933 	if (value == 0 || value > VA_ADDRESS_SPACE_BITS)
934 		cmn_err(CE_PANIC, "Incorrect number of va bits in MD");
935 
936 	/* Do not expect number of VA bits to be more than 32-bit quantity */
937 
938 	va_bits = (int)value;
939 
940 	/*
941 	 * Correct the value for VA bits on UltraSPARC-T1 based systems
942 	 * in case of broken MD.
943 	 */
944 	if (broken_md_flag)
945 		va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS;
946 }
947 
948 int
949 l2_cache_node_count(void)
950 {
951 	return (n_l2_caches);
952 }
953 
954 /*
955  * count the number of l2 caches.
956  */
957 int
958 get_l2_cache_node_count(md_t *mdp)
959 {
960 	int i;
961 	mde_cookie_t *cachenodes;
962 	uint64_t level;
963 	int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp),
964 	    "cache", "fwd", &cachenodes);
965 	int l2_caches = 0;
966 
967 	for (i = 0; i < n_cachenodes; i++) {
968 		if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) {
969 			level = 0;
970 		}
971 		if (level == 2) {
972 			l2_caches++;
973 		}
974 	}
975 	md_free_scan_dag(mdp, &cachenodes);
976 	return (l2_caches);
977 }
978 
979 /*
980  * This routine returns the L2 cache information such as -- associativity,
981  * size and linesize.
982  */
983 static int
984 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie,
985 	    uint64_t *associativity, uint64_t *size, uint64_t *linesize)
986 {
987 	mde_cookie_t *cachelist;
988 	int ncaches, i;
989 	uint64_t cache_level = 0;
990 
991 	ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache",
992 	    "fwd", &cachelist);
993 	/*
994 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
995 	 */
996 	if (ncaches < 1) {
997 		return (0);
998 	}
999 
1000 	for (i = 0; i < ncaches; i++) {
1001 		uint64_t local_assoc;
1002 		uint64_t local_size;
1003 		uint64_t local_lsize;
1004 
1005 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
1006 			continue;
1007 
1008 		if (cache_level != 2) continue;
1009 
1010 		/* If properties are missing from this cache ignore it */
1011 
1012 		if ((md_get_prop_val(mdp, cachelist[i],
1013 		    "associativity", &local_assoc))) {
1014 			continue;
1015 		}
1016 
1017 		if ((md_get_prop_val(mdp, cachelist[i],
1018 		    "size", &local_size))) {
1019 			continue;
1020 		}
1021 
1022 		if ((md_get_prop_val(mdp, cachelist[i],
1023 		    "line-size", &local_lsize))) {
1024 			continue;
1025 		}
1026 
1027 		*associativity = local_assoc;
1028 		*size = local_size;
1029 		*linesize = local_lsize;
1030 		break;
1031 	}
1032 
1033 	md_free_scan_dag(mdp, &cachelist);
1034 
1035 	return ((cache_level == 2) ? 1 : 0);
1036 }
1037 
1038 
1039 /*
1040  * Set the broken_md_flag to 1 if the MD doesn't have
1041  * the domaining-enabled property in the platform node and the
1042  * platform uses the UltraSPARC-T1 cpu. This flag is used to
1043  * workaround some of the incorrect MD properties.
1044  */
1045 static void
1046 init_md_broken(md_t *mdp, mde_cookie_t *cpulist)
1047 {
1048 	int nrnode;
1049 	mde_cookie_t *platlist, rootnode;
1050 	uint64_t val = 0;
1051 	char *namebuf;
1052 	int namelen;
1053 
1054 	rootnode = md_root_node(mdp);
1055 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
1056 	ASSERT(cpulist);
1057 
1058 	nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd",
1059 	    &platlist);
1060 
1061 	if (nrnode < 1)
1062 		cmn_err(CE_PANIC, "init_md_broken: platform node missing");
1063 
1064 	if (md_get_prop_data(mdp, cpulist[0],
1065 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
1066 		cmn_err(CE_PANIC, "init_md_broken: "
1067 		    "Cannot read 'compatible' property of 'cpu' node");
1068 	}
1069 
1070 	if (md_get_prop_val(mdp, platlist[0],
1071 	    "domaining-enabled", &val) == -1 &&
1072 	    strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0)
1073 		broken_md_flag = 1;
1074 
1075 	md_free_scan_dag(mdp, &platlist);
1076 }
1077 
1078 /*
1079  * This routine gets the MD properties associated with the TLB search order API
1080  * and compares these against the expected values for a processor which supports
1081  * this API. The return value is used to determine whether use the API.
1082  */
1083 static int
1084 check_mmu_pgsz_search(md_t *mdp, mde_cookie_t cpu_node_cookie)
1085 {
1086 
1087 	uint64_t mmu_search_nshared_contexts;
1088 	uint64_t mmu_max_search_order;
1089 	uint64_t mmu_non_priv_search_unified;
1090 	uint64_t mmu_search_page_size_list;
1091 
1092 	if (md_get_prop_val(mdp, cpu_node_cookie,
1093 	    "mmu-search-#shared-contexts", &mmu_search_nshared_contexts))
1094 		mmu_search_nshared_contexts = 0;
1095 
1096 	if (mmu_search_nshared_contexts == 0 ||
1097 	    mmu_search_nshared_contexts != NSEARCH_SHCONTEXTS)
1098 		return (0);
1099 
1100 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-search-order",
1101 	    &mmu_max_search_order))
1102 		mmu_max_search_order = 0;
1103 
1104 	if (mmu_max_search_order == 0 || mmu_max_search_order !=
1105 	    MAX_PGSZ_SEARCH_ORDER)
1106 		return (0);
1107 
1108 	if (md_get_prop_val(mdp, cpu_node_cookie,
1109 	    "mmu-non-priv-search-unified", &mmu_non_priv_search_unified))
1110 		mmu_non_priv_search_unified = -1;
1111 
1112 	if (mmu_non_priv_search_unified != 1) {
1113 		return (0);
1114 	}
1115 
1116 	if (md_get_prop_val(mdp, cpu_node_cookie,
1117 	    "mmu-search-page-size-list", &mmu_search_page_size_list)) {
1118 		mmu_search_page_size_list = 0;
1119 		return (0);
1120 	}
1121 
1122 	return (1);
1123 }
1124