xref: /illumos-gate/usr/src/uts/sun4v/os/fillsysinfo.c (revision de710d24)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2294c894bbSVikram Hegde  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/errno.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/cpu.h>
297c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
307c478bd9Sstevel@tonic-gate #include <sys/clock.h>
317c478bd9Sstevel@tonic-gate #include <sys/promif.h>
327c478bd9Sstevel@tonic-gate #include <sys/promimpl.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
357c478bd9Sstevel@tonic-gate #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
387c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
397c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
407c478bd9Sstevel@tonic-gate #include <sys/cmp.h>
417c478bd9Sstevel@tonic-gate #include <sys/async.h>
427c478bd9Sstevel@tonic-gate #include <vm/page.h>
431ae08745Sheppo #include <vm/hat_sfmmu.h>
441ae08745Sheppo #include <sys/sysmacros.h>
451ae08745Sheppo #include <sys/mach_descrip.h>
461ae08745Sheppo #include <sys/mdesc.h>
471ae08745Sheppo #include <sys/archsystm.h>
481ae08745Sheppo #include <sys/error.h>
491ae08745Sheppo #include <sys/mmu.h>
501ae08745Sheppo #include <sys/bitmap.h>
514bac2208Snarayan #include <sys/intreg.h>
5294c894bbSVikram Hegde #include <sys/instance.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU];
557c478bd9Sstevel@tonic-gate 
561ae08745Sheppo uint64_t cpu_q_entries;
571ae08745Sheppo uint64_t dev_q_entries;
581ae08745Sheppo uint64_t cpu_rq_entries;
591ae08745Sheppo uint64_t cpu_nrq_entries;
60aaa10e67Sha uint64_t ncpu_guest_max;
611ae08745Sheppo 
621ae08745Sheppo void fill_cpu(md_t *, mde_cookie_t);
631ae08745Sheppo 
641ae08745Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t);
6505d3dc4bSpaulsan static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t);
6605d3dc4bSpaulsan static uint64_t	get_mmu_shcontexts(md_t *, mde_cookie_t);
671ae08745Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t);
681ae08745Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **);
694bac2208Snarayan static void init_md_broken(md_t *, mde_cookie_t *);
701ae08745Sheppo static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *,
711ae08745Sheppo     uint64_t *);
722f0fcb93SJason Beloro static void get_hwcaps(md_t *, mde_cookie_t);
732c5124a1SPrashanth Sreenivasa static void get_weakest_mem_model(md_t *, mde_cookie_t);
741ae08745Sheppo static void get_q_sizes(md_t *, mde_cookie_t);
751ae08745Sheppo static void get_va_bits(md_t *, mde_cookie_t);
769853d9e8SJason Beloro static size_t get_ra_limit(md_t *, mde_cookie_t);
77575a7426Spt static int get_l2_cache_node_count(md_t *);
782f0fcb93SJason Beloro static unsigned long names2bits(char *tokens, size_t tokenslen,
792f0fcb93SJason Beloro     char *bit_formatter, char *warning);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate uint64_t	system_clock_freq;
827c478bd9Sstevel@tonic-gate uint_t		niommu_tsbs = 0;
837c478bd9Sstevel@tonic-gate 
84575a7426Spt static int n_l2_caches = 0;
85575a7426Spt 
86fedab560Sae /* prevent compilation with VAC defined */
87fedab560Sae #ifdef VAC
88fedab560Sae #error "The sun4v architecture does not support VAC"
89fedab560Sae #endif
90fedab560Sae 
91fedab560Sae #define	S_VAC_SIZE	MMU_PAGESIZE
92fedab560Sae #define	S_VAC_SHIFT	MMU_PAGESHIFT
93fedab560Sae 
94fedab560Sae int		vac_size = S_VAC_SIZE;
95fedab560Sae uint_t		vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1);
96fedab560Sae int		vac_shift = S_VAC_SHIFT;
97fedab560Sae uintptr_t	shm_alignment = S_VAC_SIZE;
98fedab560Sae 
991ae08745Sheppo void
map_wellknown_devices()1001ae08745Sheppo map_wellknown_devices()
1011ae08745Sheppo {
1021ae08745Sheppo }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate void
fill_cpu(md_t * mdp,mde_cookie_t cpuc)1051ae08745Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc)
1067c478bd9Sstevel@tonic-gate {
1071ae08745Sheppo 	struct cpu_node *cpunode;
1081ae08745Sheppo 	uint64_t cpuid;
1091ae08745Sheppo 	uint64_t clk_freq;
1101ae08745Sheppo 	char *namebuf;
1111ae08745Sheppo 	char *namebufp;
1121ae08745Sheppo 	int namelen;
1131ae08745Sheppo 	uint64_t associativity = 0, linesize = 0, size = 0;
1141ae08745Sheppo 
1151ae08745Sheppo 	if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) {
1161ae08745Sheppo 		return;
1171ae08745Sheppo 	}
1187c478bd9Sstevel@tonic-gate 
1194bac2208Snarayan 	/* All out-of-range cpus will be stopped later. */
1201ae08745Sheppo 	if (cpuid >= NCPU) {
1211ae08745Sheppo 		cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - "
1224bac2208Snarayan 		    "cpu excluded from configuration\n", cpuid);
1231ae08745Sheppo 
1241ae08745Sheppo 		return;
1251ae08745Sheppo 	}
1261ae08745Sheppo 
1271ae08745Sheppo 	cpunode = &cpunodes[cpuid];
1281ae08745Sheppo 	cpunode->cpuid = (int)cpuid;
1291ae08745Sheppo 	cpunode->device_id = cpuid;
1301ae08745Sheppo 
1311ae08745Sheppo 	if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI))
1321ae08745Sheppo 		(void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI);
1331ae08745Sheppo 
1341ae08745Sheppo 	if (md_get_prop_data(mdp, cpuc,
1351ae08745Sheppo 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
1361ae08745Sheppo 		cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible "
1371ae08745Sheppo 		    "property");
1381ae08745Sheppo 	}
1391ae08745Sheppo 	namebufp = namebuf;
1401ae08745Sheppo 	if (strncmp(namebufp, "SUNW,", 5) == 0)
1411ae08745Sheppo 		namebufp += 5;
1421ae08745Sheppo 	if (strlen(namebufp) > sizeof (cpunode->name))
1431ae08745Sheppo 		cmn_err(CE_PANIC, "Compatible property too big to "
1441ae08745Sheppo 		    "fit into the cpunode name buffer");
1451ae08745Sheppo 	(void) strcpy(cpunode->name, namebufp);
1461ae08745Sheppo 
1471ae08745Sheppo 	if (md_get_prop_val(mdp, cpuc,
1481ae08745Sheppo 	    "clock-frequency", &clk_freq)) {
1491ae08745Sheppo 			clk_freq = 0;
1501ae08745Sheppo 	}
1511ae08745Sheppo 	cpunode->clock_freq = clk_freq;
1521ae08745Sheppo 
1531ae08745Sheppo 	ASSERT(cpunode->clock_freq != 0);
1547c478bd9Sstevel@tonic-gate 	/*
1551ae08745Sheppo 	 * Compute scaling factor based on rate of %tick. This is used
1561ae08745Sheppo 	 * to convert from ticks derived from %tick to nanoseconds. See
1571ae08745Sheppo 	 * comment in sun4u/sys/clock.h for details.
1587c478bd9Sstevel@tonic-gate 	 */
1591ae08745Sheppo 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
1601ae08745Sheppo 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1631ae08745Sheppo 	 * The nodeid is not used in sun4v at all. Setting it
1641ae08745Sheppo 	 * to positive value to make starting of slave CPUs
1651ae08745Sheppo 	 * code happy.
1667c478bd9Sstevel@tonic-gate 	 */
1671ae08745Sheppo 	cpunode->nodeid = cpuid + 1;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	/*
1701ae08745Sheppo 	 * Obtain the L2 cache information from MD.
1711ae08745Sheppo 	 * If "Cache" node exists, then set L2 cache properties
1721ae08745Sheppo 	 * as read from MD.
1731ae08745Sheppo 	 * If node does not exists, then set the L2 cache properties
1741ae08745Sheppo 	 * in individual CPU module.
1757c478bd9Sstevel@tonic-gate 	 */
1761ae08745Sheppo 	if ((!get_l2_cache_info(mdp, cpuc,
1771ae08745Sheppo 	    &associativity, &size, &linesize)) ||
1781ae08745Sheppo 	    associativity == 0 || size == 0 || linesize == 0) {
1791ae08745Sheppo 		cpu_fiximp(cpunode);
1801ae08745Sheppo 	} else {
1811ae08745Sheppo 		/*
1821ae08745Sheppo 		 * Do not expect L2 cache properties to be bigger
1831ae08745Sheppo 		 * than 32-bit quantity.
1841ae08745Sheppo 		 */
1851ae08745Sheppo 		cpunode->ecache_associativity = (int)associativity;
1861ae08745Sheppo 		cpunode->ecache_size = (int)size;
1871ae08745Sheppo 		cpunode->ecache_linesize = (int)linesize;
1887c478bd9Sstevel@tonic-gate 	}
1891ae08745Sheppo 
1901ae08745Sheppo 	cpunode->ecache_setsize =
1911ae08745Sheppo 	    cpunode->ecache_size / cpunode->ecache_associativity;
1921ae08745Sheppo 
19359ac0c16Sdavemq 	/*
19459ac0c16Sdavemq 	 * Initialize the mapping for exec unit, chip and core.
19559ac0c16Sdavemq 	 */
1961ae08745Sheppo 	cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND;
19759ac0c16Sdavemq 	cpunode->l2_cache_mapping = NO_MAPPING_FOUND;
19859ac0c16Sdavemq 	cpunode->core_mapping = NO_CORE_MAPPING_FOUND;
1991ae08745Sheppo 
2001ae08745Sheppo 	if (ecache_setsize == 0)
2011ae08745Sheppo 		ecache_setsize = cpunode->ecache_setsize;
2021ae08745Sheppo 	if (ecache_alignsize == 0)
2031ae08745Sheppo 		ecache_alignsize = cpunode->ecache_linesize;
2041ae08745Sheppo 
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2071ae08745Sheppo void
empty_cpu(int cpuid)2081ae08745Sheppo empty_cpu(int cpuid)
2097c478bd9Sstevel@tonic-gate {
2101ae08745Sheppo 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
2111ae08745Sheppo }
2127c478bd9Sstevel@tonic-gate 
21359ac0c16Sdavemq /*
21459ac0c16Sdavemq  * Use L2 cache node to derive the chip mapping.
21559ac0c16Sdavemq  */
21659ac0c16Sdavemq void
setup_chip_mappings(md_t * mdp)21759ac0c16Sdavemq setup_chip_mappings(md_t *mdp)
21859ac0c16Sdavemq {
2192f0fcb93SJason Beloro 	int ncache, ncpu;
22059ac0c16Sdavemq 	mde_cookie_t *node, *cachelist;
22159ac0c16Sdavemq 	int i, j;
22259ac0c16Sdavemq 	processorid_t cpuid;
22359ac0c16Sdavemq 	int idx = 0;
22459ac0c16Sdavemq 
22559ac0c16Sdavemq 	ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache",
22659ac0c16Sdavemq 	    "fwd", &cachelist);
22759ac0c16Sdavemq 
22859ac0c16Sdavemq 	/*
22959ac0c16Sdavemq 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
23059ac0c16Sdavemq 	 */
23159ac0c16Sdavemq 	if (ncache < 1) {
23259ac0c16Sdavemq 		return;
23359ac0c16Sdavemq 	}
23459ac0c16Sdavemq 
23559ac0c16Sdavemq 	for (i = 0; i < ncache; i++) {
23659ac0c16Sdavemq 		uint64_t cache_level;
23759ac0c16Sdavemq 		uint64_t lcpuid;
23859ac0c16Sdavemq 
23959ac0c16Sdavemq 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
24059ac0c16Sdavemq 			continue;
24159ac0c16Sdavemq 
24259ac0c16Sdavemq 		if (cache_level != 2)
24359ac0c16Sdavemq 			continue;
24459ac0c16Sdavemq 
24559ac0c16Sdavemq 		/*
24659ac0c16Sdavemq 		 * Found a l2 cache node. Find out the cpu nodes it
24759ac0c16Sdavemq 		 * points to.
24859ac0c16Sdavemq 		 */
24959ac0c16Sdavemq 		ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu",
25059ac0c16Sdavemq 		    "back", &node);
25159ac0c16Sdavemq 
25259ac0c16Sdavemq 		if (ncpu < 1)
25359ac0c16Sdavemq 			continue;
25459ac0c16Sdavemq 
25559ac0c16Sdavemq 		for (j = 0; j < ncpu; j++) {
25659ac0c16Sdavemq 			if (md_get_prop_val(mdp, node[j], "id", &lcpuid))
25759ac0c16Sdavemq 				continue;
25859ac0c16Sdavemq 			if (lcpuid >= NCPU)
25959ac0c16Sdavemq 				continue;
26059ac0c16Sdavemq 			cpuid = (processorid_t)lcpuid;
26159ac0c16Sdavemq 			cpunodes[cpuid].l2_cache_mapping = idx;
26259ac0c16Sdavemq 		}
26359ac0c16Sdavemq 		md_free_scan_dag(mdp, &node);
26459ac0c16Sdavemq 
26559ac0c16Sdavemq 		idx++;
26659ac0c16Sdavemq 	}
26759ac0c16Sdavemq 
26859ac0c16Sdavemq 	md_free_scan_dag(mdp, &cachelist);
26959ac0c16Sdavemq }
27059ac0c16Sdavemq 
2711ae08745Sheppo void
setup_exec_unit_mappings(md_t * mdp)2721ae08745Sheppo setup_exec_unit_mappings(md_t *mdp)
2731ae08745Sheppo {
2742f0fcb93SJason Beloro 	int num, num_eunits;
2751ae08745Sheppo 	mde_cookie_t cpus_node;
2761ae08745Sheppo 	mde_cookie_t *node, *eunit;
2771ae08745Sheppo 	int idx, i, j;
2781ae08745Sheppo 	processorid_t cpuid;
2791ae08745Sheppo 	char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit";
280fb2f18f8Sesaxe 	enum eu_type { INTEGER, FPU } etype;
2817c478bd9Sstevel@tonic-gate 
2821ae08745Sheppo 	/*
2831ae08745Sheppo 	 * Find the cpu integer exec units - and
2841ae08745Sheppo 	 * setup the mappings appropriately.
2851ae08745Sheppo 	 */
2861ae08745Sheppo 	num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node);
2871ae08745Sheppo 	if (num < 1)
2884bac2208Snarayan 		cmn_err(CE_PANIC, "No cpus node in machine description");
2891ae08745Sheppo 	if (num > 1)
2901ae08745Sheppo 		cmn_err(CE_PANIC, "More than 1 cpus node in machine"
2911ae08745Sheppo 		    " description");
2921ae08745Sheppo 
2931ae08745Sheppo 	cpus_node = node[0];
2941ae08745Sheppo 	md_free_scan_dag(mdp, &node);
2951ae08745Sheppo 
2961ae08745Sheppo 	num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name,
2971ae08745Sheppo 	    "fwd", &eunit);
2981ae08745Sheppo 	if (num_eunits > 0) {
299fb2f18f8Sesaxe 		char *int_str = broken_md_flag ? "int" : "integer";
300fb2f18f8Sesaxe 		char *fpu_str = "fp";
3011ae08745Sheppo 
3021ae08745Sheppo 		/* Spin through and find all the integer exec units */
3031ae08745Sheppo 		for (i = 0; i < num_eunits; i++) {
3041ae08745Sheppo 			char *p;
3051ae08745Sheppo 			char *val;
3061ae08745Sheppo 			int vallen;
3071ae08745Sheppo 			uint64_t lcpuid;
3081ae08745Sheppo 
309fb2f18f8Sesaxe 			/* ignore nodes with no type */
3101ae08745Sheppo 			if (md_get_prop_data(mdp, eunit[i], "type",
311ad8d2eb8Szx 			    (uint8_t **)&val, &vallen))
312ad8d2eb8Szx 				continue;
3131ae08745Sheppo 
3141ae08745Sheppo 			for (p = val; *p != '\0'; p += strlen(p) + 1) {
315fb2f18f8Sesaxe 				if (strcmp(p, int_str) == 0) {
316fb2f18f8Sesaxe 					etype = INTEGER;
3171ae08745Sheppo 					goto found;
318fb2f18f8Sesaxe 				}
319fb2f18f8Sesaxe 				if (strcmp(p, fpu_str) == 0) {
320fb2f18f8Sesaxe 					etype = FPU;
321fb2f18f8Sesaxe 					goto found;
322fb2f18f8Sesaxe 				}
3237c478bd9Sstevel@tonic-gate 			}
3241ae08745Sheppo 
3251ae08745Sheppo 			continue;
3261ae08745Sheppo found:
3271ae08745Sheppo 			idx = NCPU + i;
3287c478bd9Sstevel@tonic-gate 			/*
3291ae08745Sheppo 			 * find the cpus attached to this EU and
3301ae08745Sheppo 			 * update their mapping indices
3317c478bd9Sstevel@tonic-gate 			 */
3321ae08745Sheppo 			num = md_alloc_scan_dag(mdp, eunit[i], "cpu",
3331ae08745Sheppo 			    "back", &node);
3341ae08745Sheppo 
3351ae08745Sheppo 			if (num < 1)
3361ae08745Sheppo 				cmn_err(CE_PANIC, "exec-unit node in MD"
3371ae08745Sheppo 				    " not attached to a cpu node");
3381ae08745Sheppo 
3391ae08745Sheppo 			for (j = 0; j < num; j++) {
3401ae08745Sheppo 				if (md_get_prop_val(mdp, node[j], "id",
3411ae08745Sheppo 				    &lcpuid))
3421ae08745Sheppo 					continue;
3431ae08745Sheppo 				if (lcpuid >= NCPU)
3441ae08745Sheppo 					continue;
3451ae08745Sheppo 				cpuid = (processorid_t)lcpuid;
346fb2f18f8Sesaxe 				switch (etype) {
347fb2f18f8Sesaxe 				case INTEGER:
348fb2f18f8Sesaxe 					cpunodes[cpuid].exec_unit_mapping = idx;
349fb2f18f8Sesaxe 					break;
350fb2f18f8Sesaxe 				case FPU:
351fb2f18f8Sesaxe 					cpunodes[cpuid].fpu_mapping = idx;
352fb2f18f8Sesaxe 					break;
353fb2f18f8Sesaxe 				}
3541ae08745Sheppo 			}
3551ae08745Sheppo 			md_free_scan_dag(mdp, &node);
3567c478bd9Sstevel@tonic-gate 		}
3572f0fcb93SJason Beloro 
3582f0fcb93SJason Beloro 
3599d0d62adSJason Beloro 		md_free_scan_dag(mdp, &eunit);
3602f0fcb93SJason Beloro 	}
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3631ae08745Sheppo /*
3641ae08745Sheppo  * All the common setup of sun4v CPU modules is done by this routine.
3651ae08745Sheppo  */
3661ae08745Sheppo void
cpu_setup_common(char ** cpu_module_isa_set)3671ae08745Sheppo cpu_setup_common(char **cpu_module_isa_set)
3687c478bd9Sstevel@tonic-gate {
3691ae08745Sheppo 	extern int mmu_exported_pagesize_mask;
3701ae08745Sheppo 	int nocpus, i;
3711ae08745Sheppo 	size_t ra_limit;
3721ae08745Sheppo 	mde_cookie_t *cpulist;
3731ae08745Sheppo 	md_t *mdp;
3741ae08745Sheppo 
3751ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL)
3761ae08745Sheppo 		cmn_err(CE_PANIC, "Unable to initialize machine description");
3771ae08745Sheppo 
37806fb6a36Sdv 	boot_ncpus = nocpus = md_alloc_scan_dag(mdp,
3791ae08745Sheppo 	    md_root_node(mdp), "cpu", "fwd", &cpulist);
3801ae08745Sheppo 	if (nocpus < 1) {
3811ae08745Sheppo 		cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation "
3821ae08745Sheppo 		    "failed or incorrect number of CPUs in MD");
3831ae08745Sheppo 	}
3847c478bd9Sstevel@tonic-gate 
3854bac2208Snarayan 	init_md_broken(mdp, cpulist);
3864bac2208Snarayan 
3871ae08745Sheppo 	if (use_page_coloring) {
3881ae08745Sheppo 		do_pg_coloring = 1;
3891ae08745Sheppo 	}
3901ae08745Sheppo 
3911ae08745Sheppo 	/*
3921e2e7a75Shuah 	 * Get the valid mmu page sizes mask, Q sizes and isalist/r
3931ae08745Sheppo 	 * from the MD for the first available CPU in cpulist.
3941e2e7a75Shuah 	 *
3951e2e7a75Shuah 	 * Do not expect the MMU page sizes mask to be more than 32-bit.
3961ae08745Sheppo 	 */
3971ae08745Sheppo 	mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]);
3981ae08745Sheppo 
39905d3dc4bSpaulsan 	/*
40005d3dc4bSpaulsan 	 * Get the number of contexts and tsbs supported.
40105d3dc4bSpaulsan 	 */
40205d3dc4bSpaulsan 	if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS &&
40305d3dc4bSpaulsan 	    get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) {
40405d3dc4bSpaulsan 		shctx_on = 1;
40505d3dc4bSpaulsan 	}
40605d3dc4bSpaulsan 
4071ae08745Sheppo 	for (i = 0; i < nocpus; i++)
4081ae08745Sheppo 		fill_cpu(mdp, cpulist[i]);
4091ae08745Sheppo 
410575a7426Spt 	/* setup l2 cache count. */
411575a7426Spt 	n_l2_caches = get_l2_cache_node_count(mdp);
412575a7426Spt 
41359ac0c16Sdavemq 	setup_chip_mappings(mdp);
4141ae08745Sheppo 	setup_exec_unit_mappings(mdp);
4151ae08745Sheppo 
4161ae08745Sheppo 	/*
4171ae08745Sheppo 	 * If MD is broken then append the passed ISA set,
4181ae08745Sheppo 	 * otherwise trust the MD.
4191ae08745Sheppo 	 */
4201ae08745Sheppo 
4211ae08745Sheppo 	if (broken_md_flag)
4221ae08745Sheppo 		isa_list = construct_isalist(mdp, cpulist[0],
4231ae08745Sheppo 		    cpu_module_isa_set);
4241ae08745Sheppo 	else
4251ae08745Sheppo 		isa_list = construct_isalist(mdp, cpulist[0], NULL);
4261ae08745Sheppo 
4272f0fcb93SJason Beloro 	get_hwcaps(mdp, cpulist[0]);
4282c5124a1SPrashanth Sreenivasa 	get_weakest_mem_model(mdp, cpulist[0]);
4291ae08745Sheppo 	get_q_sizes(mdp, cpulist[0]);
4301ae08745Sheppo 	get_va_bits(mdp, cpulist[0]);
4311ae08745Sheppo 
4321ae08745Sheppo 	/*
4331ae08745Sheppo 	 * ra_limit is the highest real address in the machine.
4341ae08745Sheppo 	 */
4359853d9e8SJason Beloro 	ra_limit = get_ra_limit(mdp, cpulist[0]);
4361ae08745Sheppo 
4371ae08745Sheppo 	md_free_scan_dag(mdp, &cpulist);
4381ae08745Sheppo 
4391ae08745Sheppo 	(void) md_fini_handle(mdp);
4401ae08745Sheppo 
4411ae08745Sheppo 	/*
4421ae08745Sheppo 	 * Block stores invalidate all pages of the d$ so pagecopy
4431ae08745Sheppo 	 * et. al. do not need virtual translations with virtual
4441ae08745Sheppo 	 * coloring taken into consideration.
4451ae08745Sheppo 	 */
4461ae08745Sheppo 	pp_consistent_coloring = 0;
4471ae08745Sheppo 
4481ae08745Sheppo 	/*
4491ae08745Sheppo 	 * The kpm mapping window.
4501ae08745Sheppo 	 * kpm_size:
4511ae08745Sheppo 	 *	The size of a single kpm range.
4521ae08745Sheppo 	 *	The overall size will be: kpm_size * vac_colors.
4531ae08745Sheppo 	 * kpm_vbase:
4541ae08745Sheppo 	 *	The virtual start address of the kpm range within the kernel
4551ae08745Sheppo 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
4561ae08745Sheppo 	 */
4571ae08745Sheppo 
4581ae08745Sheppo 	/*
4591ae08745Sheppo 	 * Make kpm_vbase, kpm_size aligned to kpm_size_shift.
4601ae08745Sheppo 	 * To do this find the nearest power of 2 size that the
4611ae08745Sheppo 	 * actual ra_limit fits within.
4621ae08745Sheppo 	 * If it is an even power of two use that, otherwise use the
4631ae08745Sheppo 	 * next power of two larger than ra_limit.
4641ae08745Sheppo 	 */
4651ae08745Sheppo 
4661ae08745Sheppo 	ASSERT(ra_limit != 0);
4671ae08745Sheppo 
468*de710d24SJosef 'Jeff' Sipek 	kpm_size_shift = !ISP2(ra_limit) ?
469ad8d2eb8Szx 	    highbit(ra_limit) : highbit(ra_limit) - 1;
4701ae08745Sheppo 
4711ae08745Sheppo 	/*
4721ae08745Sheppo 	 * No virtual caches on sun4v so size matches size shift
4731ae08745Sheppo 	 */
4741ae08745Sheppo 	kpm_size = 1ul << kpm_size_shift;
4751ae08745Sheppo 
4761ae08745Sheppo 	if (va_bits < VA_ADDRESS_SPACE_BITS) {
4777c478bd9Sstevel@tonic-gate 		/*
4781ae08745Sheppo 		 * In case of VA hole
4791ae08745Sheppo 		 * kpm_base = hole_end + 1TB
4801ae08745Sheppo 		 * Starting 1TB beyond where VA hole ends because on Niagara
4811ae08745Sheppo 		 * processor software must not use pages within 4GB of the
4821ae08745Sheppo 		 * VA hole as instruction pages to avoid problems with
4831ae08745Sheppo 		 * prefetching into the VA hole.
4847c478bd9Sstevel@tonic-gate 		 */
4851ae08745Sheppo 		kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) +
4861ae08745Sheppo 		    (1ull << 40));
4871ae08745Sheppo 	} else {		/* Number of VA bits 64 ... no VA hole */
4881ae08745Sheppo 		kpm_vbase = (caddr_t)0x8000000000000000ull;	/* 8 EB */
4897c478bd9Sstevel@tonic-gate 	}
4901ae08745Sheppo 
4911ae08745Sheppo 	/*
4921ae08745Sheppo 	 * The traptrace code uses either %tick or %stick for
4931ae08745Sheppo 	 * timestamping.  The sun4v require use of %stick.
4941ae08745Sheppo 	 */
4951ae08745Sheppo 	traptrace_use_stick = 1;
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4981ae08745Sheppo /*
4991ae08745Sheppo  * Get the nctxs from MD. If absent panic.
5001ae08745Sheppo  */
5011ae08745Sheppo static uint64_t
get_mmu_ctx_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)5021ae08745Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
5037c478bd9Sstevel@tonic-gate {
5041ae08745Sheppo 	uint64_t ctx_bits;
5057c478bd9Sstevel@tonic-gate 
5061ae08745Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits",
5071ae08745Sheppo 	    &ctx_bits))
5081ae08745Sheppo 		ctx_bits = 0;
5097c478bd9Sstevel@tonic-gate 
5101ae08745Sheppo 	if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS)
5111ae08745Sheppo 		cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits "
5121ae08745Sheppo 		    "returned by MD", ctx_bits);
5137c478bd9Sstevel@tonic-gate 
5141ae08745Sheppo 	return (ctx_bits);
5151ae08745Sheppo }
5167c478bd9Sstevel@tonic-gate 
51705d3dc4bSpaulsan /*
51805d3dc4bSpaulsan  * Get the number of tsbs from MD. If absent the default value is 0.
51905d3dc4bSpaulsan  */
52005d3dc4bSpaulsan static uint64_t
get_mmu_tsbs(md_t * mdp,mde_cookie_t cpu_node_cookie)52105d3dc4bSpaulsan get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie)
52205d3dc4bSpaulsan {
52305d3dc4bSpaulsan 	uint64_t number_tsbs;
52405d3dc4bSpaulsan 
52505d3dc4bSpaulsan 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs",
52605d3dc4bSpaulsan 	    &number_tsbs))
52705d3dc4bSpaulsan 		number_tsbs = 0;
52805d3dc4bSpaulsan 
52905d3dc4bSpaulsan 	return (number_tsbs);
53005d3dc4bSpaulsan }
53105d3dc4bSpaulsan 
53205d3dc4bSpaulsan /*
5337dacfc44Spaulsan  * Get the number of shared contexts from MD. If absent the default value is 0.
53405d3dc4bSpaulsan  *
53505d3dc4bSpaulsan  */
53605d3dc4bSpaulsan static uint64_t
get_mmu_shcontexts(md_t * mdp,mde_cookie_t cpu_node_cookie)53705d3dc4bSpaulsan get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie)
53805d3dc4bSpaulsan {
53905d3dc4bSpaulsan 	uint64_t number_contexts;
54005d3dc4bSpaulsan 
54105d3dc4bSpaulsan 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts",
54205d3dc4bSpaulsan 	    &number_contexts))
54305d3dc4bSpaulsan 		number_contexts = 0;
54405d3dc4bSpaulsan 
54505d3dc4bSpaulsan 	return (number_contexts);
54605d3dc4bSpaulsan }
54705d3dc4bSpaulsan 
5481ae08745Sheppo /*
5491ae08745Sheppo  * Initalize supported page sizes information.
5501ae08745Sheppo  * Set to 0, if the page sizes mask information is absent in MD.
5511ae08745Sheppo  */
5521ae08745Sheppo static uint64_t
get_cpu_pagesizes(md_t * mdp,mde_cookie_t cpu_node_cookie)5531ae08745Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
5541ae08745Sheppo {
5551ae08745Sheppo 	uint64_t mmu_page_size_list;
5567c478bd9Sstevel@tonic-gate 
5571ae08745Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list",
5581ae08745Sheppo 	    &mmu_page_size_list))
5591ae08745Sheppo 		mmu_page_size_list = 0;
5601ae08745Sheppo 
5611ae08745Sheppo 	if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK)
5621ae08745Sheppo 		cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned"
5631ae08745Sheppo 		    "by MD", mmu_page_size_list);
5641ae08745Sheppo 
5651ae08745Sheppo 	return (mmu_page_size_list);
5661ae08745Sheppo }
5671ae08745Sheppo 
5681ae08745Sheppo /*
5691ae08745Sheppo  * This routine gets the isalist information from MD and appends
5701ae08745Sheppo  * the CPU module ISA set if required.
5711ae08745Sheppo  */
5721ae08745Sheppo static char *
construct_isalist(md_t * mdp,mde_cookie_t cpu_node_cookie,char ** cpu_module_isa_set)5731ae08745Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie,
5741ae08745Sheppo     char **cpu_module_isa_set)
5751ae08745Sheppo {
5761ae08745Sheppo 	extern int at_flags;
5771ae08745Sheppo 	char *md_isalist;
5781ae08745Sheppo 	int md_isalen;
5791ae08745Sheppo 	char *isabuf;
5801ae08745Sheppo 	int isalen;
5811ae08745Sheppo 	char **isa_set;
5821ae08745Sheppo 	char *p, *q;
5831ae08745Sheppo 	int cpu_module_isalen = 0, found = 0;
5841ae08745Sheppo 
5851ae08745Sheppo 	(void) md_get_prop_data(mdp, cpu_node_cookie,
5861ae08745Sheppo 	    "isalist", (uint8_t **)&isabuf, &isalen);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	/*
5891ae08745Sheppo 	 * We support binaries for all the cpus that have shipped so far.
5901ae08745Sheppo 	 * The kernel emulates instructions that are not supported by hardware.
5917c478bd9Sstevel@tonic-gate 	 */
5921ae08745Sheppo 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
5937c478bd9Sstevel@tonic-gate 
5941ae08745Sheppo 	/*
5951ae08745Sheppo 	 * Construct the space separated isa_list.
5961ae08745Sheppo 	 */
5971ae08745Sheppo 	if (cpu_module_isa_set != NULL) {
5981ae08745Sheppo 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
5991ae08745Sheppo 		    isa_set++) {
6001ae08745Sheppo 			cpu_module_isalen += strlen(*isa_set);
6011ae08745Sheppo 			cpu_module_isalen++;	/* for space character */
6021ae08745Sheppo 		}
6031ae08745Sheppo 	}
6047c478bd9Sstevel@tonic-gate 
6051ae08745Sheppo 	/*
6061ae08745Sheppo 	 * Allocate the buffer of MD isa buffer length + CPU module
6071ae08745Sheppo 	 * isa buffer length.
6081ae08745Sheppo 	 */
6091ae08745Sheppo 	md_isalen = isalen + cpu_module_isalen + 2;
6101ae08745Sheppo 	md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0);
6111ae08745Sheppo 	if (md_isalist == NULL)
6121ae08745Sheppo 		cmn_err(CE_PANIC, "construct_isalist: Allocation failed for "
6131ae08745Sheppo 		    "md_isalist");
6141ae08745Sheppo 
6151ae08745Sheppo 	md_isalist[0] = '\0'; /* create an empty string to start */
6161ae08745Sheppo 	for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) {
6171ae08745Sheppo 		(void) strlcat(md_isalist, p, md_isalen);
6181ae08745Sheppo 		(void) strcat(md_isalist, " ");
6191ae08745Sheppo 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/*
6221ae08745Sheppo 	 * Check if the isa_set is present in isalist returned by MD.
6231ae08745Sheppo 	 * If yes, then no need to append it, if no then append it to
6241ae08745Sheppo 	 * isalist returned by MD.
6257c478bd9Sstevel@tonic-gate 	 */
6261ae08745Sheppo 	if (cpu_module_isa_set != NULL) {
6271ae08745Sheppo 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
6281ae08745Sheppo 		    isa_set++) {
6291ae08745Sheppo 			found = 0;
6301ae08745Sheppo 			for (p = isabuf, q = p + isalen; p < q;
6311ae08745Sheppo 			    p += strlen(p) + 1) {
6321ae08745Sheppo 				if (strcmp(p, *isa_set) == 0) {
6331ae08745Sheppo 					found = 1;
6341ae08745Sheppo 					break;
6351ae08745Sheppo 				}
6361ae08745Sheppo 			}
6371ae08745Sheppo 			if (!found) {
6381ae08745Sheppo 				(void) strlcat(md_isalist, *isa_set, md_isalen);
6391ae08745Sheppo 				(void) strcat(md_isalist, " ");
6401ae08745Sheppo 			}
6411ae08745Sheppo 		}
6421ae08745Sheppo 	}
6431ae08745Sheppo 
6441ae08745Sheppo 	/* Get rid of any trailing white spaces */
6451ae08745Sheppo 	md_isalist[strlen(md_isalist) - 1] = '\0';
6461ae08745Sheppo 
6471ae08745Sheppo 	return (md_isalist);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6502f0fcb93SJason Beloro static void
get_hwcaps(md_t * mdp,mde_cookie_t cpu_node_cookie)6512f0fcb93SJason Beloro get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie)
6522f0fcb93SJason Beloro {
6532f0fcb93SJason Beloro 	char *hwcapbuf;
6542f0fcb93SJason Beloro 	int hwcaplen;
6552f0fcb93SJason Beloro 
6562f0fcb93SJason Beloro 	if (md_get_prop_data(mdp, cpu_node_cookie,
6572f0fcb93SJason Beloro 	    "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) {
6582f0fcb93SJason Beloro 		/* Property not found */
6592f0fcb93SJason Beloro 		return;
6602f0fcb93SJason Beloro 	}
6612f0fcb93SJason Beloro 
6622f0fcb93SJason Beloro 	cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC,
6632f0fcb93SJason Beloro 	    "unrecognized token: %s");
6642f0fcb93SJason Beloro }
6652f0fcb93SJason Beloro 
6662c5124a1SPrashanth Sreenivasa static void
get_weakest_mem_model(md_t * mdp,mde_cookie_t cpu_node_cookie)6672c5124a1SPrashanth Sreenivasa get_weakest_mem_model(md_t *mdp, mde_cookie_t cpu_node_cookie)
6682c5124a1SPrashanth Sreenivasa {
6692c5124a1SPrashanth Sreenivasa 	char *mmbuf;
6702c5124a1SPrashanth Sreenivasa 	int mmlen;
6712c5124a1SPrashanth Sreenivasa 	uint_t wmm;
6722c5124a1SPrashanth Sreenivasa 	char *p, *q;
6732c5124a1SPrashanth Sreenivasa 
6742c5124a1SPrashanth Sreenivasa 	if (md_get_prop_data(mdp, cpu_node_cookie,
6752c5124a1SPrashanth Sreenivasa 	    "memory-model-list", (uint8_t **)&mmbuf, &mmlen)) {
6762c5124a1SPrashanth Sreenivasa 		/* Property not found */
6772c5124a1SPrashanth Sreenivasa 		return;
6782c5124a1SPrashanth Sreenivasa 	}
6792c5124a1SPrashanth Sreenivasa 
6802c5124a1SPrashanth Sreenivasa 	wmm = TSTATE_MM_TSO;
6812c5124a1SPrashanth Sreenivasa 	for (p = mmbuf, q = p + mmlen; p < q; p += strlen(p) + 1) {
6822c5124a1SPrashanth Sreenivasa 		if (strcmp(p, "wc") == 0)
6832c5124a1SPrashanth Sreenivasa 			wmm = TSTATE_MM_WC;
6842c5124a1SPrashanth Sreenivasa 	}
6852c5124a1SPrashanth Sreenivasa 	weakest_mem_model = wmm;
6862c5124a1SPrashanth Sreenivasa }
6872f0fcb93SJason Beloro 
6882f0fcb93SJason Beloro /*
6892f0fcb93SJason Beloro  * Does the opposite of cmn_err(9f) "%b" conversion specification:
6902f0fcb93SJason Beloro  * Given a list of strings, converts them to a bit-vector.
6912f0fcb93SJason Beloro  *
6922f0fcb93SJason Beloro  *  tokens - is a buffer of [NUL-terminated] strings.
6932f0fcb93SJason Beloro  *  tokenslen - length of tokenbuf in bytes.
6942f0fcb93SJason Beloro  *  bit_formatter - is a %b format string, such as FMT_AV_SPARC
6952f0fcb93SJason Beloro  *    from /usr/include/sys/auxv_SPARC.h, of the form:
6962f0fcb93SJason Beloro  *    <base-char>[<bit-char><token-string>]...
6972f0fcb93SJason Beloro  *        <base-char> is ignored.
6982f0fcb93SJason Beloro  *        <bit-char>  is [1-32], as per cmn_err(9f).
6992f0fcb93SJason Beloro  *  warning - is a printf-style format string containing "%s",
7002f0fcb93SJason Beloro  *    which is used to print a warning message when an unrecognized
7012f0fcb93SJason Beloro  *    token is found.  If warning is NULL, no warning is printed.
7022f0fcb93SJason Beloro  * Returns a bit-vector corresponding to the specified tokens.
7032f0fcb93SJason Beloro  */
7042f0fcb93SJason Beloro 
7052f0fcb93SJason Beloro static unsigned long
names2bits(char * tokens,size_t tokenslen,char * bit_formatter,char * warning)7062f0fcb93SJason Beloro names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning)
7072f0fcb93SJason Beloro {
7082f0fcb93SJason Beloro 	char *cur;
7092f0fcb93SJason Beloro 	size_t  curlen;
7102f0fcb93SJason Beloro 	unsigned long ul = 0;
7112f0fcb93SJason Beloro 	char *hit;
7122f0fcb93SJason Beloro 	char *bs;
7132f0fcb93SJason Beloro 
7142f0fcb93SJason Beloro 	bit_formatter++;	/* skip base; not needed for input */
7152f0fcb93SJason Beloro 	cur = tokens;
7162f0fcb93SJason Beloro 	while (tokenslen) {
7172f0fcb93SJason Beloro 		curlen = strlen(cur);
7182f0fcb93SJason Beloro 		bs = bit_formatter;
7192f0fcb93SJason Beloro 		/*
7202f0fcb93SJason Beloro 		 * We need a complicated while loop and the >=32 check,
7212f0fcb93SJason Beloro 		 * instead of a simple "if (strstr())" so that when the
7222f0fcb93SJason Beloro 		 * token is "vis", we don't match on "vis2" (for example).
7232f0fcb93SJason Beloro 		 */
7242f0fcb93SJason Beloro 		/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
7252f0fcb93SJason Beloro 		while ((hit = strstr(bs, cur)) &&
7262f0fcb93SJason Beloro 		    *(hit + curlen) >= 32) {
7272f0fcb93SJason Beloro 			/*
7282f0fcb93SJason Beloro 			 * We're still in the middle of a word, i.e., not
7292f0fcb93SJason Beloro 			 * pointing at a <bit-char>.  So advance ptr
7302f0fcb93SJason Beloro 			 * to ensure forward progress.
7312f0fcb93SJason Beloro 			 */
7322f0fcb93SJason Beloro 			bs = hit + curlen + 1;
7332f0fcb93SJason Beloro 		}
7342f0fcb93SJason Beloro 
7352f0fcb93SJason Beloro 		if (hit != NULL) {
7362f0fcb93SJason Beloro 			ul |= (1<<(*(hit-1) - 1));
7372f0fcb93SJason Beloro 		} else {
7382f0fcb93SJason Beloro 			/* The token wasn't found in bit_formatter */
7392f0fcb93SJason Beloro 			if (warning != NULL)
7402f0fcb93SJason Beloro 				cmn_err(CE_WARN, warning, cur);
7412f0fcb93SJason Beloro 		}
7422f0fcb93SJason Beloro 		tokenslen -= curlen + 1;
7432f0fcb93SJason Beloro 		cur += curlen + 1;
7442f0fcb93SJason Beloro 	}
7452f0fcb93SJason Beloro 	return (ul);
7462f0fcb93SJason Beloro }
7472f0fcb93SJason Beloro 
7481ae08745Sheppo uint64_t
get_ra_limit(md_t * mdp,mde_cookie_t cpu_node_cookie)7499853d9e8SJason Beloro get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie)
7501ae08745Sheppo {
7519853d9e8SJason Beloro 	extern int ppvm_enable;
7529853d9e8SJason Beloro 	extern int meta_alloc_enable;
7531ae08745Sheppo 	mde_cookie_t *mem_list;
7541ae08745Sheppo 	mde_cookie_t *mblock_list;
7551ae08745Sheppo 	int i;
7561ae08745Sheppo 	int memnodes;
7571ae08745Sheppo 	int nmblock;
7589853d9e8SJason Beloro 	uint64_t r;
7591ae08745Sheppo 	uint64_t base;
7601ae08745Sheppo 	uint64_t size;
7611ae08745Sheppo 	uint64_t ra_limit = 0, new_limit = 0;
7621ae08745Sheppo 
7639853d9e8SJason Beloro 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) {
7649853d9e8SJason Beloro 		if (r == 0 || r > RA_ADDRESS_SPACE_BITS)
7659853d9e8SJason Beloro 			cmn_err(CE_PANIC, "Incorrect number of ra bits in MD");
7669853d9e8SJason Beloro 		else {
7679853d9e8SJason Beloro 			/*
7689853d9e8SJason Beloro 			 * Enable memory DR and metadata (page_t)
7699853d9e8SJason Beloro 			 * allocation from existing memory.
7709853d9e8SJason Beloro 			 */
7719853d9e8SJason Beloro 			ppvm_enable = 1;
7729853d9e8SJason Beloro 			meta_alloc_enable = 1;
7739853d9e8SJason Beloro 			return (1ULL << r);
7749853d9e8SJason Beloro 		}
7759853d9e8SJason Beloro 	}
7769853d9e8SJason Beloro 
7771ae08745Sheppo 	memnodes = md_alloc_scan_dag(mdp,
7781ae08745Sheppo 	    md_root_node(mdp), "memory", "fwd", &mem_list);
7791ae08745Sheppo 
7801ae08745Sheppo 	ASSERT(memnodes == 1);
7811ae08745Sheppo 
7821ae08745Sheppo 	nmblock = md_alloc_scan_dag(mdp,
7831ae08745Sheppo 	    mem_list[0], "mblock", "fwd", &mblock_list);
7841ae08745Sheppo 	if (nmblock < 1)
7851ae08745Sheppo 		cmn_err(CE_PANIC, "cannot find mblock nodes in MD");
7861ae08745Sheppo 
7871ae08745Sheppo 	for (i = 0; i < nmblock; i++) {
7881ae08745Sheppo 		if (md_get_prop_val(mdp, mblock_list[i], "base", &base))
7891ae08745Sheppo 			cmn_err(CE_PANIC, "base property missing from MD"
7901ae08745Sheppo 			    " mblock node");
7911ae08745Sheppo 		if (md_get_prop_val(mdp, mblock_list[i], "size", &size))
7921ae08745Sheppo 			cmn_err(CE_PANIC, "size property missing from MD"
7931ae08745Sheppo 			    " mblock node");
7941ae08745Sheppo 
7951ae08745Sheppo 		ASSERT(size != 0);
7961ae08745Sheppo 
7971ae08745Sheppo 		new_limit = base + size;
7981ae08745Sheppo 
7991ae08745Sheppo 		if (base > new_limit)
8001ae08745Sheppo 			cmn_err(CE_PANIC, "mblock in MD wrapped around");
8011ae08745Sheppo 
8021ae08745Sheppo 		if (new_limit > ra_limit)
803ad8d2eb8Szx 			ra_limit = new_limit;
8041ae08745Sheppo 	}
8051ae08745Sheppo 
8061ae08745Sheppo 	ASSERT(ra_limit != 0);
8071ae08745Sheppo 
8081ae08745Sheppo 	if (ra_limit > MAX_REAL_ADDRESS) {
8091ae08745Sheppo 		cmn_err(CE_WARN, "Highest real address in MD too large"
8101ae08745Sheppo 		    " clipping to %llx\n", MAX_REAL_ADDRESS);
8111ae08745Sheppo 		ra_limit = MAX_REAL_ADDRESS;
8121ae08745Sheppo 	}
8131ae08745Sheppo 
8141ae08745Sheppo 	md_free_scan_dag(mdp, &mblock_list);
8151ae08745Sheppo 
8161ae08745Sheppo 	md_free_scan_dag(mdp, &mem_list);
8171ae08745Sheppo 
8181ae08745Sheppo 	return (ra_limit);
8191ae08745Sheppo }
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate /*
8221ae08745Sheppo  * This routine sets the globals for CPU and DEV mondo queue entries and
8231ae08745Sheppo  * resumable and non-resumable error queue entries.
8244bac2208Snarayan  *
8254bac2208Snarayan  * First, look up the number of bits available to pass an entry number.
8264bac2208Snarayan  * This can vary by platform and may result in allocating an unreasonably
8274bac2208Snarayan  * (or impossibly) large amount of memory for the corresponding table,
828d5e8e65eSdavemq  * so we clamp it by 'max_entries'.  Finally, since the q size is used when
829d5e8e65eSdavemq  * calling contig_mem_alloc(), which expects a power of 2, clamp the q size
830d5e8e65eSdavemq  * down to a power of 2.  If the prop is missing, use 'default_entries'.
8317c478bd9Sstevel@tonic-gate  */
8321ae08745Sheppo 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)8331ae08745Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie,
8344bac2208Snarayan     char *qnamep, uint64_t default_entries, uint64_t max_entries)
8351ae08745Sheppo {
8361ae08745Sheppo 	uint64_t entries;
8371ae08745Sheppo 
8384bac2208Snarayan 	if (default_entries > max_entries)
8394bac2208Snarayan 		cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > "
8404bac2208Snarayan 		    "max %ld for %s\n", default_entries, max_entries, qnamep);
8414bac2208Snarayan 
8421ae08745Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) {
8431ae08745Sheppo 		if (!broken_md_flag)
8441ae08745Sheppo 			cmn_err(CE_PANIC, "Missing %s property in MD cpu node",
845ad8d2eb8Szx 			    qnamep);
8461ae08745Sheppo 		entries = default_entries;
8471ae08745Sheppo 	} else {
8481ae08745Sheppo 		entries = 1 << entries;
8491ae08745Sheppo 	}
8504bac2208Snarayan 
8514bac2208Snarayan 	entries = MIN(entries, max_entries);
852d5e8e65eSdavemq 	/* If not a power of 2, truncate to a power of 2. */
853*de710d24SJosef 'Jeff' Sipek 	if (!ISP2(entries)) {
854d5e8e65eSdavemq 		entries = 1 << (highbit(entries) - 1);
855d5e8e65eSdavemq 	}
8564bac2208Snarayan 
8571ae08745Sheppo 	return (entries);
8581ae08745Sheppo }
8591ae08745Sheppo 
8604bac2208Snarayan /* Scaling constant used to compute size of cpu mondo queue */
8614bac2208Snarayan #define	CPU_MONDO_Q_MULTIPLIER	8
8621ae08745Sheppo 
8637c478bd9Sstevel@tonic-gate static void
get_q_sizes(md_t * mdp,mde_cookie_t cpu_node_cookie)8641ae08745Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
8657c478bd9Sstevel@tonic-gate {
8664bac2208Snarayan 	uint64_t max_qsize;
8674bac2208Snarayan 	mde_cookie_t *platlist;
8684bac2208Snarayan 	int nrnode;
8694bac2208Snarayan 
8704bac2208Snarayan 	/*
8714bac2208Snarayan 	 * Compute the maximum number of entries for the cpu mondo queue.
8724bac2208Snarayan 	 * Use the appropriate property in the platform node, if it is
8734bac2208Snarayan 	 * available.  Else, base it on NCPU.
8744bac2208Snarayan 	 */
8754bac2208Snarayan 	nrnode = md_alloc_scan_dag(mdp,
8764bac2208Snarayan 	    md_root_node(mdp), "platform", "fwd", &platlist);
8774bac2208Snarayan 
8784bac2208Snarayan 	ASSERT(nrnode == 1);
8794bac2208Snarayan 
880aaa10e67Sha 	ncpu_guest_max = NCPU;
881aaa10e67Sha 	(void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max);
882aaa10e67Sha 	max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER;
8834bac2208Snarayan 
8844bac2208Snarayan 	md_free_scan_dag(mdp, &platlist);
8854bac2208Snarayan 
8861ae08745Sheppo 	cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie,
8874bac2208Snarayan 	    "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize);
8881ae08745Sheppo 
8891ae08745Sheppo 	dev_q_entries = get_single_q_size(mdp, cpu_node_cookie,
890b0fc0e77Sgovinda 	    "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM);
8911ae08745Sheppo 
8921ae08745Sheppo 	cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie,
8934bac2208Snarayan 	    "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES);
8941ae08745Sheppo 
8951ae08745Sheppo 	cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie,
8964bac2208Snarayan 	    "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES);
8971ae08745Sheppo }
8981ae08745Sheppo 
8991ae08745Sheppo 
9001ae08745Sheppo static void
get_va_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)9011ae08745Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
9021ae08745Sheppo {
9031ae08745Sheppo 	uint64_t value = VA_ADDRESS_SPACE_BITS;
9041ae08745Sheppo 
9051ae08745Sheppo 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value))
9061ae08745Sheppo 		cmn_err(CE_PANIC, "mmu-#va-bits property  not found in MD");
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 
9091ae08745Sheppo 	if (value == 0 || value > VA_ADDRESS_SPACE_BITS)
9101ae08745Sheppo 		cmn_err(CE_PANIC, "Incorrect number of va bits in MD");
9117c478bd9Sstevel@tonic-gate 
9121ae08745Sheppo 	/* Do not expect number of VA bits to be more than 32-bit quantity */
9137c478bd9Sstevel@tonic-gate 
9141ae08745Sheppo 	va_bits = (int)value;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/*
9171ae08745Sheppo 	 * Correct the value for VA bits on UltraSPARC-T1 based systems
9181ae08745Sheppo 	 * in case of broken MD.
9197c478bd9Sstevel@tonic-gate 	 */
9201ae08745Sheppo 	if (broken_md_flag)
9211ae08745Sheppo 		va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS;
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
924575a7426Spt int
l2_cache_node_count(void)925575a7426Spt l2_cache_node_count(void)
926575a7426Spt {
927575a7426Spt 	return (n_l2_caches);
928575a7426Spt }
929575a7426Spt 
930575a7426Spt /*
931575a7426Spt  * count the number of l2 caches.
932575a7426Spt  */
933575a7426Spt int
get_l2_cache_node_count(md_t * mdp)934575a7426Spt get_l2_cache_node_count(md_t *mdp)
935575a7426Spt {
936575a7426Spt 	int i;
937575a7426Spt 	mde_cookie_t *cachenodes;
938575a7426Spt 	uint64_t level;
939575a7426Spt 	int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp),
940575a7426Spt 	    "cache", "fwd", &cachenodes);
941575a7426Spt 	int l2_caches = 0;
942575a7426Spt 
943575a7426Spt 	for (i = 0; i < n_cachenodes; i++) {
944575a7426Spt 		if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) {
945575a7426Spt 			level = 0;
946575a7426Spt 		}
947575a7426Spt 		if (level == 2) {
948575a7426Spt 			l2_caches++;
949575a7426Spt 		}
950575a7426Spt 	}
951575a7426Spt 	md_free_scan_dag(mdp, &cachenodes);
952575a7426Spt 	return (l2_caches);
953575a7426Spt }
954575a7426Spt 
9551ae08745Sheppo /*
9561ae08745Sheppo  * This routine returns the L2 cache information such as -- associativity,
9571ae08745Sheppo  * size and linesize.
9581ae08745Sheppo  */
9591ae08745Sheppo static int
get_l2_cache_info(md_t * mdp,mde_cookie_t cpu_node_cookie,uint64_t * associativity,uint64_t * size,uint64_t * linesize)9601ae08745Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie,
9611ae08745Sheppo 	    uint64_t *associativity, uint64_t *size, uint64_t *linesize)
9621ae08745Sheppo {
9631ae08745Sheppo 	mde_cookie_t *cachelist;
9641ae08745Sheppo 	int ncaches, i;
965f5db7437Sae 	uint64_t cache_level = 0;
9661ae08745Sheppo 
9671ae08745Sheppo 	ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache",
9681ae08745Sheppo 	    "fwd", &cachelist);
9691ae08745Sheppo 	/*
9701ae08745Sheppo 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
9711ae08745Sheppo 	 */
9721ae08745Sheppo 	if (ncaches < 1) {
9731ae08745Sheppo 		return (0);
9741ae08745Sheppo 	}
9751ae08745Sheppo 
9761ae08745Sheppo 	for (i = 0; i < ncaches; i++) {
9771ae08745Sheppo 		uint64_t local_assoc;
9781ae08745Sheppo 		uint64_t local_size;
9791ae08745Sheppo 		uint64_t local_lsize;
9801ae08745Sheppo 
9811ae08745Sheppo 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
9821ae08745Sheppo 			continue;
9831ae08745Sheppo 
984f5db7437Sae 		if (cache_level != 2) continue;
9851ae08745Sheppo 
9861ae08745Sheppo 		/* If properties are missing from this cache ignore it */
9871ae08745Sheppo 
9881ae08745Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9891ae08745Sheppo 		    "associativity", &local_assoc))) {
9901ae08745Sheppo 			continue;
9911ae08745Sheppo 		}
9921ae08745Sheppo 
9931ae08745Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9941ae08745Sheppo 		    "size", &local_size))) {
9951ae08745Sheppo 			continue;
9961ae08745Sheppo 		}
9971ae08745Sheppo 
9981ae08745Sheppo 		if ((md_get_prop_val(mdp, cachelist[i],
9991ae08745Sheppo 		    "line-size", &local_lsize))) {
10001ae08745Sheppo 			continue;
10011ae08745Sheppo 		}
10021ae08745Sheppo 
10031ae08745Sheppo 		*associativity = local_assoc;
10041ae08745Sheppo 		*size = local_size;
10051ae08745Sheppo 		*linesize = local_lsize;
1006f5db7437Sae 		break;
10071ae08745Sheppo 	}
10087c478bd9Sstevel@tonic-gate 
10091ae08745Sheppo 	md_free_scan_dag(mdp, &cachelist);
10101ae08745Sheppo 
1011f5db7437Sae 	return ((cache_level == 2) ? 1 : 0);
10121ae08745Sheppo }
10131ae08745Sheppo 
10144bac2208Snarayan 
10151ae08745Sheppo /*
10164bac2208Snarayan  * Set the broken_md_flag to 1 if the MD doesn't have
10174bac2208Snarayan  * the domaining-enabled property in the platform node and the
10184bac2208Snarayan  * platform uses the UltraSPARC-T1 cpu. This flag is used to
10194bac2208Snarayan  * workaround some of the incorrect MD properties.
10201ae08745Sheppo  */
10211ae08745Sheppo static void
init_md_broken(md_t * mdp,mde_cookie_t * cpulist)10224bac2208Snarayan init_md_broken(md_t *mdp, mde_cookie_t *cpulist)
10237c478bd9Sstevel@tonic-gate {
10241ae08745Sheppo 	int nrnode;
10251ae08745Sheppo 	mde_cookie_t *platlist, rootnode;
10261ae08745Sheppo 	uint64_t val = 0;
10274bac2208Snarayan 	char *namebuf;
10284bac2208Snarayan 	int namelen;
10291ae08745Sheppo 
10301ae08745Sheppo 	rootnode = md_root_node(mdp);
10311ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
10324bac2208Snarayan 	ASSERT(cpulist);
10331ae08745Sheppo 
10344bac2208Snarayan 	nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd",
10351ae08745Sheppo 	    &platlist);
10361ae08745Sheppo 
1037f273041fSjm 	if (nrnode < 1)
1038f273041fSjm 		cmn_err(CE_PANIC, "init_md_broken: platform node missing");
10391ae08745Sheppo 
10404bac2208Snarayan 	if (md_get_prop_data(mdp, cpulist[0],
10414bac2208Snarayan 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
10424bac2208Snarayan 		cmn_err(CE_PANIC, "init_md_broken: "
10434bac2208Snarayan 		    "Cannot read 'compatible' property of 'cpu' node");
10444bac2208Snarayan 	}
10457c478bd9Sstevel@tonic-gate 
10464bac2208Snarayan 	if (md_get_prop_val(mdp, platlist[0],
1047ad8d2eb8Szx 	    "domaining-enabled", &val) == -1 &&
10484bac2208Snarayan 	    strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0)
10491ae08745Sheppo 		broken_md_flag = 1;
10501ae08745Sheppo 
10511ae08745Sheppo 	md_free_scan_dag(mdp, &platlist);
10527c478bd9Sstevel@tonic-gate }
1053d2365b01SPavel Tatashin 
105494c894bbSVikram Hegde #define	PLAT_MAX_IOALIASES	8
105594c894bbSVikram Hegde 
105694c894bbSVikram Hegde static plat_alias_t *plat_ioaliases;
105794c894bbSVikram Hegde static uint64_t plat_num_ioaliases;
105894c894bbSVikram Hegde 
105994c894bbSVikram Hegde /*
106094c894bbSVikram Hegde  * split the aliases property into its
106194c894bbSVikram Hegde  * component strings for easy searching.
106294c894bbSVikram Hegde  */
106394c894bbSVikram Hegde static void
split_alias(plat_alias_t * pali,char * str)106494c894bbSVikram Hegde split_alias(plat_alias_t *pali, char *str)
106594c894bbSVikram Hegde {
106694c894bbSVikram Hegde 	char *aliasv[PLAT_MAX_IOALIASES], *p;
106794c894bbSVikram Hegde 	int i, duplen;
106894c894bbSVikram Hegde 	char *dup;
106994c894bbSVikram Hegde 
107094c894bbSVikram Hegde 	/* skip leading space */
107194c894bbSVikram Hegde 	str = dup = strdup(str);
107294c894bbSVikram Hegde 	duplen = strlen(dup) + 1;
107394c894bbSVikram Hegde 	str += strspn(str, " ");
107494c894bbSVikram Hegde 	for (i = 0; *str != '\0'; str = p) {
107594c894bbSVikram Hegde 
107694c894bbSVikram Hegde 		p = strpbrk(str, " ");
107794c894bbSVikram Hegde 		if (p != NULL) {
107894c894bbSVikram Hegde 			*p++ = '\0';
107994c894bbSVikram Hegde 		}
108094c894bbSVikram Hegde 
108194c894bbSVikram Hegde 		VERIFY(i < PLAT_MAX_IOALIASES);
108294c894bbSVikram Hegde 		aliasv[i++] = strdup(str);
108394c894bbSVikram Hegde 		if (p == NULL)
108494c894bbSVikram Hegde 			break;
108594c894bbSVikram Hegde 		p += strspn(p, " ");
108694c894bbSVikram Hegde 	}
108794c894bbSVikram Hegde 
108894c894bbSVikram Hegde 	kmem_free(dup, duplen);
108994c894bbSVikram Hegde 
109094c894bbSVikram Hegde 	if (i == 0) {
109194c894bbSVikram Hegde 		pali->pali_naliases = 0;
109294c894bbSVikram Hegde 		pali->pali_aliases = NULL;
109394c894bbSVikram Hegde 		return;
109494c894bbSVikram Hegde 	}
109594c894bbSVikram Hegde 
109694c894bbSVikram Hegde 	pali->pali_naliases = i;
109794c894bbSVikram Hegde 	pali->pali_aliases = kmem_alloc(i * sizeof (char *), KM_SLEEP);
109894c894bbSVikram Hegde 	for (i = 0; i < pali->pali_naliases; i++) {
109994c894bbSVikram Hegde 		pali->pali_aliases[i] = aliasv[i];
110094c894bbSVikram Hegde 	}
110194c894bbSVikram Hegde }
110294c894bbSVikram Hegde 
110394c894bbSVikram Hegde /*
110494c894bbSVikram Hegde  * retrieve the ioalias info from the MD,
110594c894bbSVikram Hegde  * and init the ioalias struct.
110694c894bbSVikram Hegde  *
110794c894bbSVikram Hegde  * NOTE: Assumes that the ioalias info does not change at runtime
110894c894bbSVikram Hegde  * This routine is invoked only once at boot time.
110994c894bbSVikram Hegde  *
111094c894bbSVikram Hegde  * No lock needed as this is called at boot with a DDI lock held
111194c894bbSVikram Hegde  */
111294c894bbSVikram Hegde void
plat_ioaliases_init(void)111394c894bbSVikram Hegde plat_ioaliases_init(void)
111494c894bbSVikram Hegde {
111594c894bbSVikram Hegde 	md_t *mdp;
111694c894bbSVikram Hegde 	mde_cookie_t *ionodes, alinode;
111794c894bbSVikram Hegde 	plat_alias_t *pali;
111894c894bbSVikram Hegde 	int nio;
111994c894bbSVikram Hegde 	int i;
112094c894bbSVikram Hegde 	int err;
112194c894bbSVikram Hegde 
112294c894bbSVikram Hegde 	mdp = md_get_handle();
112394c894bbSVikram Hegde 	if (mdp == NULL) {
112494c894bbSVikram Hegde 		cmn_err(CE_PANIC, "no machine description (MD)");
112594c894bbSVikram Hegde 		/*NOTREACHED*/
112694c894bbSVikram Hegde 	}
112794c894bbSVikram Hegde 
112894c894bbSVikram Hegde 	nio = md_alloc_scan_dag(mdp, md_root_node(mdp),
112994c894bbSVikram Hegde 	    "ioaliases", "fwd", &ionodes);
113094c894bbSVikram Hegde 
113194c894bbSVikram Hegde 
113294c894bbSVikram Hegde 	/* not all platforms support aliases */
113394c894bbSVikram Hegde 	if (nio < 1) {
113494c894bbSVikram Hegde 		(void) md_fini_handle(mdp);
113594c894bbSVikram Hegde 		return;
113694c894bbSVikram Hegde 	}
113794c894bbSVikram Hegde 	if (nio > 1) {
113894c894bbSVikram Hegde 		cmn_err(CE_PANIC, "multiple ioalias nodes in MD");
113994c894bbSVikram Hegde 		/*NOTREACHED*/
114094c894bbSVikram Hegde 	}
114194c894bbSVikram Hegde 
114294c894bbSVikram Hegde 	alinode = ionodes[0];
114394c894bbSVikram Hegde 	md_free_scan_dag(mdp, &ionodes);
114494c894bbSVikram Hegde 
114594c894bbSVikram Hegde 	nio = md_alloc_scan_dag(mdp, alinode, "ioalias", "fwd", &ionodes);
114694c894bbSVikram Hegde 	if (nio <= 0) {
114794c894bbSVikram Hegde 		cmn_err(CE_PANIC, "MD alias node has no aliases");
114894c894bbSVikram Hegde 		/*NOTREACHED*/
114994c894bbSVikram Hegde 	}
115094c894bbSVikram Hegde 
115194c894bbSVikram Hegde 	plat_num_ioaliases = nio;
115294c894bbSVikram Hegde 	plat_ioaliases = pali = kmem_zalloc(nio * sizeof (plat_alias_t),
115394c894bbSVikram Hegde 	    KM_SLEEP);
115494c894bbSVikram Hegde 
115594c894bbSVikram Hegde 	/*
115694c894bbSVikram Hegde 	 * Each ioalias map will have a composite property of
115794c894bbSVikram Hegde 	 * aliases and the current valid path.
115894c894bbSVikram Hegde 	 */
115994c894bbSVikram Hegde 	for (i = 0; i < nio; i++) {
116094c894bbSVikram Hegde 		char *str;
116194c894bbSVikram Hegde 
116294c894bbSVikram Hegde 		err = md_get_prop_str(mdp, ionodes[i], "current", &str);
116394c894bbSVikram Hegde 		if (err != 0) {
116494c894bbSVikram Hegde 			cmn_err(CE_PANIC, "malformed ioalias node");
116594c894bbSVikram Hegde 			/*NOTREACHED*/
116694c894bbSVikram Hegde 		}
116794c894bbSVikram Hegde 		pali->pali_current = strdup(str);
116894c894bbSVikram Hegde 
116994c894bbSVikram Hegde 		err = md_get_prop_str(mdp, ionodes[i], "aliases", &str);
117094c894bbSVikram Hegde 		if (err != 0) {
117194c894bbSVikram Hegde 			cmn_err(CE_PANIC, "malformed aliases");
117294c894bbSVikram Hegde 			/*NOTREACHED*/
117394c894bbSVikram Hegde 		}
11745633e4f8SJan Setje-Eilers 		DDI_MP_DBG((CE_NOTE, "path: %s aliases %s",
11755633e4f8SJan Setje-Eilers 		    pali->pali_current, str));
11765633e4f8SJan Setje-Eilers 
117794c894bbSVikram Hegde 		split_alias(pali, str);
117894c894bbSVikram Hegde 		pali++;
117994c894bbSVikram Hegde 	}
118094c894bbSVikram Hegde 
118194c894bbSVikram Hegde 	md_free_scan_dag(mdp, &ionodes);
118294c894bbSVikram Hegde 
118394c894bbSVikram Hegde 	/*
118494c894bbSVikram Hegde 	 * Register the io-aliases array with the DDI framework
118594c894bbSVikram Hegde 	 * The DDI framework assumes that this array and its contents
118694c894bbSVikram Hegde 	 * will not change post-register. The DDI framework will
118794c894bbSVikram Hegde 	 * cache this array and is free to access this array at
118894c894bbSVikram Hegde 	 * any time without any locks.
118994c894bbSVikram Hegde 	 */
119094c894bbSVikram Hegde 	ddi_register_aliases(plat_ioaliases, plat_num_ioaliases);
119194c894bbSVikram Hegde 
119294c894bbSVikram Hegde 	(void) md_fini_handle(mdp);
119394c894bbSVikram Hegde }
119494c894bbSVikram Hegde 
1195d2365b01SPavel Tatashin /*
1196d2365b01SPavel Tatashin  * Number of bits forming a valid context for use in a sun4v TTE and the MMU
1197d2365b01SPavel Tatashin  * context registers. Sun4v defines the minimum default value to be 13 if this
1198d2365b01SPavel Tatashin  * property is not specified in a cpu node in machine descriptor graph.
1199d2365b01SPavel Tatashin  */
1200d2365b01SPavel Tatashin #define	MMU_INFO_CTXBITS_MIN		13
1201d2365b01SPavel Tatashin 
1202d2365b01SPavel Tatashin /* Convert context bits to number of contexts */
1203d2365b01SPavel Tatashin #define	MMU_INFO_BNCTXS(nbits)		((uint_t)(1u<<(nbits)))
1204d2365b01SPavel Tatashin 
1205d2365b01SPavel Tatashin /*
1206d2365b01SPavel Tatashin  * Read machine descriptor and load TLB to CPU mappings.
1207d2365b01SPavel Tatashin  * Returned values: cpuid2pset[NCPU], nctxs[NCPU], md_gen
1208d2365b01SPavel Tatashin  * - cpuid2pset is initialized so it can convert cpuids to processor set of CPUs
1209d2365b01SPavel Tatashin  *   that are shared between TLBs.
1210d2365b01SPavel Tatashin  * - nctxs is initialized to number of contexts for each CPU
1211d2365b01SPavel Tatashin  * - md_gen is set to generation number of machine descriptor from which this
1212d2365b01SPavel Tatashin  *   data was.
1213d2365b01SPavel Tatashin  * Return: zero on success.
1214d2365b01SPavel Tatashin  */
1215d2365b01SPavel Tatashin static int
load_tlb_cpu_mappings(cpuset_t ** cpuid2pset,uint_t * nctxs,uint64_t * md_gen)1216d2365b01SPavel Tatashin load_tlb_cpu_mappings(cpuset_t **cpuid2pset, uint_t *nctxs, uint64_t *md_gen)
1217d2365b01SPavel Tatashin {
1218d2365b01SPavel Tatashin 	mde_str_cookie_t cpu_sc, bck_sc;
1219d2365b01SPavel Tatashin 	int		tlbs_idx, cp_idx;
1220d2365b01SPavel Tatashin 	mde_cookie_t	root;
1221d2365b01SPavel Tatashin 	md_t		*mdp = NULL;
1222d2365b01SPavel Tatashin 	mde_cookie_t	*tlbs = NULL;
1223d2365b01SPavel Tatashin 	mde_cookie_t	*cp = NULL;
1224d2365b01SPavel Tatashin 	uint64_t	*cpids = NULL;
1225d2365b01SPavel Tatashin 	uint64_t	nbit;
1226d2365b01SPavel Tatashin 	int		ntlbs;
1227d2365b01SPavel Tatashin 	int		ncp;
1228d2365b01SPavel Tatashin 	int		retval = 1;
1229d2365b01SPavel Tatashin 	cpuset_t	*ppset;
1230d2365b01SPavel Tatashin 
1231d2365b01SPavel Tatashin 	/* get MD handle, and string cookies for cpu and back nodes */
1232d2365b01SPavel Tatashin 	if ((mdp = md_get_handle()) == NULL ||
1233d2365b01SPavel Tatashin 	    (cpu_sc = md_find_name(mdp, "cpu")) == MDE_INVAL_STR_COOKIE ||
1234d2365b01SPavel Tatashin 	    (bck_sc = md_find_name(mdp, "back")) == MDE_INVAL_STR_COOKIE)
1235d2365b01SPavel Tatashin 		goto cleanup;
1236d2365b01SPavel Tatashin 
1237d2365b01SPavel Tatashin 	/* set generation number of current MD handle */
1238d2365b01SPavel Tatashin 	*md_gen = md_get_gen(mdp);
1239d2365b01SPavel Tatashin 
1240d2365b01SPavel Tatashin 	/* Find root element, and search for all TLBs in MD */
1241d2365b01SPavel Tatashin 	if ((root = md_root_node(mdp)) == MDE_INVAL_ELEM_COOKIE ||
1242d2365b01SPavel Tatashin 	    (ntlbs = md_alloc_scan_dag(mdp, root, "tlb", "fwd", &tlbs)) <= 0)
1243d2365b01SPavel Tatashin 		goto cleanup;
1244d2365b01SPavel Tatashin 
1245d2365b01SPavel Tatashin 	cp = kmem_alloc(sizeof (mde_cookie_t) * NCPU, KM_SLEEP);
1246d2365b01SPavel Tatashin 	cpids = kmem_alloc(sizeof (uint64_t) * NCPU, KM_SLEEP);
1247d2365b01SPavel Tatashin 
1248d2365b01SPavel Tatashin 	/*
1249d2365b01SPavel Tatashin 	 * Build processor sets, one per possible context domain.  For each tlb,
1250d2365b01SPavel Tatashin 	 * search for connected CPUs.  If any CPU is already in a set, then add
1251d2365b01SPavel Tatashin 	 * all the TLB's CPUs to that set.  Otherwise, create and populate a new
1252d2365b01SPavel Tatashin 	 * pset.  Thus, a single pset is built to represent multiple TLBs if
1253d2365b01SPavel Tatashin 	 * they have CPUs in common.
1254d2365b01SPavel Tatashin 	 */
1255d2365b01SPavel Tatashin 	for (tlbs_idx = 0; tlbs_idx < ntlbs; tlbs_idx++) {
1256d2365b01SPavel Tatashin 		ncp = md_scan_dag(mdp, tlbs[tlbs_idx], cpu_sc, bck_sc, cp);
1257d2365b01SPavel Tatashin 		if (ncp < 0)
1258d2365b01SPavel Tatashin 			goto cleanup;
1259d2365b01SPavel Tatashin 		else if (ncp == 0)
1260d2365b01SPavel Tatashin 			continue;
1261d2365b01SPavel Tatashin 
1262d2365b01SPavel Tatashin 		/* Get the id and number of contexts for each cpu */
1263d2365b01SPavel Tatashin 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1264d2365b01SPavel Tatashin 			mde_cookie_t c = cp[cp_idx];
1265d2365b01SPavel Tatashin 
1266d2365b01SPavel Tatashin 			if (md_get_prop_val(mdp, c, "id", &cpids[cp_idx]))
1267d2365b01SPavel Tatashin 				goto cleanup;
1268d2365b01SPavel Tatashin 			if (md_get_prop_val(mdp, c, "mmu-#context-bits", &nbit))
1269d2365b01SPavel Tatashin 				nbit = MMU_INFO_CTXBITS_MIN;
1270d2365b01SPavel Tatashin 			nctxs[cpids[cp_idx]] = MMU_INFO_BNCTXS(nbit);
1271d2365b01SPavel Tatashin 		}
1272d2365b01SPavel Tatashin 
1273d2365b01SPavel Tatashin 		/*
1274d2365b01SPavel Tatashin 		 * If a CPU is already in a set as shown by cpuid2pset[], then
1275d2365b01SPavel Tatashin 		 * use that set.
1276d2365b01SPavel Tatashin 		 */
1277d2365b01SPavel Tatashin 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1278d2365b01SPavel Tatashin 			ASSERT(cpids[cp_idx] < NCPU);
1279d2365b01SPavel Tatashin 			ppset = cpuid2pset[cpids[cp_idx]];
1280d2365b01SPavel Tatashin 			if (ppset != NULL)
1281d2365b01SPavel Tatashin 				break;
1282d2365b01SPavel Tatashin 		}
1283d2365b01SPavel Tatashin 
1284d2365b01SPavel Tatashin 		/* No CPU has a set. Create a new one. */
1285d2365b01SPavel Tatashin 		if (ppset == NULL) {
1286d2365b01SPavel Tatashin 			ppset = kmem_alloc(sizeof (cpuset_t), KM_SLEEP);
1287d2365b01SPavel Tatashin 			CPUSET_ZERO(*ppset);
1288d2365b01SPavel Tatashin 		}
1289d2365b01SPavel Tatashin 
1290d2365b01SPavel Tatashin 		/* Add every CPU to the set, and record the set assignment. */
1291d2365b01SPavel Tatashin 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1292d2365b01SPavel Tatashin 			cpuid2pset[cpids[cp_idx]] = ppset;
1293d2365b01SPavel Tatashin 			CPUSET_ADD(*ppset, cpids[cp_idx]);
1294d2365b01SPavel Tatashin 		}
1295d2365b01SPavel Tatashin 	}
1296d2365b01SPavel Tatashin 
1297d2365b01SPavel Tatashin 	retval = 0;
1298d2365b01SPavel Tatashin 
1299d2365b01SPavel Tatashin cleanup:
1300d2365b01SPavel Tatashin 	if (tlbs != NULL)
1301d2365b01SPavel Tatashin 		md_free_scan_dag(mdp, &tlbs);
1302d2365b01SPavel Tatashin 	if (cp != NULL)
1303d2365b01SPavel Tatashin 		kmem_free(cp, sizeof (mde_cookie_t) * NCPU);
1304d2365b01SPavel Tatashin 	if (cpids != NULL)
1305d2365b01SPavel Tatashin 		kmem_free(cpids, sizeof (uint64_t) * NCPU);
1306d2365b01SPavel Tatashin 	if (mdp != NULL)
1307d2365b01SPavel Tatashin 		(void) md_fini_handle(mdp);
1308d2365b01SPavel Tatashin 
1309d2365b01SPavel Tatashin 	return (retval);
1310d2365b01SPavel Tatashin }
1311d2365b01SPavel Tatashin 
1312d2365b01SPavel Tatashin /*
1313d2365b01SPavel Tatashin  * Return MMU info based on cpuid.
1314d2365b01SPavel Tatashin  *
1315d2365b01SPavel Tatashin  * Algorithm:
1316d2365b01SPavel Tatashin  * Read machine descriptor and find all CPUs that share the same TLB with CPU
1317d2365b01SPavel Tatashin  * specified by cpuid. Go through found CPUs and see if any one of them already
1318d2365b01SPavel Tatashin  * has MMU index, if so, set index based on that value. If CPU does not share
1319d2365b01SPavel Tatashin  * TLB with any other CPU or if none of those CPUs has mmu_ctx pointer, find the
1320d2365b01SPavel Tatashin  * smallest available MMU index and give it to current CPU. If no available
1321d2365b01SPavel Tatashin  * domain, perform a round robin, and start assigning from the beginning.
1322d2365b01SPavel Tatashin  *
1323d2365b01SPavel Tatashin  * For optimization reasons, this function uses a cache to store all TLB to CPU
1324d2365b01SPavel Tatashin  * mappings, and updates them only when machine descriptor graph is changed.
1325d2365b01SPavel Tatashin  * Because of this, and because we search MMU table for smallest index id, this
1326d2365b01SPavel Tatashin  * function needs to be serialized which is protected by cpu_lock.
1327d2365b01SPavel Tatashin  */
1328d2365b01SPavel Tatashin void
plat_cpuid_to_mmu_ctx_info(processorid_t cpuid,mmu_ctx_info_t * info)1329d2365b01SPavel Tatashin plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info)
1330d2365b01SPavel Tatashin {
1331d2365b01SPavel Tatashin 	static cpuset_t	**cpuid2pset = NULL;
1332d2365b01SPavel Tatashin 	static uint_t	*nctxs;
1333d2365b01SPavel Tatashin 	static uint_t	next_domain = 0;
1334d2365b01SPavel Tatashin 	static uint64_t	md_gen = MDESC_INVAL_GEN;
1335d2365b01SPavel Tatashin 	uint64_t	current_gen;
1336d2365b01SPavel Tatashin 	int		idx;
1337d2365b01SPavel Tatashin 	cpuset_t	cpuid_pset;
1338d2365b01SPavel Tatashin 	processorid_t	id;
1339d2365b01SPavel Tatashin 	cpu_t		*cp;
1340d2365b01SPavel Tatashin 
1341d2365b01SPavel Tatashin 	ASSERT(MUTEX_HELD(&cpu_lock));
1342d2365b01SPavel Tatashin 
1343d2365b01SPavel Tatashin 	current_gen = md_get_current_gen();
1344d2365b01SPavel Tatashin 
1345d2365b01SPavel Tatashin 	/*
1346d2365b01SPavel Tatashin 	 * Load TLB CPU mappings only if MD generation has changed, FW that do
1347d2365b01SPavel Tatashin 	 * not provide generation number, always return MDESC_INVAL_GEN, and as
1348d2365b01SPavel Tatashin 	 * result MD is read here only once on such machines: when cpuid2pset is
1349d2365b01SPavel Tatashin 	 * NULL
1350d2365b01SPavel Tatashin 	 */
1351d2365b01SPavel Tatashin 	if (current_gen != md_gen || cpuid2pset == NULL) {
1352d2365b01SPavel Tatashin 		if (cpuid2pset == NULL) {
1353d2365b01SPavel Tatashin 			cpuid2pset = kmem_zalloc(sizeof (cpuset_t *) * NCPU,
1354d2365b01SPavel Tatashin 			    KM_SLEEP);
1355d2365b01SPavel Tatashin 			nctxs = kmem_alloc(sizeof (uint_t) * NCPU, KM_SLEEP);
1356d2365b01SPavel Tatashin 		} else {
1357d2365b01SPavel Tatashin 			/* clean cpuid2pset[NCPU], before loading new values */
1358d2365b01SPavel Tatashin 			for (idx = 0; idx < NCPU; idx++) {
1359d2365b01SPavel Tatashin 				cpuset_t *pset = cpuid2pset[idx];
1360d2365b01SPavel Tatashin 
1361d2365b01SPavel Tatashin 				if (pset != NULL) {
1362d2365b01SPavel Tatashin 					for (;;) {
1363d2365b01SPavel Tatashin 						CPUSET_FIND(*pset, id);
1364d2365b01SPavel Tatashin 						if (id == CPUSET_NOTINSET)
1365d2365b01SPavel Tatashin 							break;
1366d2365b01SPavel Tatashin 						CPUSET_DEL(*pset, id);
1367d2365b01SPavel Tatashin 						ASSERT(id < NCPU);
1368d2365b01SPavel Tatashin 						cpuid2pset[id] = NULL;
1369d2365b01SPavel Tatashin 					}
1370d2365b01SPavel Tatashin 					ASSERT(cpuid2pset[idx] == NULL);
1371d2365b01SPavel Tatashin 					kmem_free(pset, sizeof (cpuset_t));
1372d2365b01SPavel Tatashin 				}
1373d2365b01SPavel Tatashin 			}
1374d2365b01SPavel Tatashin 		}
1375d2365b01SPavel Tatashin 
1376d2365b01SPavel Tatashin 		if (load_tlb_cpu_mappings(cpuid2pset, nctxs, &md_gen))
1377d2365b01SPavel Tatashin 			goto error_panic;
1378d2365b01SPavel Tatashin 	}
1379d2365b01SPavel Tatashin 
1380d2365b01SPavel Tatashin 	info->mmu_nctxs = nctxs[cpuid];
1381d2365b01SPavel Tatashin 
1382d2365b01SPavel Tatashin 	if (cpuid2pset[cpuid] == NULL)
1383d2365b01SPavel Tatashin 		goto error_panic;
1384d2365b01SPavel Tatashin 
1385d2365b01SPavel Tatashin 	cpuid_pset = *cpuid2pset[cpuid];
1386d2365b01SPavel Tatashin 	CPUSET_DEL(cpuid_pset, cpuid);
1387d2365b01SPavel Tatashin 
1388d2365b01SPavel Tatashin 	/* Search for a processor in the same TLB pset with MMU context */
1389d2365b01SPavel Tatashin 	for (;;) {
1390d2365b01SPavel Tatashin 		CPUSET_FIND(cpuid_pset, id);
1391d2365b01SPavel Tatashin 
1392d2365b01SPavel Tatashin 		if (id == CPUSET_NOTINSET)
1393d2365b01SPavel Tatashin 			break;
1394d2365b01SPavel Tatashin 
1395d2365b01SPavel Tatashin 		ASSERT(id < NCPU);
1396d2365b01SPavel Tatashin 		cp = cpu[id];
1397d2365b01SPavel Tatashin 		if (cp != NULL && CPU_MMU_CTXP(cp) != NULL) {
1398d2365b01SPavel Tatashin 			info->mmu_idx = CPU_MMU_IDX(cp);
1399d2365b01SPavel Tatashin 
1400d2365b01SPavel Tatashin 			return;
1401d2365b01SPavel Tatashin 		}
1402d2365b01SPavel Tatashin 		CPUSET_DEL(cpuid_pset, id);
1403d2365b01SPavel Tatashin 	}
1404d2365b01SPavel Tatashin 
1405d2365b01SPavel Tatashin 	/*
1406d2365b01SPavel Tatashin 	 * No CPU in the TLB pset has a context domain yet.
1407d2365b01SPavel Tatashin 	 * Use next_domain if available, or search for an unused domain, or
1408d2365b01SPavel Tatashin 	 * overload next_domain, in that order.  Overloading is necessary when
1409d2365b01SPavel Tatashin 	 * the number of TLB psets is greater than max_mmu_ctxdoms.
1410d2365b01SPavel Tatashin 	 */
1411d2365b01SPavel Tatashin 	idx = next_domain;
1412d2365b01SPavel Tatashin 
1413d2365b01SPavel Tatashin 	if (mmu_ctxs_tbl[idx] != NULL) {
1414d2365b01SPavel Tatashin 		for (idx = 0; idx < max_mmu_ctxdoms; idx++)
1415d2365b01SPavel Tatashin 			if (mmu_ctxs_tbl[idx] == NULL)
1416d2365b01SPavel Tatashin 				break;
1417d2365b01SPavel Tatashin 		if (idx == max_mmu_ctxdoms) {
1418d2365b01SPavel Tatashin 			/* overload next_domain */
1419d2365b01SPavel Tatashin 			idx = next_domain;
1420d2365b01SPavel Tatashin 
1421d2365b01SPavel Tatashin 			if (info->mmu_nctxs < sfmmu_ctxdom_nctxs(idx))
1422d2365b01SPavel Tatashin 				cmn_err(CE_PANIC, "max_mmu_ctxdoms is too small"
1423d2365b01SPavel Tatashin 				    " to support CPUs with different nctxs");
1424d2365b01SPavel Tatashin 		}
1425d2365b01SPavel Tatashin 	}
1426d2365b01SPavel Tatashin 
1427d2365b01SPavel Tatashin 	info->mmu_idx = idx;
1428d2365b01SPavel Tatashin 	next_domain = (idx + 1) % max_mmu_ctxdoms;
1429d2365b01SPavel Tatashin 
1430d2365b01SPavel Tatashin 	return;
1431d2365b01SPavel Tatashin 
1432d2365b01SPavel Tatashin error_panic:
1433d2365b01SPavel Tatashin 	cmn_err(CE_PANIC, "!cpu%d: failed to get MMU CTX domain index", cpuid);
1434d2365b01SPavel Tatashin }
1435