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