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