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