xref: /onnv-gate/usr/src/uts/sun4v/os/fillsysinfo.c (revision 12701:8c9362e17ee4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212116SVikram.Hegde@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/errno.h>
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/cpu.h>
290Sstevel@tonic-gate #include <sys/cpuvar.h>
300Sstevel@tonic-gate #include <sys/clock.h>
310Sstevel@tonic-gate #include <sys/promif.h>
320Sstevel@tonic-gate #include <sys/promimpl.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/machsystm.h>
350Sstevel@tonic-gate #include <sys/debug.h>
360Sstevel@tonic-gate #include <sys/sunddi.h>
370Sstevel@tonic-gate #include <sys/modctl.h>
380Sstevel@tonic-gate #include <sys/cpu_module.h>
390Sstevel@tonic-gate #include <sys/kobj.h>
400Sstevel@tonic-gate #include <sys/cmp.h>
410Sstevel@tonic-gate #include <sys/async.h>
420Sstevel@tonic-gate #include <vm/page.h>
431991Sheppo #include <vm/hat_sfmmu.h>
441991Sheppo #include <sys/sysmacros.h>
451991Sheppo #include <sys/mach_descrip.h>
461991Sheppo #include <sys/mdesc.h>
471991Sheppo #include <sys/archsystm.h>
481991Sheppo #include <sys/error.h>
491991Sheppo #include <sys/mmu.h>
501991Sheppo #include <sys/bitmap.h>
512531Snarayan #include <sys/intreg.h>
5212116SVikram.Hegde@Sun.COM #include <sys/instance.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate struct cpu_node cpunodes[NCPU];
550Sstevel@tonic-gate 
561991Sheppo uint64_t cpu_q_entries;
571991Sheppo uint64_t dev_q_entries;
581991Sheppo uint64_t cpu_rq_entries;
591991Sheppo uint64_t cpu_nrq_entries;
604204Sha137994 uint64_t ncpu_guest_max;
611991Sheppo 
621991Sheppo void fill_cpu(md_t *, mde_cookie_t);
631991Sheppo 
641991Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t);
654528Spaulsan static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t);
664528Spaulsan static uint64_t	get_mmu_shcontexts(md_t *, mde_cookie_t);
671991Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t);
681991Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **);
692531Snarayan static void init_md_broken(md_t *, mde_cookie_t *);
701991Sheppo static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *,
711991Sheppo     uint64_t *);
727718SJason.Beloro@Sun.COM static void get_hwcaps(md_t *, mde_cookie_t);
739351SPrashanth.Sreenivasa@Sun.COM static void get_weakest_mem_model(md_t *, mde_cookie_t);
741991Sheppo static void get_q_sizes(md_t *, mde_cookie_t);
751991Sheppo static void get_va_bits(md_t *, mde_cookie_t);
7610106SJason.Beloro@Sun.COM static size_t get_ra_limit(md_t *, mde_cookie_t);
775834Spt157919 static int get_l2_cache_node_count(md_t *);
787718SJason.Beloro@Sun.COM static unsigned long names2bits(char *tokens, size_t tokenslen,
797718SJason.Beloro@Sun.COM     char *bit_formatter, char *warning);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate uint64_t	system_clock_freq;
820Sstevel@tonic-gate uint_t		niommu_tsbs = 0;
830Sstevel@tonic-gate 
845834Spt157919 static int n_l2_caches = 0;
855834Spt157919 
862296Sae112802 /* prevent compilation with VAC defined */
872296Sae112802 #ifdef VAC
882296Sae112802 #error "The sun4v architecture does not support VAC"
892296Sae112802 #endif
902296Sae112802 
912296Sae112802 #define	S_VAC_SIZE	MMU_PAGESIZE
922296Sae112802 #define	S_VAC_SHIFT	MMU_PAGESHIFT
932296Sae112802 
942296Sae112802 int		vac_size = S_VAC_SIZE;
952296Sae112802 uint_t		vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1);
962296Sae112802 int		vac_shift = S_VAC_SHIFT;
972296Sae112802 uintptr_t	shm_alignment = S_VAC_SIZE;
982296Sae112802 
990Sstevel@tonic-gate void
map_wellknown_devices()1000Sstevel@tonic-gate map_wellknown_devices()
1010Sstevel@tonic-gate {
1021991Sheppo }
1030Sstevel@tonic-gate 
1041991Sheppo void
fill_cpu(md_t * mdp,mde_cookie_t cpuc)1051991Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc)
1061991Sheppo {
1071991Sheppo 	struct cpu_node *cpunode;
1081991Sheppo 	uint64_t cpuid;
1091991Sheppo 	uint64_t clk_freq;
1101991Sheppo 	char *namebuf;
1111991Sheppo 	char *namebufp;
1121991Sheppo 	int namelen;
1131991Sheppo 	uint64_t associativity = 0, linesize = 0, size = 0;
1140Sstevel@tonic-gate 
1151991Sheppo 	if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) {
1161991Sheppo 		return;
1171991Sheppo 	}
1181991Sheppo 
1192531Snarayan 	/* All out-of-range cpus will be stopped later. */
1201991Sheppo 	if (cpuid >= NCPU) {
1211991Sheppo 		cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - "
1222531Snarayan 		    "cpu excluded from configuration\n", cpuid);
1231991Sheppo 
1240Sstevel@tonic-gate 		return;
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	cpunode = &cpunodes[cpuid];
1281991Sheppo 	cpunode->cpuid = (int)cpuid;
1290Sstevel@tonic-gate 	cpunode->device_id = cpuid;
1300Sstevel@tonic-gate 
1311991Sheppo 	if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI))
1321991Sheppo 		(void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI);
1331991Sheppo 
1341991Sheppo 	if (md_get_prop_data(mdp, cpuc,
1351991Sheppo 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
1361991Sheppo 		cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible "
1371991Sheppo 		    "property");
1381991Sheppo 	}
1390Sstevel@tonic-gate 	namebufp = namebuf;
1400Sstevel@tonic-gate 	if (strncmp(namebufp, "SUNW,", 5) == 0)
1410Sstevel@tonic-gate 		namebufp += 5;
1421991Sheppo 	if (strlen(namebufp) > sizeof (cpunode->name))
1431991Sheppo 		cmn_err(CE_PANIC, "Compatible property too big to "
1441991Sheppo 		    "fit into the cpunode name buffer");
1450Sstevel@tonic-gate 	(void) strcpy(cpunode->name, namebufp);
1460Sstevel@tonic-gate 
1471991Sheppo 	if (md_get_prop_val(mdp, cpuc,
1481991Sheppo 	    "clock-frequency", &clk_freq)) {
1490Sstevel@tonic-gate 			clk_freq = 0;
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 	cpunode->clock_freq = clk_freq;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	ASSERT(cpunode->clock_freq != 0);
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * Compute scaling factor based on rate of %tick. This is used
1560Sstevel@tonic-gate 	 * to convert from ticks derived from %tick to nanoseconds. See
1570Sstevel@tonic-gate 	 * comment in sun4u/sys/clock.h for details.
1580Sstevel@tonic-gate 	 */
1590Sstevel@tonic-gate 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
1600Sstevel@tonic-gate 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
1610Sstevel@tonic-gate 
1621991Sheppo 	/*
1631991Sheppo 	 * The nodeid is not used in sun4v at all. Setting it
1641991Sheppo 	 * to positive value to make starting of slave CPUs
1651991Sheppo 	 * code happy.
1661991Sheppo 	 */
1671991Sheppo 	cpunode->nodeid = cpuid + 1;
1680Sstevel@tonic-gate 
1691991Sheppo 	/*
1701991Sheppo 	 * Obtain the L2 cache information from MD.
1711991Sheppo 	 * If "Cache" node exists, then set L2 cache properties
1721991Sheppo 	 * as read from MD.
1731991Sheppo 	 * If node does not exists, then set the L2 cache properties
1741991Sheppo 	 * in individual CPU module.
1751991Sheppo 	 */
1761991Sheppo 	if ((!get_l2_cache_info(mdp, cpuc,
1771991Sheppo 	    &associativity, &size, &linesize)) ||
1781991Sheppo 	    associativity == 0 || size == 0 || linesize == 0) {
1791991Sheppo 		cpu_fiximp(cpunode);
1801991Sheppo 	} else {
1811991Sheppo 		/*
1821991Sheppo 		 * Do not expect L2 cache properties to be bigger
1831991Sheppo 		 * than 32-bit quantity.
1841991Sheppo 		 */
1851991Sheppo 		cpunode->ecache_associativity = (int)associativity;
1861991Sheppo 		cpunode->ecache_size = (int)size;
1871991Sheppo 		cpunode->ecache_linesize = (int)linesize;
1881991Sheppo 	}
1891991Sheppo 
1901991Sheppo 	cpunode->ecache_setsize =
1911991Sheppo 	    cpunode->ecache_size / cpunode->ecache_associativity;
1921991Sheppo 
1934732Sdavemq 	/*
1944732Sdavemq 	 * Initialize the mapping for exec unit, chip and core.
1954732Sdavemq 	 */
1961991Sheppo 	cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND;
1974732Sdavemq 	cpunode->l2_cache_mapping = NO_MAPPING_FOUND;
1984732Sdavemq 	cpunode->core_mapping = NO_CORE_MAPPING_FOUND;
1991991Sheppo 
2001991Sheppo 	if (ecache_setsize == 0)
2011991Sheppo 		ecache_setsize = cpunode->ecache_setsize;
2021991Sheppo 	if (ecache_alignsize == 0)
2031991Sheppo 		ecache_alignsize = cpunode->ecache_linesize;
2041991Sheppo 
2051991Sheppo }
2061991Sheppo 
2071991Sheppo void
empty_cpu(int cpuid)2081991Sheppo empty_cpu(int cpuid)
2091991Sheppo {
2101991Sheppo 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
2111991Sheppo }
2121991Sheppo 
2134732Sdavemq /*
2144732Sdavemq  * Use L2 cache node to derive the chip mapping.
2154732Sdavemq  */
2164732Sdavemq void
setup_chip_mappings(md_t * mdp)2174732Sdavemq setup_chip_mappings(md_t *mdp)
2184732Sdavemq {
2197718SJason.Beloro@Sun.COM 	int ncache, ncpu;
2204732Sdavemq 	mde_cookie_t *node, *cachelist;
2214732Sdavemq 	int i, j;
2224732Sdavemq 	processorid_t cpuid;
2234732Sdavemq 	int idx = 0;
2244732Sdavemq 
2254732Sdavemq 	ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache",
2264732Sdavemq 	    "fwd", &cachelist);
2274732Sdavemq 
2284732Sdavemq 	/*
2294732Sdavemq 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
2304732Sdavemq 	 */
2314732Sdavemq 	if (ncache < 1) {
2324732Sdavemq 		return;
2334732Sdavemq 	}
2344732Sdavemq 
2354732Sdavemq 	for (i = 0; i < ncache; i++) {
2364732Sdavemq 		uint64_t cache_level;
2374732Sdavemq 		uint64_t lcpuid;
2384732Sdavemq 
2394732Sdavemq 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
2404732Sdavemq 			continue;
2414732Sdavemq 
2424732Sdavemq 		if (cache_level != 2)
2434732Sdavemq 			continue;
2444732Sdavemq 
2454732Sdavemq 		/*
2464732Sdavemq 		 * Found a l2 cache node. Find out the cpu nodes it
2474732Sdavemq 		 * points to.
2484732Sdavemq 		 */
2494732Sdavemq 		ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu",
2504732Sdavemq 		    "back", &node);
2514732Sdavemq 
2524732Sdavemq 		if (ncpu < 1)
2534732Sdavemq 			continue;
2544732Sdavemq 
2554732Sdavemq 		for (j = 0; j < ncpu; j++) {
2564732Sdavemq 			if (md_get_prop_val(mdp, node[j], "id", &lcpuid))
2574732Sdavemq 				continue;
2584732Sdavemq 			if (lcpuid >= NCPU)
2594732Sdavemq 				continue;
2604732Sdavemq 			cpuid = (processorid_t)lcpuid;
2614732Sdavemq 			cpunodes[cpuid].l2_cache_mapping = idx;
2624732Sdavemq 		}
2634732Sdavemq 		md_free_scan_dag(mdp, &node);
2644732Sdavemq 
2654732Sdavemq 		idx++;
2664732Sdavemq 	}
2674732Sdavemq 
2684732Sdavemq 	md_free_scan_dag(mdp, &cachelist);
2694732Sdavemq }
2704732Sdavemq 
2711991Sheppo void
setup_exec_unit_mappings(md_t * mdp)2721991Sheppo setup_exec_unit_mappings(md_t *mdp)
2731991Sheppo {
2747718SJason.Beloro@Sun.COM 	int num, num_eunits;
2751991Sheppo 	mde_cookie_t cpus_node;
2761991Sheppo 	mde_cookie_t *node, *eunit;
2771991Sheppo 	int idx, i, j;
2781991Sheppo 	processorid_t cpuid;
2791991Sheppo 	char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit";
2803434Sesaxe 	enum eu_type { INTEGER, FPU } etype;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/*
2831991Sheppo 	 * Find the cpu integer exec units - and
2841991Sheppo 	 * setup the mappings appropriately.
2850Sstevel@tonic-gate 	 */
2861991Sheppo 	num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node);
2871991Sheppo 	if (num < 1)
2882531Snarayan 		cmn_err(CE_PANIC, "No cpus node in machine description");
2891991Sheppo 	if (num > 1)
2901991Sheppo 		cmn_err(CE_PANIC, "More than 1 cpus node in machine"
2911991Sheppo 		    " description");
2921991Sheppo 
2931991Sheppo 	cpus_node = node[0];
2941991Sheppo 	md_free_scan_dag(mdp, &node);
2951991Sheppo 
2961991Sheppo 	num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name,
2971991Sheppo 	    "fwd", &eunit);
2981991Sheppo 	if (num_eunits > 0) {
2993434Sesaxe 		char *int_str = broken_md_flag ? "int" : "integer";
3003434Sesaxe 		char *fpu_str = "fp";
3011991Sheppo 
3021991Sheppo 		/* Spin through and find all the integer exec units */
3031991Sheppo 		for (i = 0; i < num_eunits; i++) {
3041991Sheppo 			char *p;
3051991Sheppo 			char *val;
3061991Sheppo 			int vallen;
3071991Sheppo 			uint64_t lcpuid;
3081991Sheppo 
3093434Sesaxe 			/* ignore nodes with no type */
3101991Sheppo 			if (md_get_prop_data(mdp, eunit[i], "type",
3114677Szx151605 			    (uint8_t **)&val, &vallen))
3124677Szx151605 				continue;
3131991Sheppo 
3141991Sheppo 			for (p = val; *p != '\0'; p += strlen(p) + 1) {
3153434Sesaxe 				if (strcmp(p, int_str) == 0) {
3163434Sesaxe 					etype = INTEGER;
3171991Sheppo 					goto found;
3183434Sesaxe 				}
3193434Sesaxe 				if (strcmp(p, fpu_str) == 0) {
3203434Sesaxe 					etype = FPU;
3213434Sesaxe 					goto found;
3223434Sesaxe 				}
3231991Sheppo 			}
3241991Sheppo 
3251991Sheppo 			continue;
3261991Sheppo found:
3271991Sheppo 			idx = NCPU + i;
3281991Sheppo 			/*
3291991Sheppo 			 * find the cpus attached to this EU and
3301991Sheppo 			 * update their mapping indices
3311991Sheppo 			 */
3321991Sheppo 			num = md_alloc_scan_dag(mdp, eunit[i], "cpu",
3331991Sheppo 			    "back", &node);
3341991Sheppo 
3351991Sheppo 			if (num < 1)
3361991Sheppo 				cmn_err(CE_PANIC, "exec-unit node in MD"
3371991Sheppo 				    " not attached to a cpu node");
3381991Sheppo 
3391991Sheppo 			for (j = 0; j < num; j++) {
3401991Sheppo 				if (md_get_prop_val(mdp, node[j], "id",
3411991Sheppo 				    &lcpuid))
3421991Sheppo 					continue;
3431991Sheppo 				if (lcpuid >= NCPU)
3441991Sheppo 					continue;
3451991Sheppo 				cpuid = (processorid_t)lcpuid;
3463434Sesaxe 				switch (etype) {
3473434Sesaxe 				case INTEGER:
3483434Sesaxe 					cpunodes[cpuid].exec_unit_mapping = idx;
3493434Sesaxe 					break;
3503434Sesaxe 				case FPU:
3513434Sesaxe 					cpunodes[cpuid].fpu_mapping = idx;
3523434Sesaxe 					break;
3533434Sesaxe 				}
3541991Sheppo 			}
3551991Sheppo 			md_free_scan_dag(mdp, &node);
3561991Sheppo 		}
35710271SJason.Beloro@Sun.COM 
35810271SJason.Beloro@Sun.COM 
3591991Sheppo 		md_free_scan_dag(mdp, &eunit);
3601991Sheppo 	}
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate /*
3641991Sheppo  * All the common setup of sun4v CPU modules is done by this routine.
3650Sstevel@tonic-gate  */
3661991Sheppo void
cpu_setup_common(char ** cpu_module_isa_set)3671991Sheppo cpu_setup_common(char **cpu_module_isa_set)
3680Sstevel@tonic-gate {
3691991Sheppo 	extern int mmu_exported_pagesize_mask;
3701991Sheppo 	int nocpus, i;
3711991Sheppo 	size_t ra_limit;
3721991Sheppo 	mde_cookie_t *cpulist;
3731991Sheppo 	md_t *mdp;
3741991Sheppo 
3751991Sheppo 	if ((mdp = md_get_handle()) == NULL)
3761991Sheppo 		cmn_err(CE_PANIC, "Unable to initialize machine description");
3771991Sheppo 
3786880Sdv142724 	boot_ncpus = nocpus = md_alloc_scan_dag(mdp,
3791991Sheppo 	    md_root_node(mdp), "cpu", "fwd", &cpulist);
3801991Sheppo 	if (nocpus < 1) {
3811991Sheppo 		cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation "
3821991Sheppo 		    "failed or incorrect number of CPUs in MD");
3831991Sheppo 	}
3841991Sheppo 
3852531Snarayan 	init_md_broken(mdp, cpulist);
3862531Snarayan 
3871991Sheppo 	if (use_page_coloring) {
3881991Sheppo 		do_pg_coloring = 1;
3891991Sheppo 	}
3901991Sheppo 
3911991Sheppo 	/*
3922241Shuah 	 * Get the valid mmu page sizes mask, Q sizes and isalist/r
3931991Sheppo 	 * from the MD for the first available CPU in cpulist.
3942241Shuah 	 *
3952241Shuah 	 * Do not expect the MMU page sizes mask to be more than 32-bit.
3961991Sheppo 	 */
3971991Sheppo 	mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]);
3981991Sheppo 
3994528Spaulsan 	/*
4004528Spaulsan 	 * Get the number of contexts and tsbs supported.
4014528Spaulsan 	 */
4024528Spaulsan 	if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS &&
4034528Spaulsan 	    get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) {
4044528Spaulsan 		shctx_on = 1;
4054528Spaulsan 	}
4064528Spaulsan 
4071991Sheppo 	for (i = 0; i < nocpus; i++)
4081991Sheppo 		fill_cpu(mdp, cpulist[i]);
4091991Sheppo 
4105834Spt157919 	/* setup l2 cache count. */
4115834Spt157919 	n_l2_caches = get_l2_cache_node_count(mdp);
4125834Spt157919 
4134732Sdavemq 	setup_chip_mappings(mdp);
4141991Sheppo 	setup_exec_unit_mappings(mdp);
4151991Sheppo 
4161991Sheppo 	/*
4171991Sheppo 	 * If MD is broken then append the passed ISA set,
4181991Sheppo 	 * otherwise trust the MD.
4191991Sheppo 	 */
4200Sstevel@tonic-gate 
4211991Sheppo 	if (broken_md_flag)
4221991Sheppo 		isa_list = construct_isalist(mdp, cpulist[0],
4231991Sheppo 		    cpu_module_isa_set);
4241991Sheppo 	else
4251991Sheppo 		isa_list = construct_isalist(mdp, cpulist[0], NULL);
4261991Sheppo 
4277718SJason.Beloro@Sun.COM 	get_hwcaps(mdp, cpulist[0]);
4289351SPrashanth.Sreenivasa@Sun.COM 	get_weakest_mem_model(mdp, cpulist[0]);
4291991Sheppo 	get_q_sizes(mdp, cpulist[0]);
4301991Sheppo 	get_va_bits(mdp, cpulist[0]);
4311991Sheppo 
4321991Sheppo 	/*
4331991Sheppo 	 * ra_limit is the highest real address in the machine.
4341991Sheppo 	 */
43510106SJason.Beloro@Sun.COM 	ra_limit = get_ra_limit(mdp, cpulist[0]);
4361991Sheppo 
4371991Sheppo 	md_free_scan_dag(mdp, &cpulist);
4381991Sheppo 
4391991Sheppo 	(void) md_fini_handle(mdp);
4401991Sheppo 
4411991Sheppo 	/*
4421991Sheppo 	 * Block stores invalidate all pages of the d$ so pagecopy
4431991Sheppo 	 * et. al. do not need virtual translations with virtual
4441991Sheppo 	 * coloring taken into consideration.
4451991Sheppo 	 */
4461991Sheppo 	pp_consistent_coloring = 0;
4471991Sheppo 
4481991Sheppo 	/*
4491991Sheppo 	 * The kpm mapping window.
4501991Sheppo 	 * kpm_size:
4511991Sheppo 	 *	The size of a single kpm range.
4521991Sheppo 	 *	The overall size will be: kpm_size * vac_colors.
4531991Sheppo 	 * kpm_vbase:
4541991Sheppo 	 *	The virtual start address of the kpm range within the kernel
4551991Sheppo 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
4561991Sheppo 	 */
4570Sstevel@tonic-gate 
4581991Sheppo 	/*
4591991Sheppo 	 * Make kpm_vbase, kpm_size aligned to kpm_size_shift.
4601991Sheppo 	 * To do this find the nearest power of 2 size that the
4611991Sheppo 	 * actual ra_limit fits within.
4621991Sheppo 	 * If it is an even power of two use that, otherwise use the
4631991Sheppo 	 * next power of two larger than ra_limit.
4641991Sheppo 	 */
4651991Sheppo 
4661991Sheppo 	ASSERT(ra_limit != 0);
4671991Sheppo 
4681991Sheppo 	kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ?
4694677Szx151605 	    highbit(ra_limit) : highbit(ra_limit) - 1;
4701991Sheppo 
4711991Sheppo 	/*
4721991Sheppo 	 * No virtual caches on sun4v so size matches size shift
4731991Sheppo 	 */
4741991Sheppo 	kpm_size = 1ul << kpm_size_shift;
4750Sstevel@tonic-gate 
4761991Sheppo 	if (va_bits < VA_ADDRESS_SPACE_BITS) {
4771991Sheppo 		/*
4781991Sheppo 		 * In case of VA hole
4791991Sheppo 		 * kpm_base = hole_end + 1TB
4801991Sheppo 		 * Starting 1TB beyond where VA hole ends because on Niagara
4811991Sheppo 		 * processor software must not use pages within 4GB of the
4821991Sheppo 		 * VA hole as instruction pages to avoid problems with
4831991Sheppo 		 * prefetching into the VA hole.
4841991Sheppo 		 */
4851991Sheppo 		kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) +
4861991Sheppo 		    (1ull << 40));
4871991Sheppo 	} else {		/* Number of VA bits 64 ... no VA hole */
4881991Sheppo 		kpm_vbase = (caddr_t)0x8000000000000000ull;	/* 8 EB */
4891991Sheppo 	}
4900Sstevel@tonic-gate 
4911991Sheppo 	/*
4921991Sheppo 	 * The traptrace code uses either %tick or %stick for
4931991Sheppo 	 * timestamping.  The sun4v require use of %stick.
4941991Sheppo 	 */
4951991Sheppo 	traptrace_use_stick = 1;
4961991Sheppo }
4971991Sheppo 
4981991Sheppo /*
4991991Sheppo  * Get the nctxs from MD. If absent panic.
5001991Sheppo  */
5011991Sheppo static uint64_t
get_mmu_ctx_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)5021991Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
5031991Sheppo {
5041991Sheppo 	uint64_t ctx_bits;
5051991Sheppo 
5061991Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits",
5071991Sheppo 	    &ctx_bits))
5081991Sheppo 		ctx_bits = 0;
5091991Sheppo 
5101991Sheppo 	if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS)
5111991Sheppo 		cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits "
5121991Sheppo 		    "returned by MD", ctx_bits);
5131991Sheppo 
5141991Sheppo 	return (ctx_bits);
5151991Sheppo }
5161991Sheppo 
5171991Sheppo /*
5184528Spaulsan  * Get the number of tsbs from MD. If absent the default value is 0.
5194528Spaulsan  */
5204528Spaulsan static uint64_t
get_mmu_tsbs(md_t * mdp,mde_cookie_t cpu_node_cookie)5214528Spaulsan get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie)
5224528Spaulsan {
5234528Spaulsan 	uint64_t number_tsbs;
5244528Spaulsan 
5254528Spaulsan 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs",
5264528Spaulsan 	    &number_tsbs))
5274528Spaulsan 		number_tsbs = 0;
5284528Spaulsan 
5294528Spaulsan 	return (number_tsbs);
5304528Spaulsan }
5314528Spaulsan 
5324528Spaulsan /*
5335075Spaulsan  * Get the number of shared contexts from MD. If absent the default value is 0.
5344528Spaulsan  *
5354528Spaulsan  */
5364528Spaulsan static uint64_t
get_mmu_shcontexts(md_t * mdp,mde_cookie_t cpu_node_cookie)5374528Spaulsan get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie)
5384528Spaulsan {
5394528Spaulsan 	uint64_t number_contexts;
5404528Spaulsan 
5414528Spaulsan 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts",
5424528Spaulsan 	    &number_contexts))
5434528Spaulsan 		number_contexts = 0;
5444528Spaulsan 
5454528Spaulsan 	return (number_contexts);
5464528Spaulsan }
5474528Spaulsan 
5484528Spaulsan /*
5491991Sheppo  * Initalize supported page sizes information.
5501991Sheppo  * Set to 0, if the page sizes mask information is absent in MD.
5511991Sheppo  */
5521991Sheppo static uint64_t
get_cpu_pagesizes(md_t * mdp,mde_cookie_t cpu_node_cookie)5531991Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
5541991Sheppo {
5551991Sheppo 	uint64_t mmu_page_size_list;
5561991Sheppo 
5571991Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list",
5581991Sheppo 	    &mmu_page_size_list))
5591991Sheppo 		mmu_page_size_list = 0;
5601991Sheppo 
5611991Sheppo 	if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK)
5621991Sheppo 		cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned"
5631991Sheppo 		    "by MD", mmu_page_size_list);
5641991Sheppo 
5651991Sheppo 	return (mmu_page_size_list);
5661991Sheppo }
5671991Sheppo 
5681991Sheppo /*
5691991Sheppo  * This routine gets the isalist information from MD and appends
5701991Sheppo  * the CPU module ISA set if required.
5711991Sheppo  */
5721991Sheppo static char *
construct_isalist(md_t * mdp,mde_cookie_t cpu_node_cookie,char ** cpu_module_isa_set)5731991Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie,
5741991Sheppo     char **cpu_module_isa_set)
5751991Sheppo {
5761991Sheppo 	extern int at_flags;
5771991Sheppo 	char *md_isalist;
5781991Sheppo 	int md_isalen;
5791991Sheppo 	char *isabuf;
5801991Sheppo 	int isalen;
5811991Sheppo 	char **isa_set;
5821991Sheppo 	char *p, *q;
5831991Sheppo 	int cpu_module_isalen = 0, found = 0;
5841991Sheppo 
5851991Sheppo 	(void) md_get_prop_data(mdp, cpu_node_cookie,
5861991Sheppo 	    "isalist", (uint8_t **)&isabuf, &isalen);
5871991Sheppo 
5881991Sheppo 	/*
5891991Sheppo 	 * We support binaries for all the cpus that have shipped so far.
5901991Sheppo 	 * The kernel emulates instructions that are not supported by hardware.
5911991Sheppo 	 */
5921991Sheppo 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
5931991Sheppo 
5941991Sheppo 	/*
5951991Sheppo 	 * Construct the space separated isa_list.
5961991Sheppo 	 */
5971991Sheppo 	if (cpu_module_isa_set != NULL) {
5981991Sheppo 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
5991991Sheppo 		    isa_set++) {
6001991Sheppo 			cpu_module_isalen += strlen(*isa_set);
6011991Sheppo 			cpu_module_isalen++;	/* for space character */
6021991Sheppo 		}
6031991Sheppo 	}
6041991Sheppo 
6051991Sheppo 	/*
6061991Sheppo 	 * Allocate the buffer of MD isa buffer length + CPU module
6071991Sheppo 	 * isa buffer length.
6080Sstevel@tonic-gate 	 */
6091991Sheppo 	md_isalen = isalen + cpu_module_isalen + 2;
6101991Sheppo 	md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0);
6111991Sheppo 	if (md_isalist == NULL)
6121991Sheppo 		cmn_err(CE_PANIC, "construct_isalist: Allocation failed for "
6131991Sheppo 		    "md_isalist");
6141991Sheppo 
6151991Sheppo 	md_isalist[0] = '\0'; /* create an empty string to start */
6161991Sheppo 	for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) {
6171991Sheppo 		(void) strlcat(md_isalist, p, md_isalen);
6181991Sheppo 		(void) strcat(md_isalist, " ");
6191991Sheppo 	}
6201991Sheppo 
6211991Sheppo 	/*
6221991Sheppo 	 * Check if the isa_set is present in isalist returned by MD.
6231991Sheppo 	 * If yes, then no need to append it, if no then append it to
6241991Sheppo 	 * isalist returned by MD.
6251991Sheppo 	 */
6261991Sheppo 	if (cpu_module_isa_set != NULL) {
6271991Sheppo 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
6281991Sheppo 		    isa_set++) {
6291991Sheppo 			found = 0;
6301991Sheppo 			for (p = isabuf, q = p + isalen; p < q;
6311991Sheppo 			    p += strlen(p) + 1) {
6321991Sheppo 				if (strcmp(p, *isa_set) == 0) {
6331991Sheppo 					found = 1;
6341991Sheppo 					break;
6351991Sheppo 				}
6361991Sheppo 			}
6371991Sheppo 			if (!found) {
6381991Sheppo 				(void) strlcat(md_isalist, *isa_set, md_isalen);
6391991Sheppo 				(void) strcat(md_isalist, " ");
6401991Sheppo 			}
6411991Sheppo 		}
6421991Sheppo 	}
6431991Sheppo 
6441991Sheppo 	/* Get rid of any trailing white spaces */
6451991Sheppo 	md_isalist[strlen(md_isalist) - 1] = '\0';
6461991Sheppo 
6471991Sheppo 	return (md_isalist);
6481991Sheppo }
6491991Sheppo 
6507718SJason.Beloro@Sun.COM static void
get_hwcaps(md_t * mdp,mde_cookie_t cpu_node_cookie)6517718SJason.Beloro@Sun.COM get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie)
6527718SJason.Beloro@Sun.COM {
6537718SJason.Beloro@Sun.COM 	char *hwcapbuf;
6547718SJason.Beloro@Sun.COM 	int hwcaplen;
6557718SJason.Beloro@Sun.COM 
6567718SJason.Beloro@Sun.COM 	if (md_get_prop_data(mdp, cpu_node_cookie,
6577718SJason.Beloro@Sun.COM 	    "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) {
6587718SJason.Beloro@Sun.COM 		/* Property not found */
6597718SJason.Beloro@Sun.COM 		return;
6607718SJason.Beloro@Sun.COM 	}
6617718SJason.Beloro@Sun.COM 
6627718SJason.Beloro@Sun.COM 	cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC,
6637718SJason.Beloro@Sun.COM 	    "unrecognized token: %s");
6647718SJason.Beloro@Sun.COM }
6657718SJason.Beloro@Sun.COM 
6669351SPrashanth.Sreenivasa@Sun.COM static void
get_weakest_mem_model(md_t * mdp,mde_cookie_t cpu_node_cookie)6679351SPrashanth.Sreenivasa@Sun.COM get_weakest_mem_model(md_t *mdp, mde_cookie_t cpu_node_cookie)
6689351SPrashanth.Sreenivasa@Sun.COM {
6699351SPrashanth.Sreenivasa@Sun.COM 	char *mmbuf;
6709351SPrashanth.Sreenivasa@Sun.COM 	int mmlen;
6719351SPrashanth.Sreenivasa@Sun.COM 	uint_t wmm;
6729351SPrashanth.Sreenivasa@Sun.COM 	char *p, *q;
6739351SPrashanth.Sreenivasa@Sun.COM 
6749351SPrashanth.Sreenivasa@Sun.COM 	if (md_get_prop_data(mdp, cpu_node_cookie,
6759351SPrashanth.Sreenivasa@Sun.COM 	    "memory-model-list", (uint8_t **)&mmbuf, &mmlen)) {
6769351SPrashanth.Sreenivasa@Sun.COM 		/* Property not found */
6779351SPrashanth.Sreenivasa@Sun.COM 		return;
6789351SPrashanth.Sreenivasa@Sun.COM 	}
6799351SPrashanth.Sreenivasa@Sun.COM 
6809351SPrashanth.Sreenivasa@Sun.COM 	wmm = TSTATE_MM_TSO;
6819351SPrashanth.Sreenivasa@Sun.COM 	for (p = mmbuf, q = p + mmlen; p < q; p += strlen(p) + 1) {
6829351SPrashanth.Sreenivasa@Sun.COM 		if (strcmp(p, "wc") == 0)
6839351SPrashanth.Sreenivasa@Sun.COM 			wmm = TSTATE_MM_WC;
6849351SPrashanth.Sreenivasa@Sun.COM 	}
6859351SPrashanth.Sreenivasa@Sun.COM 	weakest_mem_model = wmm;
6869351SPrashanth.Sreenivasa@Sun.COM }
6877718SJason.Beloro@Sun.COM 
6887718SJason.Beloro@Sun.COM /*
6897718SJason.Beloro@Sun.COM  * Does the opposite of cmn_err(9f) "%b" conversion specification:
6907718SJason.Beloro@Sun.COM  * Given a list of strings, converts them to a bit-vector.
6917718SJason.Beloro@Sun.COM  *
6927718SJason.Beloro@Sun.COM  *  tokens - is a buffer of [NUL-terminated] strings.
6937718SJason.Beloro@Sun.COM  *  tokenslen - length of tokenbuf in bytes.
6947718SJason.Beloro@Sun.COM  *  bit_formatter - is a %b format string, such as FMT_AV_SPARC
6957718SJason.Beloro@Sun.COM  *    from /usr/include/sys/auxv_SPARC.h, of the form:
6967718SJason.Beloro@Sun.COM  *    <base-char>[<bit-char><token-string>]...
6977718SJason.Beloro@Sun.COM  *        <base-char> is ignored.
6987718SJason.Beloro@Sun.COM  *        <bit-char>  is [1-32], as per cmn_err(9f).
6997718SJason.Beloro@Sun.COM  *  warning - is a printf-style format string containing "%s",
7007718SJason.Beloro@Sun.COM  *    which is used to print a warning message when an unrecognized
7017718SJason.Beloro@Sun.COM  *    token is found.  If warning is NULL, no warning is printed.
7027718SJason.Beloro@Sun.COM  * Returns a bit-vector corresponding to the specified tokens.
7037718SJason.Beloro@Sun.COM  */
7047718SJason.Beloro@Sun.COM 
7057718SJason.Beloro@Sun.COM static unsigned long
names2bits(char * tokens,size_t tokenslen,char * bit_formatter,char * warning)7067718SJason.Beloro@Sun.COM names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning)
7077718SJason.Beloro@Sun.COM {
7087718SJason.Beloro@Sun.COM 	char *cur;
7097718SJason.Beloro@Sun.COM 	size_t  curlen;
7107718SJason.Beloro@Sun.COM 	unsigned long ul = 0;
7117718SJason.Beloro@Sun.COM 	char *hit;
7127718SJason.Beloro@Sun.COM 	char *bs;
7137718SJason.Beloro@Sun.COM 
7147718SJason.Beloro@Sun.COM 	bit_formatter++;	/* skip base; not needed for input */
7157718SJason.Beloro@Sun.COM 	cur = tokens;
7167718SJason.Beloro@Sun.COM 	while (tokenslen) {
7177718SJason.Beloro@Sun.COM 		curlen = strlen(cur);
7187718SJason.Beloro@Sun.COM 		bs = bit_formatter;
7197718SJason.Beloro@Sun.COM 		/*
7207718SJason.Beloro@Sun.COM 		 * We need a complicated while loop and the >=32 check,
7217718SJason.Beloro@Sun.COM 		 * instead of a simple "if (strstr())" so that when the
7227718SJason.Beloro@Sun.COM 		 * token is "vis", we don't match on "vis2" (for example).
7237718SJason.Beloro@Sun.COM 		 */
7247718SJason.Beloro@Sun.COM 		/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
7257718SJason.Beloro@Sun.COM 		while ((hit = strstr(bs, cur)) &&
7267718SJason.Beloro@Sun.COM 		    *(hit + curlen) >= 32) {
7277718SJason.Beloro@Sun.COM 			/*
7287718SJason.Beloro@Sun.COM 			 * We're still in the middle of a word, i.e., not
7297718SJason.Beloro@Sun.COM 			 * pointing at a <bit-char>.  So advance ptr
7307718SJason.Beloro@Sun.COM 			 * to ensure forward progress.
7317718SJason.Beloro@Sun.COM 			 */
7327718SJason.Beloro@Sun.COM 			bs = hit + curlen + 1;
7337718SJason.Beloro@Sun.COM 		}
7347718SJason.Beloro@Sun.COM 
7357718SJason.Beloro@Sun.COM 		if (hit != NULL) {
7367718SJason.Beloro@Sun.COM 			ul |= (1<<(*(hit-1) - 1));
7377718SJason.Beloro@Sun.COM 		} else {
7387718SJason.Beloro@Sun.COM 			/* The token wasn't found in bit_formatter */
7397718SJason.Beloro@Sun.COM 			if (warning != NULL)
7407718SJason.Beloro@Sun.COM 				cmn_err(CE_WARN, warning, cur);
7417718SJason.Beloro@Sun.COM 		}
7427718SJason.Beloro@Sun.COM 		tokenslen -= curlen + 1;
7437718SJason.Beloro@Sun.COM 		cur += curlen + 1;
7447718SJason.Beloro@Sun.COM 	}
7457718SJason.Beloro@Sun.COM 	return (ul);
7467718SJason.Beloro@Sun.COM }
7477718SJason.Beloro@Sun.COM 
7481991Sheppo uint64_t
get_ra_limit(md_t * mdp,mde_cookie_t cpu_node_cookie)74910106SJason.Beloro@Sun.COM get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie)
7501991Sheppo {
75110106SJason.Beloro@Sun.COM 	extern int ppvm_enable;
75210106SJason.Beloro@Sun.COM 	extern int meta_alloc_enable;
7531991Sheppo 	mde_cookie_t *mem_list;
7541991Sheppo 	mde_cookie_t *mblock_list;
7551991Sheppo 	int i;
7561991Sheppo 	int memnodes;
7571991Sheppo 	int nmblock;
75810106SJason.Beloro@Sun.COM 	uint64_t r;
7591991Sheppo 	uint64_t base;
7601991Sheppo 	uint64_t size;
7611991Sheppo 	uint64_t ra_limit = 0, new_limit = 0;
7621991Sheppo 
76310106SJason.Beloro@Sun.COM 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) {
76410106SJason.Beloro@Sun.COM 		if (r == 0 || r > RA_ADDRESS_SPACE_BITS)
76510106SJason.Beloro@Sun.COM 			cmn_err(CE_PANIC, "Incorrect number of ra bits in MD");
76610106SJason.Beloro@Sun.COM 		else {
76710106SJason.Beloro@Sun.COM 			/*
76810106SJason.Beloro@Sun.COM 			 * Enable memory DR and metadata (page_t)
76910106SJason.Beloro@Sun.COM 			 * allocation from existing memory.
77010106SJason.Beloro@Sun.COM 			 */
77110106SJason.Beloro@Sun.COM 			ppvm_enable = 1;
77210106SJason.Beloro@Sun.COM 			meta_alloc_enable = 1;
77310106SJason.Beloro@Sun.COM 			return (1ULL << r);
77410106SJason.Beloro@Sun.COM 		}
77510106SJason.Beloro@Sun.COM 	}
77610106SJason.Beloro@Sun.COM 
7771991Sheppo 	memnodes = md_alloc_scan_dag(mdp,
7781991Sheppo 	    md_root_node(mdp), "memory", "fwd", &mem_list);
7791991Sheppo 
7801991Sheppo 	ASSERT(memnodes == 1);
7811991Sheppo 
7821991Sheppo 	nmblock = md_alloc_scan_dag(mdp,
7831991Sheppo 	    mem_list[0], "mblock", "fwd", &mblock_list);
7841991Sheppo 	if (nmblock < 1)
7851991Sheppo 		cmn_err(CE_PANIC, "cannot find mblock nodes in MD");
7861991Sheppo 
7871991Sheppo 	for (i = 0; i < nmblock; i++) {
7881991Sheppo 		if (md_get_prop_val(mdp, mblock_list[i], "base", &base))
7891991Sheppo 			cmn_err(CE_PANIC, "base property missing from MD"
7901991Sheppo 			    " mblock node");
7911991Sheppo 		if (md_get_prop_val(mdp, mblock_list[i], "size", &size))
7921991Sheppo 			cmn_err(CE_PANIC, "size property missing from MD"
7931991Sheppo 			    " mblock node");
7941991Sheppo 
7951991Sheppo 		ASSERT(size != 0);
7961991Sheppo 
7971991Sheppo 		new_limit = base + size;
7981991Sheppo 
7991991Sheppo 		if (base > new_limit)
8001991Sheppo 			cmn_err(CE_PANIC, "mblock in MD wrapped around");
8011991Sheppo 
8021991Sheppo 		if (new_limit > ra_limit)
8034677Szx151605 			ra_limit = new_limit;
8041991Sheppo 	}
8051991Sheppo 
8061991Sheppo 	ASSERT(ra_limit != 0);
8071991Sheppo 
8081991Sheppo 	if (ra_limit > MAX_REAL_ADDRESS) {
8091991Sheppo 		cmn_err(CE_WARN, "Highest real address in MD too large"
8101991Sheppo 		    " clipping to %llx\n", MAX_REAL_ADDRESS);
8111991Sheppo 		ra_limit = MAX_REAL_ADDRESS;
8121991Sheppo 	}
8131991Sheppo 
8141991Sheppo 	md_free_scan_dag(mdp, &mblock_list);
8151991Sheppo 
8161991Sheppo 	md_free_scan_dag(mdp, &mem_list);
8171991Sheppo 
8181991Sheppo 	return (ra_limit);
8191991Sheppo }
8201991Sheppo 
8211991Sheppo /*
8221991Sheppo  * This routine sets the globals for CPU and DEV mondo queue entries and
8231991Sheppo  * resumable and non-resumable error queue entries.
8242531Snarayan  *
8252531Snarayan  * First, look up the number of bits available to pass an entry number.
8262531Snarayan  * This can vary by platform and may result in allocating an unreasonably
8272531Snarayan  * (or impossibly) large amount of memory for the corresponding table,
8286038Sdavemq  * so we clamp it by 'max_entries'.  Finally, since the q size is used when
8296038Sdavemq  * calling contig_mem_alloc(), which expects a power of 2, clamp the q size
8306038Sdavemq  * down to a power of 2.  If the prop is missing, use 'default_entries'.
8311991Sheppo  */
8321991Sheppo static uint64_t
get_single_q_size(md_t * mdp,mde_cookie_t cpu_node_cookie,char * qnamep,uint64_t default_entries,uint64_t max_entries)8331991Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie,
8342531Snarayan     char *qnamep, uint64_t default_entries, uint64_t max_entries)
8351991Sheppo {
8361991Sheppo 	uint64_t entries;
8371991Sheppo 
8382531Snarayan 	if (default_entries > max_entries)
8392531Snarayan 		cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > "
8402531Snarayan 		    "max %ld for %s\n", default_entries, max_entries, qnamep);
8412531Snarayan 
8421991Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) {
8431991Sheppo 		if (!broken_md_flag)
8441991Sheppo 			cmn_err(CE_PANIC, "Missing %s property in MD cpu node",
8454677Szx151605 			    qnamep);
8461991Sheppo 		entries = default_entries;
8471991Sheppo 	} else {
8481991Sheppo 		entries = 1 << entries;
8491991Sheppo 	}
8502531Snarayan 
8512531Snarayan 	entries = MIN(entries, max_entries);
8526038Sdavemq 	/* If not a power of 2, truncate to a power of 2. */
8536038Sdavemq 	if ((entries & (entries - 1)) != 0) {
8546038Sdavemq 		entries = 1 << (highbit(entries) - 1);
8556038Sdavemq 	}
8562531Snarayan 
8571991Sheppo 	return (entries);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8602531Snarayan /* Scaling constant used to compute size of cpu mondo queue */
8612531Snarayan #define	CPU_MONDO_Q_MULTIPLIER	8
8620Sstevel@tonic-gate 
8631991Sheppo static void
get_q_sizes(md_t * mdp,mde_cookie_t cpu_node_cookie)8641991Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
8651991Sheppo {
8662531Snarayan 	uint64_t max_qsize;
8672531Snarayan 	mde_cookie_t *platlist;
8682531Snarayan 	int nrnode;
8692531Snarayan 
8702531Snarayan 	/*
8712531Snarayan 	 * Compute the maximum number of entries for the cpu mondo queue.
8722531Snarayan 	 * Use the appropriate property in the platform node, if it is
8732531Snarayan 	 * available.  Else, base it on NCPU.
8742531Snarayan 	 */
8752531Snarayan 	nrnode = md_alloc_scan_dag(mdp,
8762531Snarayan 	    md_root_node(mdp), "platform", "fwd", &platlist);
8772531Snarayan 
8782531Snarayan 	ASSERT(nrnode == 1);
8792531Snarayan 
8804204Sha137994 	ncpu_guest_max = NCPU;
8814204Sha137994 	(void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max);
8824204Sha137994 	max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER;
8832531Snarayan 
8842531Snarayan 	md_free_scan_dag(mdp, &platlist);
8852531Snarayan 
8861991Sheppo 	cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie,
8872531Snarayan 	    "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize);
8881991Sheppo 
8891991Sheppo 	dev_q_entries = get_single_q_size(mdp, cpu_node_cookie,
8902973Sgovinda 	    "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM);
8911991Sheppo 
8921991Sheppo 	cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie,
8932531Snarayan 	    "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES);
8941991Sheppo 
8951991Sheppo 	cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie,
8962531Snarayan 	    "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES);
8971991Sheppo }
8981991Sheppo 
8991991Sheppo 
9001991Sheppo static void
get_va_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)9011991Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
9020Sstevel@tonic-gate {
9031991Sheppo 	uint64_t value = VA_ADDRESS_SPACE_BITS;
9041991Sheppo 
9051991Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value))
9061991Sheppo 		cmn_err(CE_PANIC, "mmu-#va-bits property  not found in MD");
9071991Sheppo 
9081991Sheppo 
9091991Sheppo 	if (value == 0 || value > VA_ADDRESS_SPACE_BITS)
9101991Sheppo 		cmn_err(CE_PANIC, "Incorrect number of va bits in MD");
9111991Sheppo 
9121991Sheppo 	/* Do not expect number of VA bits to be more than 32-bit quantity */
9131991Sheppo 
9141991Sheppo 	va_bits = (int)value;
9151991Sheppo 
9161991Sheppo 	/*
9171991Sheppo 	 * Correct the value for VA bits on UltraSPARC-T1 based systems
9181991Sheppo 	 * in case of broken MD.
9191991Sheppo 	 */
9201991Sheppo 	if (broken_md_flag)
9211991Sheppo 		va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS;
9221991Sheppo }
9231991Sheppo 
9245834Spt157919 int
l2_cache_node_count(void)9255834Spt157919 l2_cache_node_count(void)
9265834Spt157919 {
9275834Spt157919 	return (n_l2_caches);
9285834Spt157919 }
9295834Spt157919 
9305834Spt157919 /*
9315834Spt157919  * count the number of l2 caches.
9325834Spt157919  */
9335834Spt157919 int
get_l2_cache_node_count(md_t * mdp)9345834Spt157919 get_l2_cache_node_count(md_t *mdp)
9355834Spt157919 {
9365834Spt157919 	int i;
9375834Spt157919 	mde_cookie_t *cachenodes;
9385834Spt157919 	uint64_t level;
9395834Spt157919 	int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp),
9405834Spt157919 	    "cache", "fwd", &cachenodes);
9415834Spt157919 	int l2_caches = 0;
9425834Spt157919 
9435834Spt157919 	for (i = 0; i < n_cachenodes; i++) {
9445834Spt157919 		if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) {
9455834Spt157919 			level = 0;
9465834Spt157919 		}
9475834Spt157919 		if (level == 2) {
9485834Spt157919 			l2_caches++;
9495834Spt157919 		}
9505834Spt157919 	}
9515834Spt157919 	md_free_scan_dag(mdp, &cachenodes);
9525834Spt157919 	return (l2_caches);
9535834Spt157919 }
9545834Spt157919 
9551991Sheppo /*
9561991Sheppo  * This routine returns the L2 cache information such as -- associativity,
9571991Sheppo  * size and linesize.
9581991Sheppo  */
9591991Sheppo static int
get_l2_cache_info(md_t * mdp,mde_cookie_t cpu_node_cookie,uint64_t * associativity,uint64_t * size,uint64_t * linesize)9601991Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie,
9611991Sheppo 	    uint64_t *associativity, uint64_t *size, uint64_t *linesize)
9621991Sheppo {
9631991Sheppo 	mde_cookie_t *cachelist;
9641991Sheppo 	int ncaches, i;
9655078Sae112802 	uint64_t cache_level = 0;
9661991Sheppo 
9671991Sheppo 	ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache",
9681991Sheppo 	    "fwd", &cachelist);
9690Sstevel@tonic-gate 	/*
9701991Sheppo 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
9711991Sheppo 	 */
9721991Sheppo 	if (ncaches < 1) {
9731991Sheppo 		return (0);
9741991Sheppo 	}
9751991Sheppo 
9761991Sheppo 	for (i = 0; i < ncaches; i++) {
9771991Sheppo 		uint64_t local_assoc;
9781991Sheppo 		uint64_t local_size;
9791991Sheppo 		uint64_t local_lsize;
9801991Sheppo 
9811991Sheppo 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
9821991Sheppo 			continue;
9831991Sheppo 
9845078Sae112802 		if (cache_level != 2) continue;
9851991Sheppo 
9861991Sheppo 		/* If properties are missing from this cache ignore it */
9871991Sheppo 
9881991Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9891991Sheppo 		    "associativity", &local_assoc))) {
9901991Sheppo 			continue;
9911991Sheppo 		}
9921991Sheppo 
9931991Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9941991Sheppo 		    "size", &local_size))) {
9951991Sheppo 			continue;
9961991Sheppo 		}
9971991Sheppo 
9981991Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9991991Sheppo 		    "line-size", &local_lsize))) {
10001991Sheppo 			continue;
10011991Sheppo 		}
10021991Sheppo 
10031991Sheppo 		*associativity = local_assoc;
10041991Sheppo 		*size = local_size;
10051991Sheppo 		*linesize = local_lsize;
10065078Sae112802 		break;
10071991Sheppo 	}
10081991Sheppo 
10091991Sheppo 	md_free_scan_dag(mdp, &cachelist);
10101991Sheppo 
10115078Sae112802 	return ((cache_level == 2) ? 1 : 0);
10121991Sheppo }
10131991Sheppo 
10142531Snarayan 
10151991Sheppo /*
10162531Snarayan  * Set the broken_md_flag to 1 if the MD doesn't have
10172531Snarayan  * the domaining-enabled property in the platform node and the
10182531Snarayan  * platform uses the UltraSPARC-T1 cpu. This flag is used to
10192531Snarayan  * workaround some of the incorrect MD properties.
10201991Sheppo  */
10211991Sheppo static void
init_md_broken(md_t * mdp,mde_cookie_t * cpulist)10222531Snarayan init_md_broken(md_t *mdp, mde_cookie_t *cpulist)
10231991Sheppo {
10241991Sheppo 	int nrnode;
10251991Sheppo 	mde_cookie_t *platlist, rootnode;
10261991Sheppo 	uint64_t val = 0;
10272531Snarayan 	char *namebuf;
10282531Snarayan 	int namelen;
10291991Sheppo 
10301991Sheppo 	rootnode = md_root_node(mdp);
10311991Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
10322531Snarayan 	ASSERT(cpulist);
10331991Sheppo 
10342531Snarayan 	nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd",
10351991Sheppo 	    &platlist);
10361991Sheppo 
10372957Sjm22469 	if (nrnode < 1)
10382957Sjm22469 		cmn_err(CE_PANIC, "init_md_broken: platform node missing");
10391991Sheppo 
10402531Snarayan 	if (md_get_prop_data(mdp, cpulist[0],
10412531Snarayan 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
10422531Snarayan 		cmn_err(CE_PANIC, "init_md_broken: "
10432531Snarayan 		    "Cannot read 'compatible' property of 'cpu' node");
10442531Snarayan 	}
10450Sstevel@tonic-gate 
10462531Snarayan 	if (md_get_prop_val(mdp, platlist[0],
10474677Szx151605 	    "domaining-enabled", &val) == -1 &&
10482531Snarayan 	    strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0)
10491991Sheppo 		broken_md_flag = 1;
10501991Sheppo 
10511991Sheppo 	md_free_scan_dag(mdp, &platlist);
10520Sstevel@tonic-gate }
105311713SPavel.Tatashin@Sun.COM 
105412116SVikram.Hegde@Sun.COM #define	PLAT_MAX_IOALIASES	8
105512116SVikram.Hegde@Sun.COM 
105612116SVikram.Hegde@Sun.COM static plat_alias_t *plat_ioaliases;
105712116SVikram.Hegde@Sun.COM static uint64_t plat_num_ioaliases;
105812116SVikram.Hegde@Sun.COM 
105912116SVikram.Hegde@Sun.COM /*
106012116SVikram.Hegde@Sun.COM  * split the aliases property into its
106112116SVikram.Hegde@Sun.COM  * component strings for easy searching.
106212116SVikram.Hegde@Sun.COM  */
106312116SVikram.Hegde@Sun.COM static void
split_alias(plat_alias_t * pali,char * str)106412116SVikram.Hegde@Sun.COM split_alias(plat_alias_t *pali, char *str)
106512116SVikram.Hegde@Sun.COM {
106612116SVikram.Hegde@Sun.COM 	char *aliasv[PLAT_MAX_IOALIASES], *p;
106712116SVikram.Hegde@Sun.COM 	int i, duplen;
106812116SVikram.Hegde@Sun.COM 	char *dup;
106912116SVikram.Hegde@Sun.COM 
107012116SVikram.Hegde@Sun.COM 	/* skip leading space */
107112116SVikram.Hegde@Sun.COM 	str = dup = strdup(str);
107212116SVikram.Hegde@Sun.COM 	duplen = strlen(dup) + 1;
107312116SVikram.Hegde@Sun.COM 	str += strspn(str, " ");
107412116SVikram.Hegde@Sun.COM 	for (i = 0; *str != '\0'; str = p) {
107512116SVikram.Hegde@Sun.COM 
107612116SVikram.Hegde@Sun.COM 		p = strpbrk(str, " ");
107712116SVikram.Hegde@Sun.COM 		if (p != NULL) {
107812116SVikram.Hegde@Sun.COM 			*p++ = '\0';
107912116SVikram.Hegde@Sun.COM 		}
108012116SVikram.Hegde@Sun.COM 
108112116SVikram.Hegde@Sun.COM 		VERIFY(i < PLAT_MAX_IOALIASES);
108212116SVikram.Hegde@Sun.COM 		aliasv[i++] = strdup(str);
108312116SVikram.Hegde@Sun.COM 		if (p == NULL)
108412116SVikram.Hegde@Sun.COM 			break;
108512116SVikram.Hegde@Sun.COM 		p += strspn(p, " ");
108612116SVikram.Hegde@Sun.COM 	}
108712116SVikram.Hegde@Sun.COM 
108812116SVikram.Hegde@Sun.COM 	kmem_free(dup, duplen);
108912116SVikram.Hegde@Sun.COM 
109012116SVikram.Hegde@Sun.COM 	if (i == 0) {
109112116SVikram.Hegde@Sun.COM 		pali->pali_naliases = 0;
109212116SVikram.Hegde@Sun.COM 		pali->pali_aliases = NULL;
109312116SVikram.Hegde@Sun.COM 		return;
109412116SVikram.Hegde@Sun.COM 	}
109512116SVikram.Hegde@Sun.COM 
109612116SVikram.Hegde@Sun.COM 	pali->pali_naliases = i;
109712116SVikram.Hegde@Sun.COM 	pali->pali_aliases = kmem_alloc(i * sizeof (char *), KM_SLEEP);
109812116SVikram.Hegde@Sun.COM 	for (i = 0; i < pali->pali_naliases; i++) {
109912116SVikram.Hegde@Sun.COM 		pali->pali_aliases[i] = aliasv[i];
110012116SVikram.Hegde@Sun.COM 	}
110112116SVikram.Hegde@Sun.COM }
110212116SVikram.Hegde@Sun.COM 
110312116SVikram.Hegde@Sun.COM /*
110412116SVikram.Hegde@Sun.COM  * retrieve the ioalias info from the MD,
110512116SVikram.Hegde@Sun.COM  * and init the ioalias struct.
110612116SVikram.Hegde@Sun.COM  *
110712116SVikram.Hegde@Sun.COM  * NOTE: Assumes that the ioalias info does not change at runtime
110812116SVikram.Hegde@Sun.COM  * This routine is invoked only once at boot time.
110912116SVikram.Hegde@Sun.COM  *
111012116SVikram.Hegde@Sun.COM  * No lock needed as this is called at boot with a DDI lock held
111112116SVikram.Hegde@Sun.COM  */
111212116SVikram.Hegde@Sun.COM void
plat_ioaliases_init(void)111312116SVikram.Hegde@Sun.COM plat_ioaliases_init(void)
111412116SVikram.Hegde@Sun.COM {
111512116SVikram.Hegde@Sun.COM 	md_t *mdp;
111612116SVikram.Hegde@Sun.COM 	mde_cookie_t *ionodes, alinode;
111712116SVikram.Hegde@Sun.COM 	plat_alias_t *pali;
111812116SVikram.Hegde@Sun.COM 	int nio;
111912116SVikram.Hegde@Sun.COM 	int i;
112012116SVikram.Hegde@Sun.COM 	int err;
112112116SVikram.Hegde@Sun.COM 
112212116SVikram.Hegde@Sun.COM 	mdp = md_get_handle();
112312116SVikram.Hegde@Sun.COM 	if (mdp == NULL) {
112412116SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "no machine description (MD)");
112512116SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
112612116SVikram.Hegde@Sun.COM 	}
112712116SVikram.Hegde@Sun.COM 
112812116SVikram.Hegde@Sun.COM 	nio = md_alloc_scan_dag(mdp, md_root_node(mdp),
112912116SVikram.Hegde@Sun.COM 	    "ioaliases", "fwd", &ionodes);
113012116SVikram.Hegde@Sun.COM 
113112116SVikram.Hegde@Sun.COM 
113212116SVikram.Hegde@Sun.COM 	/* not all platforms support aliases */
113312116SVikram.Hegde@Sun.COM 	if (nio < 1) {
113412116SVikram.Hegde@Sun.COM 		(void) md_fini_handle(mdp);
113512116SVikram.Hegde@Sun.COM 		return;
113612116SVikram.Hegde@Sun.COM 	}
113712116SVikram.Hegde@Sun.COM 	if (nio > 1) {
113812116SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "multiple ioalias nodes in MD");
113912116SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
114012116SVikram.Hegde@Sun.COM 	}
114112116SVikram.Hegde@Sun.COM 
114212116SVikram.Hegde@Sun.COM 	alinode = ionodes[0];
114312116SVikram.Hegde@Sun.COM 	md_free_scan_dag(mdp, &ionodes);
114412116SVikram.Hegde@Sun.COM 
114512116SVikram.Hegde@Sun.COM 	nio = md_alloc_scan_dag(mdp, alinode, "ioalias", "fwd", &ionodes);
114612116SVikram.Hegde@Sun.COM 	if (nio <= 0) {
114712116SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "MD alias node has no aliases");
114812116SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
114912116SVikram.Hegde@Sun.COM 	}
115012116SVikram.Hegde@Sun.COM 
115112116SVikram.Hegde@Sun.COM 	plat_num_ioaliases = nio;
115212116SVikram.Hegde@Sun.COM 	plat_ioaliases = pali = kmem_zalloc(nio * sizeof (plat_alias_t),
115312116SVikram.Hegde@Sun.COM 	    KM_SLEEP);
115412116SVikram.Hegde@Sun.COM 
115512116SVikram.Hegde@Sun.COM 	/*
115612116SVikram.Hegde@Sun.COM 	 * Each ioalias map will have a composite property of
115712116SVikram.Hegde@Sun.COM 	 * aliases and the current valid path.
115812116SVikram.Hegde@Sun.COM 	 */
115912116SVikram.Hegde@Sun.COM 	for (i = 0; i < nio; i++) {
116012116SVikram.Hegde@Sun.COM 		char *str;
116112116SVikram.Hegde@Sun.COM 
116212116SVikram.Hegde@Sun.COM 		err = md_get_prop_str(mdp, ionodes[i], "current", &str);
116312116SVikram.Hegde@Sun.COM 		if (err != 0) {
116412116SVikram.Hegde@Sun.COM 			cmn_err(CE_PANIC, "malformed ioalias node");
116512116SVikram.Hegde@Sun.COM 			/*NOTREACHED*/
116612116SVikram.Hegde@Sun.COM 		}
116712116SVikram.Hegde@Sun.COM 		pali->pali_current = strdup(str);
116812116SVikram.Hegde@Sun.COM 
116912116SVikram.Hegde@Sun.COM 		err = md_get_prop_str(mdp, ionodes[i], "aliases", &str);
117012116SVikram.Hegde@Sun.COM 		if (err != 0) {
117112116SVikram.Hegde@Sun.COM 			cmn_err(CE_PANIC, "malformed aliases");
117212116SVikram.Hegde@Sun.COM 			/*NOTREACHED*/
117312116SVikram.Hegde@Sun.COM 		}
1174*12701SJan.Setje-Eilers@Sun.COM 		DDI_MP_DBG((CE_NOTE, "path: %s aliases %s",
1175*12701SJan.Setje-Eilers@Sun.COM 		    pali->pali_current, str));
1176*12701SJan.Setje-Eilers@Sun.COM 
117712116SVikram.Hegde@Sun.COM 		split_alias(pali, str);
117812116SVikram.Hegde@Sun.COM 		pali++;
117912116SVikram.Hegde@Sun.COM 	}
118012116SVikram.Hegde@Sun.COM 
118112116SVikram.Hegde@Sun.COM 	md_free_scan_dag(mdp, &ionodes);
118212116SVikram.Hegde@Sun.COM 
118312116SVikram.Hegde@Sun.COM 	/*
118412116SVikram.Hegde@Sun.COM 	 * Register the io-aliases array with the DDI framework
118512116SVikram.Hegde@Sun.COM 	 * The DDI framework assumes that this array and its contents
118612116SVikram.Hegde@Sun.COM 	 * will not change post-register. The DDI framework will
118712116SVikram.Hegde@Sun.COM 	 * cache this array and is free to access this array at
118812116SVikram.Hegde@Sun.COM 	 * any time without any locks.
118912116SVikram.Hegde@Sun.COM 	 */
119012116SVikram.Hegde@Sun.COM 	ddi_register_aliases(plat_ioaliases, plat_num_ioaliases);
119112116SVikram.Hegde@Sun.COM 
119212116SVikram.Hegde@Sun.COM 	(void) md_fini_handle(mdp);
119312116SVikram.Hegde@Sun.COM }
119412116SVikram.Hegde@Sun.COM 
119511713SPavel.Tatashin@Sun.COM /*
119611713SPavel.Tatashin@Sun.COM  * Number of bits forming a valid context for use in a sun4v TTE and the MMU
119711713SPavel.Tatashin@Sun.COM  * context registers. Sun4v defines the minimum default value to be 13 if this
119811713SPavel.Tatashin@Sun.COM  * property is not specified in a cpu node in machine descriptor graph.
119911713SPavel.Tatashin@Sun.COM  */
120011713SPavel.Tatashin@Sun.COM #define	MMU_INFO_CTXBITS_MIN		13
120111713SPavel.Tatashin@Sun.COM 
120211713SPavel.Tatashin@Sun.COM /* Convert context bits to number of contexts */
120311713SPavel.Tatashin@Sun.COM #define	MMU_INFO_BNCTXS(nbits)		((uint_t)(1u<<(nbits)))
120411713SPavel.Tatashin@Sun.COM 
120511713SPavel.Tatashin@Sun.COM /*
120611713SPavel.Tatashin@Sun.COM  * Read machine descriptor and load TLB to CPU mappings.
120711713SPavel.Tatashin@Sun.COM  * Returned values: cpuid2pset[NCPU], nctxs[NCPU], md_gen
120811713SPavel.Tatashin@Sun.COM  * - cpuid2pset is initialized so it can convert cpuids to processor set of CPUs
120911713SPavel.Tatashin@Sun.COM  *   that are shared between TLBs.
121011713SPavel.Tatashin@Sun.COM  * - nctxs is initialized to number of contexts for each CPU
121111713SPavel.Tatashin@Sun.COM  * - md_gen is set to generation number of machine descriptor from which this
121211713SPavel.Tatashin@Sun.COM  *   data was.
121311713SPavel.Tatashin@Sun.COM  * Return: zero on success.
121411713SPavel.Tatashin@Sun.COM  */
121511713SPavel.Tatashin@Sun.COM static int
load_tlb_cpu_mappings(cpuset_t ** cpuid2pset,uint_t * nctxs,uint64_t * md_gen)121611713SPavel.Tatashin@Sun.COM load_tlb_cpu_mappings(cpuset_t **cpuid2pset, uint_t *nctxs, uint64_t *md_gen)
121711713SPavel.Tatashin@Sun.COM {
121811713SPavel.Tatashin@Sun.COM 	mde_str_cookie_t cpu_sc, bck_sc;
121911713SPavel.Tatashin@Sun.COM 	int		tlbs_idx, cp_idx;
122011713SPavel.Tatashin@Sun.COM 	mde_cookie_t	root;
122111713SPavel.Tatashin@Sun.COM 	md_t		*mdp = NULL;
122211713SPavel.Tatashin@Sun.COM 	mde_cookie_t	*tlbs = NULL;
122311713SPavel.Tatashin@Sun.COM 	mde_cookie_t	*cp = NULL;
122411713SPavel.Tatashin@Sun.COM 	uint64_t	*cpids = NULL;
122511713SPavel.Tatashin@Sun.COM 	uint64_t	nbit;
122611713SPavel.Tatashin@Sun.COM 	int		ntlbs;
122711713SPavel.Tatashin@Sun.COM 	int		ncp;
122811713SPavel.Tatashin@Sun.COM 	int		retval = 1;
122911713SPavel.Tatashin@Sun.COM 	cpuset_t	*ppset;
123011713SPavel.Tatashin@Sun.COM 
123111713SPavel.Tatashin@Sun.COM 	/* get MD handle, and string cookies for cpu and back nodes */
123211713SPavel.Tatashin@Sun.COM 	if ((mdp = md_get_handle()) == NULL ||
123311713SPavel.Tatashin@Sun.COM 	    (cpu_sc = md_find_name(mdp, "cpu")) == MDE_INVAL_STR_COOKIE ||
123411713SPavel.Tatashin@Sun.COM 	    (bck_sc = md_find_name(mdp, "back")) == MDE_INVAL_STR_COOKIE)
123511713SPavel.Tatashin@Sun.COM 		goto cleanup;
123611713SPavel.Tatashin@Sun.COM 
123711713SPavel.Tatashin@Sun.COM 	/* set generation number of current MD handle */
123811713SPavel.Tatashin@Sun.COM 	*md_gen = md_get_gen(mdp);
123911713SPavel.Tatashin@Sun.COM 
124011713SPavel.Tatashin@Sun.COM 	/* Find root element, and search for all TLBs in MD */
124111713SPavel.Tatashin@Sun.COM 	if ((root = md_root_node(mdp)) == MDE_INVAL_ELEM_COOKIE ||
124211713SPavel.Tatashin@Sun.COM 	    (ntlbs = md_alloc_scan_dag(mdp, root, "tlb", "fwd", &tlbs)) <= 0)
124311713SPavel.Tatashin@Sun.COM 		goto cleanup;
124411713SPavel.Tatashin@Sun.COM 
124511713SPavel.Tatashin@Sun.COM 	cp = kmem_alloc(sizeof (mde_cookie_t) * NCPU, KM_SLEEP);
124611713SPavel.Tatashin@Sun.COM 	cpids = kmem_alloc(sizeof (uint64_t) * NCPU, KM_SLEEP);
124711713SPavel.Tatashin@Sun.COM 
124811713SPavel.Tatashin@Sun.COM 	/*
124911713SPavel.Tatashin@Sun.COM 	 * Build processor sets, one per possible context domain.  For each tlb,
125011713SPavel.Tatashin@Sun.COM 	 * search for connected CPUs.  If any CPU is already in a set, then add
125111713SPavel.Tatashin@Sun.COM 	 * all the TLB's CPUs to that set.  Otherwise, create and populate a new
125211713SPavel.Tatashin@Sun.COM 	 * pset.  Thus, a single pset is built to represent multiple TLBs if
125311713SPavel.Tatashin@Sun.COM 	 * they have CPUs in common.
125411713SPavel.Tatashin@Sun.COM 	 */
125511713SPavel.Tatashin@Sun.COM 	for (tlbs_idx = 0; tlbs_idx < ntlbs; tlbs_idx++) {
125611713SPavel.Tatashin@Sun.COM 		ncp = md_scan_dag(mdp, tlbs[tlbs_idx], cpu_sc, bck_sc, cp);
125711713SPavel.Tatashin@Sun.COM 		if (ncp < 0)
125811713SPavel.Tatashin@Sun.COM 			goto cleanup;
125911713SPavel.Tatashin@Sun.COM 		else if (ncp == 0)
126011713SPavel.Tatashin@Sun.COM 			continue;
126111713SPavel.Tatashin@Sun.COM 
126211713SPavel.Tatashin@Sun.COM 		/* Get the id and number of contexts for each cpu */
126311713SPavel.Tatashin@Sun.COM 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
126411713SPavel.Tatashin@Sun.COM 			mde_cookie_t c = cp[cp_idx];
126511713SPavel.Tatashin@Sun.COM 
126611713SPavel.Tatashin@Sun.COM 			if (md_get_prop_val(mdp, c, "id", &cpids[cp_idx]))
126711713SPavel.Tatashin@Sun.COM 				goto cleanup;
126811713SPavel.Tatashin@Sun.COM 			if (md_get_prop_val(mdp, c, "mmu-#context-bits", &nbit))
126911713SPavel.Tatashin@Sun.COM 				nbit = MMU_INFO_CTXBITS_MIN;
127011713SPavel.Tatashin@Sun.COM 			nctxs[cpids[cp_idx]] = MMU_INFO_BNCTXS(nbit);
127111713SPavel.Tatashin@Sun.COM 		}
127211713SPavel.Tatashin@Sun.COM 
127311713SPavel.Tatashin@Sun.COM 		/*
127411713SPavel.Tatashin@Sun.COM 		 * If a CPU is already in a set as shown by cpuid2pset[], then
127511713SPavel.Tatashin@Sun.COM 		 * use that set.
127611713SPavel.Tatashin@Sun.COM 		 */
127711713SPavel.Tatashin@Sun.COM 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
127811713SPavel.Tatashin@Sun.COM 			ASSERT(cpids[cp_idx] < NCPU);
127911713SPavel.Tatashin@Sun.COM 			ppset = cpuid2pset[cpids[cp_idx]];
128011713SPavel.Tatashin@Sun.COM 			if (ppset != NULL)
128111713SPavel.Tatashin@Sun.COM 				break;
128211713SPavel.Tatashin@Sun.COM 		}
128311713SPavel.Tatashin@Sun.COM 
128411713SPavel.Tatashin@Sun.COM 		/* No CPU has a set. Create a new one. */
128511713SPavel.Tatashin@Sun.COM 		if (ppset == NULL) {
128611713SPavel.Tatashin@Sun.COM 			ppset = kmem_alloc(sizeof (cpuset_t), KM_SLEEP);
128711713SPavel.Tatashin@Sun.COM 			CPUSET_ZERO(*ppset);
128811713SPavel.Tatashin@Sun.COM 		}
128911713SPavel.Tatashin@Sun.COM 
129011713SPavel.Tatashin@Sun.COM 		/* Add every CPU to the set, and record the set assignment. */
129111713SPavel.Tatashin@Sun.COM 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
129211713SPavel.Tatashin@Sun.COM 			cpuid2pset[cpids[cp_idx]] = ppset;
129311713SPavel.Tatashin@Sun.COM 			CPUSET_ADD(*ppset, cpids[cp_idx]);
129411713SPavel.Tatashin@Sun.COM 		}
129511713SPavel.Tatashin@Sun.COM 	}
129611713SPavel.Tatashin@Sun.COM 
129711713SPavel.Tatashin@Sun.COM 	retval = 0;
129811713SPavel.Tatashin@Sun.COM 
129911713SPavel.Tatashin@Sun.COM cleanup:
130011713SPavel.Tatashin@Sun.COM 	if (tlbs != NULL)
130111713SPavel.Tatashin@Sun.COM 		md_free_scan_dag(mdp, &tlbs);
130211713SPavel.Tatashin@Sun.COM 	if (cp != NULL)
130311713SPavel.Tatashin@Sun.COM 		kmem_free(cp, sizeof (mde_cookie_t) * NCPU);
130411713SPavel.Tatashin@Sun.COM 	if (cpids != NULL)
130511713SPavel.Tatashin@Sun.COM 		kmem_free(cpids, sizeof (uint64_t) * NCPU);
130611713SPavel.Tatashin@Sun.COM 	if (mdp != NULL)
130711713SPavel.Tatashin@Sun.COM 		(void) md_fini_handle(mdp);
130811713SPavel.Tatashin@Sun.COM 
130911713SPavel.Tatashin@Sun.COM 	return (retval);
131011713SPavel.Tatashin@Sun.COM }
131111713SPavel.Tatashin@Sun.COM 
131211713SPavel.Tatashin@Sun.COM /*
131311713SPavel.Tatashin@Sun.COM  * Return MMU info based on cpuid.
131411713SPavel.Tatashin@Sun.COM  *
131511713SPavel.Tatashin@Sun.COM  * Algorithm:
131611713SPavel.Tatashin@Sun.COM  * Read machine descriptor and find all CPUs that share the same TLB with CPU
131711713SPavel.Tatashin@Sun.COM  * specified by cpuid. Go through found CPUs and see if any one of them already
131811713SPavel.Tatashin@Sun.COM  * has MMU index, if so, set index based on that value. If CPU does not share
131911713SPavel.Tatashin@Sun.COM  * TLB with any other CPU or if none of those CPUs has mmu_ctx pointer, find the
132011713SPavel.Tatashin@Sun.COM  * smallest available MMU index and give it to current CPU. If no available
132111713SPavel.Tatashin@Sun.COM  * domain, perform a round robin, and start assigning from the beginning.
132211713SPavel.Tatashin@Sun.COM  *
132311713SPavel.Tatashin@Sun.COM  * For optimization reasons, this function uses a cache to store all TLB to CPU
132411713SPavel.Tatashin@Sun.COM  * mappings, and updates them only when machine descriptor graph is changed.
132511713SPavel.Tatashin@Sun.COM  * Because of this, and because we search MMU table for smallest index id, this
132611713SPavel.Tatashin@Sun.COM  * function needs to be serialized which is protected by cpu_lock.
132711713SPavel.Tatashin@Sun.COM  */
132811713SPavel.Tatashin@Sun.COM void
plat_cpuid_to_mmu_ctx_info(processorid_t cpuid,mmu_ctx_info_t * info)132911713SPavel.Tatashin@Sun.COM plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info)
133011713SPavel.Tatashin@Sun.COM {
133111713SPavel.Tatashin@Sun.COM 	static cpuset_t	**cpuid2pset = NULL;
133211713SPavel.Tatashin@Sun.COM 	static uint_t	*nctxs;
133311713SPavel.Tatashin@Sun.COM 	static uint_t	next_domain = 0;
133411713SPavel.Tatashin@Sun.COM 	static uint64_t	md_gen = MDESC_INVAL_GEN;
133511713SPavel.Tatashin@Sun.COM 	uint64_t	current_gen;
133611713SPavel.Tatashin@Sun.COM 	int		idx;
133711713SPavel.Tatashin@Sun.COM 	cpuset_t	cpuid_pset;
133811713SPavel.Tatashin@Sun.COM 	processorid_t	id;
133911713SPavel.Tatashin@Sun.COM 	cpu_t		*cp;
134011713SPavel.Tatashin@Sun.COM 
134111713SPavel.Tatashin@Sun.COM 	ASSERT(MUTEX_HELD(&cpu_lock));
134211713SPavel.Tatashin@Sun.COM 
134311713SPavel.Tatashin@Sun.COM 	current_gen = md_get_current_gen();
134411713SPavel.Tatashin@Sun.COM 
134511713SPavel.Tatashin@Sun.COM 	/*
134611713SPavel.Tatashin@Sun.COM 	 * Load TLB CPU mappings only if MD generation has changed, FW that do
134711713SPavel.Tatashin@Sun.COM 	 * not provide generation number, always return MDESC_INVAL_GEN, and as
134811713SPavel.Tatashin@Sun.COM 	 * result MD is read here only once on such machines: when cpuid2pset is
134911713SPavel.Tatashin@Sun.COM 	 * NULL
135011713SPavel.Tatashin@Sun.COM 	 */
135111713SPavel.Tatashin@Sun.COM 	if (current_gen != md_gen || cpuid2pset == NULL) {
135211713SPavel.Tatashin@Sun.COM 		if (cpuid2pset == NULL) {
135311713SPavel.Tatashin@Sun.COM 			cpuid2pset = kmem_zalloc(sizeof (cpuset_t *) * NCPU,
135411713SPavel.Tatashin@Sun.COM 			    KM_SLEEP);
135511713SPavel.Tatashin@Sun.COM 			nctxs = kmem_alloc(sizeof (uint_t) * NCPU, KM_SLEEP);
135611713SPavel.Tatashin@Sun.COM 		} else {
135711713SPavel.Tatashin@Sun.COM 			/* clean cpuid2pset[NCPU], before loading new values */
135811713SPavel.Tatashin@Sun.COM 			for (idx = 0; idx < NCPU; idx++) {
135911713SPavel.Tatashin@Sun.COM 				cpuset_t *pset = cpuid2pset[idx];
136011713SPavel.Tatashin@Sun.COM 
136111713SPavel.Tatashin@Sun.COM 				if (pset != NULL) {
136211713SPavel.Tatashin@Sun.COM 					for (;;) {
136311713SPavel.Tatashin@Sun.COM 						CPUSET_FIND(*pset, id);
136411713SPavel.Tatashin@Sun.COM 						if (id == CPUSET_NOTINSET)
136511713SPavel.Tatashin@Sun.COM 							break;
136611713SPavel.Tatashin@Sun.COM 						CPUSET_DEL(*pset, id);
136711713SPavel.Tatashin@Sun.COM 						ASSERT(id < NCPU);
136811713SPavel.Tatashin@Sun.COM 						cpuid2pset[id] = NULL;
136911713SPavel.Tatashin@Sun.COM 					}
137011713SPavel.Tatashin@Sun.COM 					ASSERT(cpuid2pset[idx] == NULL);
137111713SPavel.Tatashin@Sun.COM 					kmem_free(pset, sizeof (cpuset_t));
137211713SPavel.Tatashin@Sun.COM 				}
137311713SPavel.Tatashin@Sun.COM 			}
137411713SPavel.Tatashin@Sun.COM 		}
137511713SPavel.Tatashin@Sun.COM 
137611713SPavel.Tatashin@Sun.COM 		if (load_tlb_cpu_mappings(cpuid2pset, nctxs, &md_gen))
137711713SPavel.Tatashin@Sun.COM 			goto error_panic;
137811713SPavel.Tatashin@Sun.COM 	}
137911713SPavel.Tatashin@Sun.COM 
138011713SPavel.Tatashin@Sun.COM 	info->mmu_nctxs = nctxs[cpuid];
138111713SPavel.Tatashin@Sun.COM 
138211713SPavel.Tatashin@Sun.COM 	if (cpuid2pset[cpuid] == NULL)
138311713SPavel.Tatashin@Sun.COM 		goto error_panic;
138411713SPavel.Tatashin@Sun.COM 
138511713SPavel.Tatashin@Sun.COM 	cpuid_pset = *cpuid2pset[cpuid];
138611713SPavel.Tatashin@Sun.COM 	CPUSET_DEL(cpuid_pset, cpuid);
138711713SPavel.Tatashin@Sun.COM 
138811713SPavel.Tatashin@Sun.COM 	/* Search for a processor in the same TLB pset with MMU context */
138911713SPavel.Tatashin@Sun.COM 	for (;;) {
139011713SPavel.Tatashin@Sun.COM 		CPUSET_FIND(cpuid_pset, id);
139111713SPavel.Tatashin@Sun.COM 
139211713SPavel.Tatashin@Sun.COM 		if (id == CPUSET_NOTINSET)
139311713SPavel.Tatashin@Sun.COM 			break;
139411713SPavel.Tatashin@Sun.COM 
139511713SPavel.Tatashin@Sun.COM 		ASSERT(id < NCPU);
139611713SPavel.Tatashin@Sun.COM 		cp = cpu[id];
139711713SPavel.Tatashin@Sun.COM 		if (cp != NULL && CPU_MMU_CTXP(cp) != NULL) {
139811713SPavel.Tatashin@Sun.COM 			info->mmu_idx = CPU_MMU_IDX(cp);
139911713SPavel.Tatashin@Sun.COM 
140011713SPavel.Tatashin@Sun.COM 			return;
140111713SPavel.Tatashin@Sun.COM 		}
140211713SPavel.Tatashin@Sun.COM 		CPUSET_DEL(cpuid_pset, id);
140311713SPavel.Tatashin@Sun.COM 	}
140411713SPavel.Tatashin@Sun.COM 
140511713SPavel.Tatashin@Sun.COM 	/*
140611713SPavel.Tatashin@Sun.COM 	 * No CPU in the TLB pset has a context domain yet.
140711713SPavel.Tatashin@Sun.COM 	 * Use next_domain if available, or search for an unused domain, or
140811713SPavel.Tatashin@Sun.COM 	 * overload next_domain, in that order.  Overloading is necessary when
140911713SPavel.Tatashin@Sun.COM 	 * the number of TLB psets is greater than max_mmu_ctxdoms.
141011713SPavel.Tatashin@Sun.COM 	 */
141111713SPavel.Tatashin@Sun.COM 	idx = next_domain;
141211713SPavel.Tatashin@Sun.COM 
141311713SPavel.Tatashin@Sun.COM 	if (mmu_ctxs_tbl[idx] != NULL) {
141411713SPavel.Tatashin@Sun.COM 		for (idx = 0; idx < max_mmu_ctxdoms; idx++)
141511713SPavel.Tatashin@Sun.COM 			if (mmu_ctxs_tbl[idx] == NULL)
141611713SPavel.Tatashin@Sun.COM 				break;
141711713SPavel.Tatashin@Sun.COM 		if (idx == max_mmu_ctxdoms) {
141811713SPavel.Tatashin@Sun.COM 			/* overload next_domain */
141911713SPavel.Tatashin@Sun.COM 			idx = next_domain;
142011713SPavel.Tatashin@Sun.COM 
142111713SPavel.Tatashin@Sun.COM 			if (info->mmu_nctxs < sfmmu_ctxdom_nctxs(idx))
142211713SPavel.Tatashin@Sun.COM 				cmn_err(CE_PANIC, "max_mmu_ctxdoms is too small"
142311713SPavel.Tatashin@Sun.COM 				    " to support CPUs with different nctxs");
142411713SPavel.Tatashin@Sun.COM 		}
142511713SPavel.Tatashin@Sun.COM 	}
142611713SPavel.Tatashin@Sun.COM 
142711713SPavel.Tatashin@Sun.COM 	info->mmu_idx = idx;
142811713SPavel.Tatashin@Sun.COM 	next_domain = (idx + 1) % max_mmu_ctxdoms;
142911713SPavel.Tatashin@Sun.COM 
143011713SPavel.Tatashin@Sun.COM 	return;
143111713SPavel.Tatashin@Sun.COM 
143211713SPavel.Tatashin@Sun.COM error_panic:
143311713SPavel.Tatashin@Sun.COM 	cmn_err(CE_PANIC, "!cpu%d: failed to get MMU CTX domain index", cpuid);
143411713SPavel.Tatashin@Sun.COM }
1435