xref: /titanic_50/usr/src/uts/sun4v/os/fillsysinfo.c (revision df4cb6e0bcfc660e38e1e96ccd7b794c0466228a)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/errno.h>
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/cpu.h>
32 #include <sys/cpuvar.h>
33 #include <sys/clock.h>
34 #include <sys/promif.h>
35 #include <sys/promimpl.h>
36 #include <sys/systm.h>
37 #include <sys/machsystm.h>
38 #include <sys/debug.h>
39 #include <sys/sunddi.h>
40 #include <sys/modctl.h>
41 #include <sys/cpu_module.h>
42 #include <sys/kobj.h>
43 #include <sys/cmp.h>
44 #include <sys/async.h>
45 #include <vm/page.h>
46 #include <vm/hat_sfmmu.h>
47 #include <sys/sysmacros.h>
48 #include <sys/mach_descrip.h>
49 #include <sys/mdesc.h>
50 #include <sys/archsystm.h>
51 #include <sys/error.h>
52 #include <sys/mmu.h>
53 #include <sys/bitmap.h>
54 
55 int ncpunode;
56 struct cpu_node cpunodes[NCPU];
57 
58 uint64_t cpu_q_entries;
59 uint64_t dev_q_entries;
60 uint64_t cpu_rq_entries;
61 uint64_t cpu_nrq_entries;
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_cpu_pagesizes(md_t *, mde_cookie_t);
67 static char *construct_isalist(md_t *, mde_cookie_t, char **);
68 static void set_at_flags(char *, int, char **);
69 static void init_md_broken(md_t *);
70 static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *,
71     uint64_t *);
72 static id_t get_exec_unit_mapping(md_t *, mde_cookie_t, mde_cookie_t *);
73 static int find_exec_unit_id(mde_cookie_t, mde_cookie_t *);
74 static void get_q_sizes(md_t *, mde_cookie_t);
75 static void get_va_bits(md_t *, mde_cookie_t);
76 static size_t get_ra_limit(md_t *);
77 
78 uint64_t	system_clock_freq;
79 int		niobus = 0;
80 uint_t		niommu_tsbs = 0;
81 
82 /* prevent compilation with VAC defined */
83 #ifdef VAC
84 #error "The sun4v architecture does not support VAC"
85 #endif
86 
87 #define	S_VAC_SIZE	MMU_PAGESIZE
88 #define	S_VAC_SHIFT	MMU_PAGESHIFT
89 
90 int		vac_size = S_VAC_SIZE;
91 uint_t		vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1);
92 int		vac_shift = S_VAC_SHIFT;
93 uintptr_t	shm_alignment = S_VAC_SIZE;
94 
95 void
96 map_wellknown_devices()
97 {
98 }
99 
100 /*
101  * For backward compatibility we need to verify that we can handle
102  * running on platforms which shipped with missing MD properties.
103  */
104 #define	ONTARIO_PLATNAME1	"SUNW,Sun-Fire-T200"
105 #define	ONTARIO_PLATNAME2	"SUNW,Sun-Fire-T2000"
106 #define	ONTARIO_PLATNAME3	"SUNW,SPARC-Enterprise-T2000"
107 #define	ERIE_PLATNAME1		"SUNW,Sun-Fire-T100"
108 #define	ERIE_PLATNAME2		"SUNW,Sun-Fire-T1000"
109 #define	ERIE_PLATNAME3		"SUNW,SPARC-Enterprise-T1000"
110 
111 void
112 fill_cpu(md_t *mdp, mde_cookie_t cpuc)
113 {
114 	struct cpu_node *cpunode;
115 	uint64_t cpuid;
116 	uint64_t clk_freq;
117 	char *namebuf;
118 	char *namebufp;
119 	int namelen;
120 	uint64_t associativity = 0, linesize = 0, size = 0;
121 	int status;
122 
123 	if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) {
124 		return;
125 	}
126 
127 	if (cpuid >= NCPU) {
128 		cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - "
129 		    "cpu excluded from configuration", cpuid);
130 
131 		mutex_enter(&cpu_lock);
132 
133 		/*
134 		 * Since the CPU cannot be used, make sure it
135 		 * is in a safe place. If the firmware does not
136 		 * support CPU stop, this is known to be true.
137 		 * If it fails to stop for any other reason, the
138 		 * system is in an inconsistent state and cannot
139 		 * be allowed to continue.
140 		 */
141 		status = stopcpu_bycpuid(cpuid);
142 
143 		if ((status != 0) && (status != ENOTSUP)) {
144 			cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)",
145 			    cpuid, status);
146 		}
147 
148 		mutex_exit(&cpu_lock);
149 		return;
150 	}
151 
152 	cpunode = &cpunodes[cpuid];
153 	cpunode->cpuid = (int)cpuid;
154 	cpunode->device_id = cpuid;
155 
156 	if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI))
157 		(void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI);
158 
159 	if (md_get_prop_data(mdp, cpuc,
160 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
161 		cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible "
162 		    "property");
163 	}
164 	namebufp = namebuf;
165 	if (strncmp(namebufp, "SUNW,", 5) == 0)
166 		namebufp += 5;
167 	if (strlen(namebufp) > sizeof (cpunode->name))
168 		cmn_err(CE_PANIC, "Compatible property too big to "
169 		    "fit into the cpunode name buffer");
170 	(void) strcpy(cpunode->name, namebufp);
171 
172 	if (md_get_prop_val(mdp, cpuc,
173 	    "clock-frequency", &clk_freq)) {
174 			clk_freq = 0;
175 	}
176 	cpunode->clock_freq = clk_freq;
177 
178 	ASSERT(cpunode->clock_freq != 0);
179 	/*
180 	 * Compute scaling factor based on rate of %tick. This is used
181 	 * to convert from ticks derived from %tick to nanoseconds. See
182 	 * comment in sun4u/sys/clock.h for details.
183 	 */
184 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
185 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
186 
187 	/*
188 	 * The nodeid is not used in sun4v at all. Setting it
189 	 * to positive value to make starting of slave CPUs
190 	 * code happy.
191 	 */
192 	cpunode->nodeid = cpuid + 1;
193 
194 	/*
195 	 * Obtain the L2 cache information from MD.
196 	 * If "Cache" node exists, then set L2 cache properties
197 	 * as read from MD.
198 	 * If node does not exists, then set the L2 cache properties
199 	 * in individual CPU module.
200 	 */
201 	if ((!get_l2_cache_info(mdp, cpuc,
202 	    &associativity, &size, &linesize)) ||
203 	    associativity == 0 || size == 0 || linesize == 0) {
204 		cpu_fiximp(cpunode);
205 	} else {
206 		/*
207 		 * Do not expect L2 cache properties to be bigger
208 		 * than 32-bit quantity.
209 		 */
210 		cpunode->ecache_associativity = (int)associativity;
211 		cpunode->ecache_size = (int)size;
212 		cpunode->ecache_linesize = (int)linesize;
213 	}
214 
215 	cpunode->ecache_setsize =
216 	    cpunode->ecache_size / cpunode->ecache_associativity;
217 
218 		/*
219 		 * Start off by assigning the cpu id as the default
220 		 * mapping index.
221 		 */
222 
223 	cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND;
224 
225 	if (ecache_setsize == 0)
226 		ecache_setsize = cpunode->ecache_setsize;
227 	if (ecache_alignsize == 0)
228 		ecache_alignsize = cpunode->ecache_linesize;
229 
230 	ncpunode++;
231 }
232 
233 void
234 empty_cpu(int cpuid)
235 {
236 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
237 	ncpunode--;
238 }
239 
240 void
241 setup_exec_unit_mappings(md_t *mdp)
242 {
243 	uint64_t num, num_eunits;
244 	mde_cookie_t cpus_node;
245 	mde_cookie_t *node, *eunit;
246 	int idx, i, j;
247 	processorid_t cpuid;
248 	char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit";
249 
250 	/*
251 	 * Find the cpu integer exec units - and
252 	 * setup the mappings appropriately.
253 	 */
254 	num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node);
255 	if (num < 1)
256 		cmn_err(CE_PANIC, "No cpus node in machine desccription");
257 	if (num > 1)
258 		cmn_err(CE_PANIC, "More than 1 cpus node in machine"
259 		    " description");
260 
261 	cpus_node = node[0];
262 	md_free_scan_dag(mdp, &node);
263 
264 	num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name,
265 	    "fwd", &eunit);
266 	if (num_eunits > 0) {
267 		char *match_type = broken_md_flag ? "int" : "integer";
268 
269 		/* Spin through and find all the integer exec units */
270 		for (i = 0; i < num_eunits; i++) {
271 			char *p;
272 			char *val;
273 			int vallen;
274 			uint64_t lcpuid;
275 
276 				/* ignore nodes with no type */
277 			if (md_get_prop_data(mdp, eunit[i], "type",
278 				(uint8_t **)&val, &vallen)) continue;
279 
280 			for (p = val; *p != '\0'; p += strlen(p) + 1) {
281 				if (strcmp(p, match_type) == 0)
282 					goto found;
283 			}
284 
285 			continue;
286 found:
287 			idx = NCPU + i;
288 			/*
289 			 * find the cpus attached to this EU and
290 			 * update their mapping indices
291 			 */
292 			num = md_alloc_scan_dag(mdp, eunit[i], "cpu",
293 			    "back", &node);
294 
295 			if (num < 1)
296 				cmn_err(CE_PANIC, "exec-unit node in MD"
297 				    " not attached to a cpu node");
298 
299 			for (j = 0; j < num; j++) {
300 				if (md_get_prop_val(mdp, node[j], "id",
301 				    &lcpuid))
302 					continue;
303 				if (lcpuid >= NCPU)
304 					continue;
305 				cpuid = (processorid_t)lcpuid;
306 				cpunodes[cpuid].exec_unit_mapping = idx;
307 			}
308 			md_free_scan_dag(mdp, &node);
309 		}
310 
311 
312 		md_free_scan_dag(mdp, &eunit);
313 	}
314 }
315 
316 /*
317  * All the common setup of sun4v CPU modules is done by this routine.
318  */
319 void
320 cpu_setup_common(char **cpu_module_isa_set)
321 {
322 	extern int disable_delay_tlb_flush, delay_tlb_flush;
323 	extern int mmu_exported_pagesize_mask;
324 	int nocpus, i;
325 	size_t ra_limit;
326 	mde_cookie_t *cpulist;
327 	md_t *mdp;
328 
329 	if ((mdp = md_get_handle()) == NULL)
330 		cmn_err(CE_PANIC, "Unable to initialize machine description");
331 
332 	init_md_broken(mdp);
333 
334 	nocpus = md_alloc_scan_dag(mdp,
335 	    md_root_node(mdp), "cpu", "fwd", &cpulist);
336 	if (nocpus < 1) {
337 		cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation "
338 		    "failed or incorrect number of CPUs in MD");
339 	}
340 
341 	if (use_page_coloring) {
342 		do_pg_coloring = 1;
343 		if (use_virtual_coloring) {
344 			/*
345 			 * XXX Sun4v cpus don't have virtual caches
346 			 */
347 			do_virtual_coloring = 1;
348 		}
349 	}
350 
351 	/*
352 	 * Get the valid mmu page sizes mask, Q sizes and isalist/r
353 	 * from the MD for the first available CPU in cpulist.
354 	 *
355 	 * Do not expect the MMU page sizes mask to be more than 32-bit.
356 	 */
357 	mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]);
358 
359 	for (i = 0; i < nocpus; i++)
360 		fill_cpu(mdp, cpulist[i]);
361 
362 	setup_exec_unit_mappings(mdp);
363 
364 	/*
365 	 * If MD is broken then append the passed ISA set,
366 	 * otherwise trust the MD.
367 	 */
368 
369 	if (broken_md_flag)
370 		isa_list = construct_isalist(mdp, cpulist[0],
371 		    cpu_module_isa_set);
372 	else
373 		isa_list = construct_isalist(mdp, cpulist[0], NULL);
374 
375 	get_q_sizes(mdp, cpulist[0]);
376 
377 	get_va_bits(mdp, cpulist[0]);
378 
379 	/*
380 	 * ra_limit is the highest real address in the machine.
381 	 */
382 	ra_limit = get_ra_limit(mdp);
383 
384 	md_free_scan_dag(mdp, &cpulist);
385 
386 	(void) md_fini_handle(mdp);
387 
388 	/*
389 	 * Block stores invalidate all pages of the d$ so pagecopy
390 	 * et. al. do not need virtual translations with virtual
391 	 * coloring taken into consideration.
392 	 */
393 	pp_consistent_coloring = 0;
394 
395 	/*
396 	 * The kpm mapping window.
397 	 * kpm_size:
398 	 *	The size of a single kpm range.
399 	 *	The overall size will be: kpm_size * vac_colors.
400 	 * kpm_vbase:
401 	 *	The virtual start address of the kpm range within the kernel
402 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
403 	 */
404 
405 	/*
406 	 * Make kpm_vbase, kpm_size aligned to kpm_size_shift.
407 	 * To do this find the nearest power of 2 size that the
408 	 * actual ra_limit fits within.
409 	 * If it is an even power of two use that, otherwise use the
410 	 * next power of two larger than ra_limit.
411 	 */
412 
413 	ASSERT(ra_limit != 0);
414 
415 	kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ?
416 		highbit(ra_limit) : highbit(ra_limit) - 1;
417 
418 	/*
419 	 * No virtual caches on sun4v so size matches size shift
420 	 */
421 	kpm_size = 1ul << kpm_size_shift;
422 
423 	if (va_bits < VA_ADDRESS_SPACE_BITS) {
424 		/*
425 		 * In case of VA hole
426 		 * kpm_base = hole_end + 1TB
427 		 * Starting 1TB beyond where VA hole ends because on Niagara
428 		 * processor software must not use pages within 4GB of the
429 		 * VA hole as instruction pages to avoid problems with
430 		 * prefetching into the VA hole.
431 		 */
432 		kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) +
433 		    (1ull << 40));
434 	} else {		/* Number of VA bits 64 ... no VA hole */
435 		kpm_vbase = (caddr_t)0x8000000000000000ull;	/* 8 EB */
436 	}
437 
438 	/*
439 	 * The traptrace code uses either %tick or %stick for
440 	 * timestamping.  The sun4v require use of %stick.
441 	 */
442 	traptrace_use_stick = 1;
443 
444 	/*
445 	 * sun4v provides demap_all
446 	 */
447 	if (!disable_delay_tlb_flush)
448 		delay_tlb_flush = 1;
449 }
450 
451 /*
452  * Get the nctxs from MD. If absent panic.
453  */
454 static uint64_t
455 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
456 {
457 	uint64_t ctx_bits;
458 
459 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits",
460 	    &ctx_bits))
461 		ctx_bits = 0;
462 
463 	if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS)
464 		cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits "
465 		    "returned by MD", ctx_bits);
466 
467 	return (ctx_bits);
468 }
469 
470 /*
471  * Initalize supported page sizes information.
472  * Set to 0, if the page sizes mask information is absent in MD.
473  */
474 static uint64_t
475 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
476 {
477 	uint64_t mmu_page_size_list;
478 
479 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list",
480 	    &mmu_page_size_list))
481 		mmu_page_size_list = 0;
482 
483 	if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK)
484 		cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned"
485 		    "by MD", mmu_page_size_list);
486 
487 	return (mmu_page_size_list);
488 }
489 
490 /*
491  * This routine gets the isalist information from MD and appends
492  * the CPU module ISA set if required.
493  */
494 static char *
495 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie,
496     char **cpu_module_isa_set)
497 {
498 	extern int at_flags;
499 	char *md_isalist;
500 	int md_isalen;
501 	char *isabuf;
502 	int isalen;
503 	char **isa_set;
504 	char *p, *q;
505 	int cpu_module_isalen = 0, found = 0;
506 
507 	(void) md_get_prop_data(mdp, cpu_node_cookie,
508 	    "isalist", (uint8_t **)&isabuf, &isalen);
509 
510 	/*
511 	 * We support binaries for all the cpus that have shipped so far.
512 	 * The kernel emulates instructions that are not supported by hardware.
513 	 */
514 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
515 
516 	/*
517 	 * Construct the space separated isa_list.
518 	 */
519 	if (cpu_module_isa_set != NULL) {
520 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
521 		    isa_set++) {
522 			cpu_module_isalen += strlen(*isa_set);
523 			cpu_module_isalen++;	/* for space character */
524 		}
525 	}
526 
527 	/*
528 	 * Allocate the buffer of MD isa buffer length + CPU module
529 	 * isa buffer length.
530 	 */
531 	md_isalen = isalen + cpu_module_isalen + 2;
532 	md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0);
533 	if (md_isalist == NULL)
534 		cmn_err(CE_PANIC, "construct_isalist: Allocation failed for "
535 		    "md_isalist");
536 
537 	md_isalist[0] = '\0'; /* create an empty string to start */
538 	for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) {
539 		(void) strlcat(md_isalist, p, md_isalen);
540 		(void) strcat(md_isalist, " ");
541 	}
542 
543 	/*
544 	 * Check if the isa_set is present in isalist returned by MD.
545 	 * If yes, then no need to append it, if no then append it to
546 	 * isalist returned by MD.
547 	 */
548 	if (cpu_module_isa_set != NULL) {
549 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
550 		    isa_set++) {
551 			found = 0;
552 			for (p = isabuf, q = p + isalen; p < q;
553 			    p += strlen(p) + 1) {
554 				if (strcmp(p, *isa_set) == 0) {
555 					found = 1;
556 					break;
557 				}
558 			}
559 			if (!found) {
560 				(void) strlcat(md_isalist, *isa_set, md_isalen);
561 				(void) strcat(md_isalist, " ");
562 			}
563 		}
564 	}
565 
566 	/* Get rid of any trailing white spaces */
567 	md_isalist[strlen(md_isalist) - 1] = '\0';
568 
569 	return (md_isalist);
570 }
571 
572 uint64_t
573 get_ra_limit(md_t *mdp)
574 {
575 	mde_cookie_t *mem_list;
576 	mde_cookie_t *mblock_list;
577 	int i;
578 	int memnodes;
579 	int nmblock;
580 	uint64_t base;
581 	uint64_t size;
582 	uint64_t ra_limit = 0, new_limit = 0;
583 
584 	memnodes = md_alloc_scan_dag(mdp,
585 	    md_root_node(mdp), "memory", "fwd", &mem_list);
586 
587 	ASSERT(memnodes == 1);
588 
589 	nmblock = md_alloc_scan_dag(mdp,
590 	    mem_list[0], "mblock", "fwd", &mblock_list);
591 	if (nmblock < 1)
592 		cmn_err(CE_PANIC, "cannot find mblock nodes in MD");
593 
594 	for (i = 0; i < nmblock; i++) {
595 		if (md_get_prop_val(mdp, mblock_list[i], "base", &base))
596 			cmn_err(CE_PANIC, "base property missing from MD"
597 			    " mblock node");
598 		if (md_get_prop_val(mdp, mblock_list[i], "size", &size))
599 			cmn_err(CE_PANIC, "size property missing from MD"
600 			    " mblock node");
601 
602 		ASSERT(size != 0);
603 
604 		new_limit = base + size;
605 
606 		if (base > new_limit)
607 			cmn_err(CE_PANIC, "mblock in MD wrapped around");
608 
609 		if (new_limit > ra_limit)
610 		    ra_limit = new_limit;
611 	}
612 
613 	ASSERT(ra_limit != 0);
614 
615 	if (ra_limit > MAX_REAL_ADDRESS) {
616 		cmn_err(CE_WARN, "Highest real address in MD too large"
617 		    " clipping to %llx\n", MAX_REAL_ADDRESS);
618 		ra_limit = MAX_REAL_ADDRESS;
619 	}
620 
621 	md_free_scan_dag(mdp, &mblock_list);
622 
623 	md_free_scan_dag(mdp, &mem_list);
624 
625 	return (ra_limit);
626 }
627 
628 /*
629  * This routine sets the globals for CPU and DEV mondo queue entries and
630  * resumable and non-resumable error queue entries.
631  */
632 static uint64_t
633 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie,
634     char *qnamep, uint64_t default_entries)
635 {
636 	uint64_t entries;
637 
638 	if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) {
639 		if (!broken_md_flag)
640 			cmn_err(CE_PANIC, "Missing %s property in MD cpu node",
641 				qnamep);
642 		entries = default_entries;
643 	} else {
644 		entries = 1 << entries;
645 	}
646 	return (entries);
647 }
648 
649 
650 static void
651 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
652 {
653 	cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie,
654 	    "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES);
655 
656 	dev_q_entries = get_single_q_size(mdp, cpu_node_cookie,
657 	    "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES);
658 
659 	cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie,
660 	    "q-resumable-#bits", CPU_RQ_ENTRIES);
661 
662 	cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie,
663 		"q-nonresumable-#bits", CPU_NRQ_ENTRIES);
664 }
665 
666 
667 static void
668 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
669 {
670 	uint64_t value = VA_ADDRESS_SPACE_BITS;
671 
672 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value))
673 		cmn_err(CE_PANIC, "mmu-#va-bits property  not found in MD");
674 
675 
676 	if (value == 0 || value > VA_ADDRESS_SPACE_BITS)
677 		cmn_err(CE_PANIC, "Incorrect number of va bits in MD");
678 
679 	/* Do not expect number of VA bits to be more than 32-bit quantity */
680 
681 	va_bits = (int)value;
682 
683 	/*
684 	 * Correct the value for VA bits on UltraSPARC-T1 based systems
685 	 * in case of broken MD.
686 	 */
687 	if (broken_md_flag)
688 		va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS;
689 }
690 
691 /*
692  * This routine returns the L2 cache information such as -- associativity,
693  * size and linesize.
694  */
695 static int
696 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie,
697 	    uint64_t *associativity, uint64_t *size, uint64_t *linesize)
698 {
699 	mde_cookie_t *cachelist;
700 	int ncaches, i;
701 	uint64_t max_level;
702 
703 	ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache",
704 	    "fwd", &cachelist);
705 	/*
706 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
707 	 */
708 	if (ncaches < 1) {
709 		return (0);
710 	}
711 
712 	max_level = 0;
713 	for (i = 0; i < ncaches; i++) {
714 		uint64_t cache_level;
715 		uint64_t local_assoc;
716 		uint64_t local_size;
717 		uint64_t local_lsize;
718 
719 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
720 			continue;
721 
722 		if (cache_level <= max_level) continue;
723 
724 		/* If properties are missing from this cache ignore it */
725 
726 		if ((md_get_prop_val(mdp, cachelist[i],
727 		    "associativity", &local_assoc))) {
728 			continue;
729 		}
730 
731 		if ((md_get_prop_val(mdp, cachelist[i],
732 		    "size", &local_size))) {
733 			continue;
734 		}
735 
736 		if ((md_get_prop_val(mdp, cachelist[i],
737 		    "line-size", &local_lsize))) {
738 			continue;
739 		}
740 
741 		max_level = cache_level;
742 		*associativity = local_assoc;
743 		*size = local_size;
744 		*linesize = local_lsize;
745 	}
746 
747 	md_free_scan_dag(mdp, &cachelist);
748 
749 	return ((max_level > 0) ? 1 : 0);
750 }
751 
752 /*
753  * The broken_md_flag is set to 1, if the MD doesn't have
754  * the domaining-enabled property in the platform node and the platforms
755  * are Ontario and Erie. This flag is used to workaround some of the
756  * incorrect MD properties.
757  */
758 static void
759 init_md_broken(md_t *mdp)
760 {
761 	int nrnode;
762 	mde_cookie_t *platlist, rootnode;
763 	char *vbuf;
764 	uint64_t val = 0;
765 
766 	rootnode = md_root_node(mdp);
767 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
768 
769 	nrnode = md_alloc_scan_dag(mdp, md_root_node(mdp), "platform", "fwd",
770 	    &platlist);
771 
772 	ASSERT(nrnode == 1);
773 
774 	if (md_get_prop_str(mdp, platlist[0], "name", &vbuf) != 0)
775 		panic("platform name not found in machine description");
776 
777 	/*
778 	 * If domaining-enable prop doesn't exist and the platform name is
779 	 * Ontario or Erie the md is broken.
780 	 */
781 
782 	if (md_get_prop_val(mdp, platlist[0], "domaining-enabled", &val) != 0 &&
783 	((strcmp(vbuf, ONTARIO_PLATNAME1) == 0) ||
784 	(strcmp(vbuf, ONTARIO_PLATNAME2) == 0) ||
785 	(strcmp(vbuf, ONTARIO_PLATNAME3) == 0) ||
786 	(strcmp(vbuf, ERIE_PLATNAME1) == 0) ||
787 	(strcmp(vbuf, ERIE_PLATNAME2) == 0) ||
788 	(strcmp(vbuf, ERIE_PLATNAME3) == 0)))
789 		broken_md_flag = 1;
790 
791 	md_free_scan_dag(mdp, &platlist);
792 }
793