xref: /onnv-gate/usr/src/uts/sun4v/os/mach_descrip.c (revision 11713:03615b084875)
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  */
211991Sheppo 
220Sstevel@tonic-gate /*
23*11713SPavel.Tatashin@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
271991Sheppo /*
281991Sheppo  * Kernel Machine Description (MD)
291991Sheppo  *
301991Sheppo  * The Kernel maintains a global copy of the machine description for
311991Sheppo  * the system. This is for use by all kernel subsystems and is exported
321991Sheppo  * to user applications through the the 'mdesc' device driver. It is
331991Sheppo  * initially copied in from the Hypervisor at boot time, but can be
341991Sheppo  * updated dynamically on demand. The Kernel provides an interface
351991Sheppo  * for consumers to obtain a handle to the global MD. Consumers of the
361991Sheppo  * MD must use the specified interfaces. An update interface is provided
371991Sheppo  * for platform services to intiate an MD update on notification by a
381991Sheppo  * service entity.
391991Sheppo  *
401991Sheppo  * Locks
411991Sheppo  * The current global MD is protected by the curr_mach_descrip_lock.
421991Sheppo  * Each Machine description has a lock to synchornize its ref count.
431991Sheppo  * The Obsolete MD list is protected by the obs_list_lock.
441991Sheppo  */
451991Sheppo 
460Sstevel@tonic-gate #include <sys/machsystm.h>
470Sstevel@tonic-gate #include <sys/vm.h>
480Sstevel@tonic-gate #include <sys/cpu.h>
490Sstevel@tonic-gate #include <sys/intreg.h>
500Sstevel@tonic-gate #include <sys/machcpuvar.h>
510Sstevel@tonic-gate #include <sys/machparam.h>
520Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
530Sstevel@tonic-gate #include <vm/seg_kmem.h>
540Sstevel@tonic-gate #include <sys/error.h>
550Sstevel@tonic-gate #include <sys/hypervisor_api.h>
560Sstevel@tonic-gate #include <sys/types.h>
570Sstevel@tonic-gate #include <sys/sysmacros.h>
581991Sheppo #include <sys/mdesc.h>
591991Sheppo #include <sys/mdesc_impl.h>
600Sstevel@tonic-gate #include <sys/mach_descrip.h>
611991Sheppo #include <sys/prom_plat.h>
621991Sheppo #include <sys/promif.h>
632531Snarayan #include <sys/ldoms.h>
641991Sheppo 
651991Sheppo static void *mach_descrip_strt_meta_alloc(size_t size);
661991Sheppo static void mach_descrip_strt_meta_free(void *buf, size_t size);
671991Sheppo static void *mach_descrip_strt_buf_alloc(size_t size, size_t align);
681991Sheppo static void mach_descrip_strt_buf_free(void *buf, size_t size);
691991Sheppo static void *mach_descrip_buf_alloc(size_t size, size_t align);
701991Sheppo static void *mach_descrip_meta_alloc(size_t size);
711991Sheppo static uint64_t mach_descrip_find_md_gen(caddr_t ptr);
721991Sheppo static void init_md_params(void);
732531Snarayan static void init_domaining_capabilities(md_t *mdp, mde_cookie_t *listp);
741991Sheppo 
751991Sheppo /*
761991Sheppo  * Global ptr of the current generation Machine Description
771991Sheppo  */
781991Sheppo static machine_descrip_t *curr_mach_descrip;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
811991Sheppo  * Initialized by machine_descrip_startup_init in startup.
821991Sheppo  * machine_descript_init will reintialize the structure with
831991Sheppo  * the vmem allocators once the vmem is available in the boot up
841991Sheppo  * process.
851991Sheppo  */
861991Sheppo static machine_descrip_memops_t *curr_mach_descrip_memops = NULL;
871991Sheppo 
881991Sheppo static machine_descrip_memops_t startup_memops = {
891991Sheppo 	mach_descrip_strt_buf_alloc,
901991Sheppo 	mach_descrip_strt_buf_free,
911991Sheppo 	mach_descrip_strt_meta_alloc,
921991Sheppo 	mach_descrip_strt_meta_free,
931991Sheppo };
941991Sheppo 
951991Sheppo static machine_descrip_memops_t mach_descrip_memops = {
961991Sheppo 	mach_descrip_buf_alloc,
971991Sheppo 	contig_mem_free,
981991Sheppo 	mach_descrip_meta_alloc,
991991Sheppo 	kmem_free,
1001991Sheppo };
1011991Sheppo 
1021991Sheppo static kmutex_t curr_mach_descrip_lock;
1031991Sheppo /*
1041991Sheppo  * List of obsolete Machine Descriptions
1051991Sheppo  * Machine descriptions that have users are put on this list
1061991Sheppo  * and freed after the last user has called md_fini_handle.
1070Sstevel@tonic-gate  */
1081991Sheppo static machine_descrip_t *obs_machine_descrip_list;
1090Sstevel@tonic-gate 
1101991Sheppo static kmutex_t obs_list_lock;
1111991Sheppo 
1121991Sheppo static const char alloc_fail_msg[] =
1131991Sheppo 	"MD: cannot allocate MD buffer of size %ld bytes\n";
1140Sstevel@tonic-gate 
1151991Sheppo /*
1162531Snarayan  * Global flags that indicate what domaining features are
1172531Snarayan  * available, if any. The value is set at boot time based on
1182531Snarayan  * the value of the 'domaining-enabled' property in the MD
1192531Snarayan  * and the global override flag below. Updates to this
1202531Snarayan  * variable after boot are not supported.
1211991Sheppo  */
1222531Snarayan uint_t domaining_capabilities;
1230Sstevel@tonic-gate 
1241991Sheppo /*
1252531Snarayan  * Global override for the 'domaining_capailities' flags. If this
1261991Sheppo  * flag is set in /etc/system, domaining features are disabled,
1271991Sheppo  * ignoring the value of the 'domaining-enabled' property in
1281991Sheppo  * the MD.
1291991Sheppo  */
1301991Sheppo uint_t force_domaining_disabled;
1310Sstevel@tonic-gate 
1322233Sarao #define	META_ALLOC_ALIGN	8
1331991Sheppo #define	HAS_GEN(x)	(x != MDESC_INVAL_GEN)
1341991Sheppo 
1351991Sheppo #ifdef DEBUG
1361991Sheppo static int mach_descrip_debug = 0;
1371991Sheppo 
1381991Sheppo #define	MDP(ARGS)	if (mach_descrip_debug) prom_printf ARGS
1391991Sheppo #define	PRINT_LIST() 	if (mach_descrip_debug) print_obs_list()
1401991Sheppo 
1411991Sheppo #ifdef	MACH_DESC_DEBUG
1420Sstevel@tonic-gate static void
dump_buf(uint8_t * bufp,int size)1430Sstevel@tonic-gate dump_buf(uint8_t *bufp, int size)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	int i;
1460Sstevel@tonic-gate 	for (i = 0; i < size; i += 16) {
1470Sstevel@tonic-gate 		int j;
1480Sstevel@tonic-gate 		prom_printf("0x%04x :", i);
1490Sstevel@tonic-gate 		for (j = 0; j < 16 && (i+j) < size; j++)
1500Sstevel@tonic-gate 			prom_printf(" %02x", bufp[i+j]);
1510Sstevel@tonic-gate 		prom_printf("\n");
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate }
1541991Sheppo #endif /* MACH_DESC_DEBUG */
1551991Sheppo 
1561991Sheppo static void
print_obs_list(void)1571991Sheppo print_obs_list(void)
1581991Sheppo {
1591991Sheppo 	machine_descrip_t *lmdescp;
1601991Sheppo 	mutex_enter(&obs_list_lock);
1611991Sheppo 
1621991Sheppo 	lmdescp	= obs_machine_descrip_list;
1631991Sheppo 	prom_printf("MD_obs_list->");
1641991Sheppo 	while (lmdescp != NULL) {
1651991Sheppo 		prom_printf("g:%ld,r:%d", lmdescp->gen, lmdescp->refcnt);
1661991Sheppo 
1671991Sheppo 		lmdescp = lmdescp->next;
1681991Sheppo 		prom_printf("->");
1691991Sheppo 	}
1701991Sheppo 	prom_printf("NULL\n");
1711991Sheppo 	mutex_exit(&obs_list_lock);
1721991Sheppo }
1731991Sheppo 
1740Sstevel@tonic-gate #else
1751991Sheppo #define	MDP(ARGS)
1761991Sheppo #define	PRINT_LIST()
1771991Sheppo #endif /* DEBUG */
1781991Sheppo 
1791991Sheppo /*
1801991Sheppo  * MD obsolete list managment functions
1811991Sheppo  */
1821991Sheppo static machine_descrip_t *
md_obs_list_look_up_by_gen(uint64_t gen)1831991Sheppo md_obs_list_look_up_by_gen(uint64_t gen)
1841991Sheppo {
1851991Sheppo 	machine_descrip_t *mdescp;
1861991Sheppo 
1871991Sheppo 	mutex_enter(&obs_list_lock);
1881991Sheppo 	mdescp = obs_machine_descrip_list;
1890Sstevel@tonic-gate 
1901991Sheppo 	while (mdescp != NULL) {
1911991Sheppo 		if (mdescp->gen == gen) {
1921991Sheppo 			mutex_exit(&obs_list_lock);
1931991Sheppo 			return (mdescp);
1941991Sheppo 		}
1951991Sheppo 		mdescp = mdescp->next;
1961991Sheppo 	}
1970Sstevel@tonic-gate 
1981991Sheppo 	mutex_exit(&obs_list_lock);
1991991Sheppo 	return (mdescp);
2001991Sheppo }
2011991Sheppo 
2021991Sheppo static void
md_obs_list_remove(machine_descrip_t * mdescp)2031991Sheppo md_obs_list_remove(machine_descrip_t *mdescp)
2041991Sheppo {
2051991Sheppo 	machine_descrip_t *lmdescp;
2061991Sheppo 
2071991Sheppo 	mutex_enter(&obs_list_lock);
2081991Sheppo 
2091991Sheppo 	lmdescp	= obs_machine_descrip_list;
2100Sstevel@tonic-gate 
2111991Sheppo 	if (obs_machine_descrip_list == mdescp) {
2121991Sheppo 		obs_machine_descrip_list = mdescp->next;
2131991Sheppo 	} else {
2141991Sheppo 		while (lmdescp != NULL) {
2151991Sheppo 			if (lmdescp->next == mdescp) {
2161991Sheppo 				lmdescp->next = mdescp->next;
2171991Sheppo 				mdescp->next = NULL;
2181991Sheppo 				break;
2191991Sheppo 			}
2201991Sheppo 			lmdescp = lmdescp->next;
2211991Sheppo 		}
2221991Sheppo 	}
2231991Sheppo 	mutex_exit(&obs_list_lock);
2241991Sheppo 	PRINT_LIST();
2251991Sheppo }
2260Sstevel@tonic-gate 
2271991Sheppo static void
md_obs_list_add(machine_descrip_t * mdescp)2281991Sheppo md_obs_list_add(machine_descrip_t *mdescp)
2291991Sheppo {
2301991Sheppo 	mutex_enter(&obs_list_lock);
2311991Sheppo 
2321991Sheppo 	mdescp->next = obs_machine_descrip_list;
2331991Sheppo 	obs_machine_descrip_list = mdescp;
2341991Sheppo 
2351991Sheppo 	mutex_exit(&obs_list_lock);
2361991Sheppo 	PRINT_LIST();
2371991Sheppo }
2381991Sheppo 
2391991Sheppo /*
2401991Sheppo  * Allocate a machine_descrip meta structure and intitialize it.
2411991Sheppo  */
2421991Sheppo static machine_descrip_t *
new_mach_descrip(void)2431991Sheppo new_mach_descrip(void)
2441991Sheppo {
2451991Sheppo 	machine_descrip_t *mdescp;
2460Sstevel@tonic-gate 
2471991Sheppo 	mdescp = (machine_descrip_t *)(*curr_mach_descrip_memops->meta_allocp)
2481991Sheppo 	    (sizeof (machine_descrip_t));
2491991Sheppo 	if (mdescp != NULL) {
2501991Sheppo 		bzero(mdescp, sizeof (*mdescp));
2511991Sheppo 		mdescp->memops = curr_mach_descrip_memops;
2521991Sheppo 		mutex_init(&mdescp->lock, NULL, MUTEX_DRIVER, NULL);
2531991Sheppo 	}
2541991Sheppo 
2551991Sheppo 	return (mdescp);
2561991Sheppo }
2571991Sheppo 
2581991Sheppo /*
2591991Sheppo  * Free a machine_descrip meta structure and intitialize it.
2601991Sheppo  * Also free the MD buffer.
2611991Sheppo  */
2621991Sheppo static void
destroy_machine_descrip(machine_descrip_t * mdescp)2631991Sheppo destroy_machine_descrip(machine_descrip_t *mdescp)
2640Sstevel@tonic-gate {
2651991Sheppo 	machine_descrip_memops_t  *mdesc_memopsp;
2661991Sheppo 
2671991Sheppo 	ASSERT((mdescp != NULL));
2681991Sheppo 
2691991Sheppo 	mdesc_memopsp = mdescp->memops;
2701991Sheppo 	if (mdescp->memops == NULL)
2711991Sheppo 		panic("destroy_machine_descrip: memops NULL\n");
2721991Sheppo 
2731991Sheppo 	(*mdesc_memopsp->buf_freep)(mdescp->va, mdescp->space);
2741991Sheppo 	mutex_destroy(&mdescp->lock);
2751991Sheppo 	(*mdesc_memopsp->meta_freep)(mdescp, sizeof (*mdescp));
2761991Sheppo }
2771991Sheppo 
2781991Sheppo /*
2791991Sheppo  * Call into the Hypervisor to retrieve the most recent copy of the
2801991Sheppo  * machine description. If references to the current MD are active
2811991Sheppo  * stow it in the obsolete MD list and update the current MD reference
2821991Sheppo  * with the new one.
2831991Sheppo  * The obsolete list contains one MD per generation. If the firmware
2841991Sheppo  * doesn't support MD generation fail the call.
2851991Sheppo  */
2861991Sheppo int
mach_descrip_update(void)2871991Sheppo mach_descrip_update(void)
2881991Sheppo {
2891991Sheppo 	uint64_t	md_size0, md_size;
2901991Sheppo 	uint64_t	md_space = 0;
2911991Sheppo 	uint64_t	hvret;
2921991Sheppo 	caddr_t		tbuf = NULL;
2931991Sheppo 	uint64_t	tbuf_pa;
2941991Sheppo 	uint64_t	tgen;
2951991Sheppo 	int		ret = 0;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	MDP(("MD: Requesting buffer size\n"));
2980Sstevel@tonic-gate 
2991991Sheppo 	ASSERT((curr_mach_descrip != NULL));
3001991Sheppo 
3011991Sheppo 	mutex_enter(&curr_mach_descrip_lock);
3020Sstevel@tonic-gate 
303288Sarao 	/*
3041991Sheppo 	 * If the required MD size changes between our first call
3051991Sheppo 	 * to hv_mach_desc (to find the required buf size) and the
3062600Sjm22469 	 * second call (to get the actual MD) and our allocated
3072600Sjm22469 	 * memory is insufficient, loop until we have allocated
3082600Sjm22469 	 * sufficient space.
309288Sarao 	 */
3101991Sheppo 	do {
3111991Sheppo 		if (tbuf != NULL)
3121991Sheppo 			(*curr_mach_descrip_memops->buf_freep)(tbuf, md_space);
3131991Sheppo 
3141991Sheppo 		md_size0 = 0LL;
3151991Sheppo 		(void) hv_mach_desc((uint64_t)0, &md_size0);
3161991Sheppo 		MDP(("MD: buffer size is %ld\n", md_size0));
3171991Sheppo 
3181991Sheppo 		/*
3191991Sheppo 		 * Align allocated space to nearest page.
3201991Sheppo 		 * contig_mem_alloc_align() requires a power of 2 alignment.
3211991Sheppo 		 */
3221991Sheppo 		md_space = P2ROUNDUP(md_size0, PAGESIZE);
3231991Sheppo 		MDP(("MD: allocated space is %ld\n", md_space));
3241991Sheppo 
3251991Sheppo 		tbuf = (caddr_t)(*curr_mach_descrip_memops->buf_allocp)
3261991Sheppo 		    (md_space, PAGESIZE);
3271991Sheppo 		if (tbuf == NULL) {
3281991Sheppo 			ret = -1;
3291991Sheppo 			goto done;
3301991Sheppo 		}
3310Sstevel@tonic-gate 
3321991Sheppo 		tbuf_pa =  va_to_pa(tbuf);
3332600Sjm22469 		md_size = md_space;
3341991Sheppo 		hvret = hv_mach_desc(tbuf_pa, &md_size);
3351991Sheppo 		MDP(("MD: HV return code = %ld\n", hvret));
3360Sstevel@tonic-gate 
3371991Sheppo 		/*
3381991Sheppo 		 * We get H_EINVAL if our buffer size is too small. In
3391991Sheppo 		 * that case stay in the loop, reallocate the buffer
3401991Sheppo 		 * and try again.
3411991Sheppo 		 */
3421991Sheppo 		if (hvret != H_EOK && hvret != H_EINVAL) {
3431991Sheppo 			MDP(("MD: Failed with code %ld from HV\n", hvret));
3441991Sheppo 			ret = -1;
3451991Sheppo 			goto done;
3461991Sheppo 		}
3470Sstevel@tonic-gate 
3482600Sjm22469 	} while (md_space < md_size);
3491991Sheppo 
3501991Sheppo 	tgen = mach_descrip_find_md_gen(tbuf);
3510Sstevel@tonic-gate 
3521991Sheppo #ifdef DEBUG
3531991Sheppo 	if (!HAS_GEN(tgen)) {
3541991Sheppo 		MDP(("MD: generation number not found\n"));
3551991Sheppo 	} else
3561991Sheppo 		MDP(("MD: generation number %ld\n", tgen));
3571991Sheppo #endif /* DEBUG */
3581991Sheppo 
3591991Sheppo 	if (curr_mach_descrip->va != NULL) {
3600Sstevel@tonic-gate 
3611991Sheppo 		/* check for the same generation number */
3621991Sheppo 		if (HAS_GEN(tgen) && ((curr_mach_descrip->gen == tgen) &&
3631991Sheppo 		    (curr_mach_descrip->size == md_size))) {
3641991Sheppo #ifdef DEBUG
3650Sstevel@tonic-gate 			/*
3661991Sheppo 			 * Pedantic Check for generation number. If the
3671991Sheppo 			 * generation number is the same, make sure the
3681991Sheppo 			 * MDs are really identical.
3690Sstevel@tonic-gate 			 */
3701991Sheppo 			if (bcmp(curr_mach_descrip->va, tbuf, md_size) != 0) {
3711991Sheppo 				cmn_err(CE_WARN, "machine_descrip_update: MDs "
3721991Sheppo 				    "with the same generation (%ld) are not "
3731991Sheppo 				    "identical", tgen);
3741991Sheppo 				ret = -1;
3751991Sheppo 				goto done;
3761991Sheppo 			}
3771991Sheppo #endif
3781991Sheppo 			ret = 0;
3791991Sheppo 			goto done;
3801991Sheppo 		}
3811991Sheppo 
3821991Sheppo 		/* check for generations moving backwards */
3831991Sheppo 		if (HAS_GEN(tgen) && HAS_GEN(curr_mach_descrip->gen) &&
3841991Sheppo 		    (curr_mach_descrip->gen > tgen)) {
3851991Sheppo 			cmn_err(CE_WARN, "machine_descrip_update: new MD"
3861991Sheppo 			    " older generation (%ld) than current MD (%ld)",
3871991Sheppo 			    tgen, curr_mach_descrip->gen);
3881991Sheppo 			ret = -1;
3891991Sheppo 			goto done;
3901991Sheppo 		}
3911991Sheppo 
3921991Sheppo 		if (curr_mach_descrip->refcnt == 0) {
3931991Sheppo 
3941991Sheppo 			MDP(("MD: freeing old md buffer gen %ld\n",
3951991Sheppo 			    curr_mach_descrip->gen));
3960Sstevel@tonic-gate 
3971991Sheppo 			/* Free old space */
3981991Sheppo 			ASSERT(curr_mach_descrip->space > 0);
3991991Sheppo 
4001991Sheppo 			(*curr_mach_descrip_memops->buf_freep)
4011991Sheppo 			    (curr_mach_descrip->va, curr_mach_descrip->space);
4020Sstevel@tonic-gate 		} else {
4031991Sheppo 			if (!HAS_GEN(tgen)) {
4041991Sheppo 				/*
4051991Sheppo 				 * No update support if FW
4061991Sheppo 				 * doesn't have MD generation id
4071991Sheppo 				 * feature.
4081991Sheppo 				 */
4091991Sheppo 				prom_printf("WARNING: F/W does not support MD "
4101991Sheppo 				    "generation count, MD update failed\n");
4111991Sheppo 				ret = -1;
4121991Sheppo 				goto done;
4131991Sheppo 			}
4141991Sheppo 
4151991Sheppo 			MDP(("MD: adding to obs list %ld\n",
4161991Sheppo 			    curr_mach_descrip->gen));
4171991Sheppo 
4181991Sheppo 			md_obs_list_add(curr_mach_descrip);
4191991Sheppo 
4201991Sheppo 			curr_mach_descrip = new_mach_descrip();
4211991Sheppo 
4221991Sheppo 			if (curr_mach_descrip == NULL) {
4231991Sheppo 				panic("Allocation for machine description"
4241991Sheppo 				    " failed\n");
4251991Sheppo 			}
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 	}
4281991Sheppo 
4291991Sheppo 	curr_mach_descrip->va = tbuf;
4301991Sheppo 	curr_mach_descrip->gen = tgen;
4311991Sheppo 	curr_mach_descrip->size = md_size;
4321991Sheppo 	curr_mach_descrip->space = md_space;
4331991Sheppo 
4341991Sheppo #ifdef MACH_DESC_DEBUG
4351991Sheppo 	dump_buf((uint8_t *)curr_mach_descrip->va, md_size);
4361991Sheppo #endif /* MACH_DESC_DEBUG */
4371991Sheppo 
4381991Sheppo 	mutex_exit(&curr_mach_descrip_lock);
4391991Sheppo 	return (ret);
4401991Sheppo 
4411991Sheppo done:
4421991Sheppo 	if (tbuf != NULL)
4431991Sheppo 		(*curr_mach_descrip_memops->buf_freep)(tbuf, md_space);
4441991Sheppo 	mutex_exit(&curr_mach_descrip_lock);
4451991Sheppo 	return (ret);
4460Sstevel@tonic-gate }
4471991Sheppo 
4481991Sheppo static void *
mach_descrip_buf_alloc(size_t size,size_t align)4491991Sheppo mach_descrip_buf_alloc(size_t size, size_t align)
4501991Sheppo {
4511991Sheppo 	void *p;
4521991Sheppo 
4531991Sheppo 	if ((p = contig_mem_alloc_align(size, align)) == NULL)
4541991Sheppo 		cmn_err(CE_WARN, alloc_fail_msg, size);
4551991Sheppo 
4561991Sheppo 	return (p);
4571991Sheppo }
4581991Sheppo 
4591991Sheppo static void *
mach_descrip_strt_meta_alloc(size_t size)4601991Sheppo mach_descrip_strt_meta_alloc(size_t size)
4611991Sheppo {
4622233Sarao 	return (mach_descrip_strt_buf_alloc(size, META_ALLOC_ALIGN));
4631991Sheppo }
4641991Sheppo 
4651991Sheppo static void
mach_descrip_strt_meta_free(void * buf,size_t size)4661991Sheppo mach_descrip_strt_meta_free(void *buf, size_t size)
4671991Sheppo {
4682233Sarao 	mach_descrip_strt_buf_free(buf, size);
4691991Sheppo }
4701991Sheppo 
4711991Sheppo static void *
mach_descrip_strt_buf_alloc(size_t size,size_t align)4721991Sheppo mach_descrip_strt_buf_alloc(size_t size, size_t align)
4731991Sheppo {
4741991Sheppo 	void *p = prom_alloc((caddr_t)0, size, align);
4751991Sheppo 
4761991Sheppo 	if (p == NULL)
4771991Sheppo 		prom_printf(alloc_fail_msg, size);
4781991Sheppo 
4791991Sheppo 	return (p);
4801991Sheppo }
4811991Sheppo 
4821991Sheppo static void
mach_descrip_strt_buf_free(void * buf,size_t size)4831991Sheppo mach_descrip_strt_buf_free(void *buf, size_t size)
4841991Sheppo {
4851991Sheppo 	prom_free((caddr_t)buf, size);
4861991Sheppo }
4871991Sheppo 
4881991Sheppo static void *
mach_descrip_meta_alloc(size_t size)4891991Sheppo mach_descrip_meta_alloc(size_t size)
4901991Sheppo {
4911991Sheppo 	return (kmem_alloc(size, KM_SLEEP));
4921991Sheppo }
4931991Sheppo 
4941991Sheppo /*
4951991Sheppo  * Initialize the kernel's Machine Description(MD) framework
4961991Sheppo  * early on in startup during mlsetup() so consumers
4971991Sheppo  * can get to the MD before the VM system has been initialized.
4981991Sheppo  *
4991991Sheppo  * Also get the most recent version of the MD.
5001991Sheppo  */
5011991Sheppo void
mach_descrip_startup_init(void)5021991Sheppo mach_descrip_startup_init(void)
5031991Sheppo {
5041991Sheppo 
5051991Sheppo 	mutex_init(&curr_mach_descrip_lock, NULL, MUTEX_DRIVER, NULL);
5061991Sheppo 	mutex_init(&obs_list_lock, NULL, MUTEX_DRIVER, NULL);
5071991Sheppo 
5081991Sheppo 	obs_machine_descrip_list = NULL;
5091991Sheppo 
5101991Sheppo 	curr_mach_descrip_memops = &startup_memops;
5111991Sheppo 
5121991Sheppo 	curr_mach_descrip = new_mach_descrip();
5131991Sheppo 	if (curr_mach_descrip == NULL)
5141991Sheppo 		panic("Allocation for machine description failed\n");
5151991Sheppo 
5161991Sheppo 	if (mach_descrip_update())
5171991Sheppo 		panic("Machine description initialization failed\n");
5181991Sheppo 
5191991Sheppo }
5201991Sheppo 
5211991Sheppo /*
5221991Sheppo  * Counterpart to the above init function.  Free up resources
5231991Sheppo  * allocated at startup by mach_descrip_startup_setup().
5241991Sheppo  * And reset machine description framework state.
5251991Sheppo  *
5261991Sheppo  * All consumers must have fini'ed their handles at this point.
5271991Sheppo  */
5281991Sheppo void
mach_descrip_startup_fini(void)5291991Sheppo mach_descrip_startup_fini(void)
5301991Sheppo {
5311991Sheppo 
5321991Sheppo 	ASSERT((curr_mach_descrip != NULL));
5331991Sheppo 	ASSERT((curr_mach_descrip->refcnt == 0));
5341991Sheppo 	ASSERT((obs_machine_descrip_list == NULL));
5351991Sheppo 
5361991Sheppo 	destroy_machine_descrip(curr_mach_descrip);
5371991Sheppo 	curr_mach_descrip = NULL;
5381991Sheppo 	curr_mach_descrip_memops = NULL;
5391991Sheppo }
5401991Sheppo 
5411991Sheppo /*
5421991Sheppo  * Initialize the kernel's Machine Description(MD) framework
5431991Sheppo  * after the the VM system has been initialized.
5441991Sheppo  *
5451991Sheppo  * Also get the most recent version of the MD.
5461991Sheppo  * Assumes that the machine description frame work is in a clean
5471991Sheppo  * state and the machine description intialized during startup
5481991Sheppo  * has been cleaned up and resources deallocated.
5491991Sheppo  */
5501991Sheppo void
mach_descrip_init(void)5511991Sheppo mach_descrip_init(void)
5521991Sheppo {
5531991Sheppo 	ASSERT((curr_mach_descrip == NULL &&
5541991Sheppo 	    curr_mach_descrip_memops == NULL));
5551991Sheppo 
5561991Sheppo 	curr_mach_descrip_memops = &mach_descrip_memops;
5571991Sheppo 
5581991Sheppo 	curr_mach_descrip = new_mach_descrip();
5591991Sheppo 	if (curr_mach_descrip == NULL)
5601991Sheppo 		panic("Allocation for machine description failed\n");
5611991Sheppo 
5621991Sheppo 	if (mach_descrip_update())
5631991Sheppo 		panic("Machine description intialization failed\n");
5641991Sheppo 
5651991Sheppo 	/* read in global params */
5661991Sheppo 	init_md_params();
5671991Sheppo }
5681991Sheppo 
5691991Sheppo /*
5701991Sheppo  * Client interface to get a handle to the current MD.
5711991Sheppo  * The md_fini_handle() interface should be used to
5721991Sheppo  * clean up the refernce to the MD returned by this function.
5731991Sheppo  */
5741991Sheppo md_t *
md_get_handle(void)5751991Sheppo md_get_handle(void)
5761991Sheppo {
5771991Sheppo 	md_t *mdp;
5781991Sheppo 
5792600Sjm22469 	mdp = NULL;
5802600Sjm22469 
5811991Sheppo 	mutex_enter(&curr_mach_descrip_lock);
5821991Sheppo 
5832600Sjm22469 	if (curr_mach_descrip != NULL) {
5841991Sheppo 
5852600Sjm22469 		mdp = md_init_intern(curr_mach_descrip->va,
5862600Sjm22469 		    curr_mach_descrip->memops->meta_allocp,
5872600Sjm22469 		    curr_mach_descrip->memops->meta_freep);
5882600Sjm22469 
5892600Sjm22469 		if (mdp != NULL)
5902600Sjm22469 			curr_mach_descrip->refcnt++;
5912600Sjm22469 	}
5921991Sheppo 
5931991Sheppo 	mutex_exit(&curr_mach_descrip_lock);
5941991Sheppo 
5951991Sheppo 	return (mdp);
5961991Sheppo }
5971991Sheppo 
5981991Sheppo /*
5991991Sheppo  * Client interface to clean up the refernce to the MD returned
6001991Sheppo  * by md_get_handle().
6011991Sheppo  */
6021991Sheppo int
md_fini_handle(md_t * ptr)6031991Sheppo md_fini_handle(md_t *ptr)
6041991Sheppo {
6051991Sheppo 	machine_descrip_t *mdescp;
6061991Sheppo 	md_impl_t *mdp;
6071991Sheppo 
6081991Sheppo 
6091991Sheppo 	mdp = (md_impl_t *)ptr;
6101991Sheppo 
6111991Sheppo 	if (mdp == NULL)
6121991Sheppo 		return (-1);
6131991Sheppo 	/*
6141991Sheppo 	 * Check if mdp is current MD gen
6151991Sheppo 	 */
6161991Sheppo 	mutex_enter(&curr_mach_descrip_lock);
6171991Sheppo 
6181991Sheppo 	if (curr_mach_descrip->gen == mdp->gen) {
6191991Sheppo 		curr_mach_descrip->refcnt--;
6201991Sheppo 		mutex_exit(&curr_mach_descrip_lock);
6211991Sheppo 		goto fini;
6221991Sheppo 	}
6231991Sheppo 	mutex_exit(&curr_mach_descrip_lock);
6241991Sheppo 
6251991Sheppo 	/*
6261991Sheppo 	 * MD is in the obsolete list
6271991Sheppo 	 */
6281991Sheppo 	mdescp = md_obs_list_look_up_by_gen(mdp->gen);
6291991Sheppo 	if (mdescp == NULL)
6301991Sheppo 		return (-1);
6311991Sheppo 
6321991Sheppo 	mutex_enter(&mdescp->lock);
6331991Sheppo 	mdescp->refcnt--;
6341991Sheppo 	if (mdescp->refcnt == 0) {
6351991Sheppo 		md_obs_list_remove(mdescp);
6361991Sheppo 		mutex_exit(&mdescp->lock);
6371991Sheppo 		destroy_machine_descrip(mdescp);
6381991Sheppo 		goto fini;
6391991Sheppo 	}
6401991Sheppo 	mutex_exit(&mdescp->lock);
6411991Sheppo 
6421991Sheppo fini:
6431991Sheppo 	return (md_fini(ptr));
6441991Sheppo }
6451991Sheppo 
6461991Sheppo /*
6471991Sheppo  * General purpose initialization function used to extract parameters
6481991Sheppo  * from the MD during the boot process. This is called immediately after
6491991Sheppo  * the in kernel copy of the MD has been initialized so that global
6501991Sheppo  * flags are available to various subsystems as they get initialized.
6511991Sheppo  */
6521991Sheppo static void
init_md_params(void)6531991Sheppo init_md_params(void)
6541991Sheppo {
6551991Sheppo 	md_t		*mdp;
6561991Sheppo 	int		num_nodes;
6571991Sheppo 	mde_cookie_t	*listp;
6581991Sheppo 	int		listsz;
6591991Sheppo 
6601991Sheppo 	mdp = md_get_handle();
6611991Sheppo 	ASSERT(mdp);
6621991Sheppo 	num_nodes = md_node_count(mdp);
6631991Sheppo 	ASSERT(num_nodes >= 0);
6641991Sheppo 
6651991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
6661991Sheppo 	listp = (mde_cookie_t *)
6671991Sheppo 	    (*curr_mach_descrip_memops->meta_allocp)(listsz);
6681991Sheppo 
6691991Sheppo 	/*
6701991Sheppo 	 * Import various parameters from the MD. For now,
6711991Sheppo 	 * the only parameter of interest is whether or not
6721991Sheppo 	 * domaining features are supported.
6731991Sheppo 	 */
6742531Snarayan 	init_domaining_capabilities(mdp, listp);
6751991Sheppo 
6761991Sheppo 	(*curr_mach_descrip_memops->meta_freep)(listp, listsz);
6771991Sheppo 	(void) md_fini_handle(mdp);
6781991Sheppo }
6791991Sheppo 
6801991Sheppo static void
init_domaining_capabilities(md_t * mdp,mde_cookie_t * listp)6812531Snarayan init_domaining_capabilities(md_t *mdp, mde_cookie_t *listp)
6821991Sheppo {
6831991Sheppo 	mde_cookie_t	rootnode;
6841991Sheppo 	int		num_nodes;
6851991Sheppo 	uint64_t	val = 0;
6861991Sheppo 
6871991Sheppo 	rootnode = md_root_node(mdp);
6881991Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
6891991Sheppo 
6901991Sheppo 	num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
6911991Sheppo 	    md_find_name(mdp, "fwd"), listp);
6921991Sheppo 
6931991Sheppo 	/* should only be one platform node */
6941991Sheppo 	ASSERT(num_nodes == 1);
6951991Sheppo 
6961991Sheppo 	if (md_get_prop_val(mdp, *listp, "domaining-enabled", &val) != 0) {
6971991Sheppo 		/*
6981991Sheppo 		 * The property is not present. This implies
6991991Sheppo 		 * that the firmware does not support domaining
7001991Sheppo 		 * features.
7011991Sheppo 		 */
7021991Sheppo 		MDP(("'domaining-enabled' property not present\n"));
7031991Sheppo 
7042531Snarayan 		domaining_capabilities = 0;
7051991Sheppo 		return;
7061991Sheppo 	}
7071991Sheppo 
7082531Snarayan 	domaining_capabilities = DOMAINING_SUPPORTED;
7091991Sheppo 
7102531Snarayan 	if (val == 1) {
7112531Snarayan 		if (force_domaining_disabled) {
7122531Snarayan 			MDP(("domaining manually disabled\n"));
7132531Snarayan 		} else {
7142531Snarayan 			domaining_capabilities |= DOMAINING_ENABLED;
7152531Snarayan 		}
7162531Snarayan 	}
7172531Snarayan 
7182531Snarayan 	MDP(("domaining_capabilities= 0x%x\n", domaining_capabilities));
7191991Sheppo }
7201991Sheppo 
7211991Sheppo /*
7221991Sheppo  * Client interface to get a pointer to the raw MD buffer
7231991Sheppo  * Private to kernel and mdesc driver.
7241991Sheppo  */
7251991Sheppo caddr_t
md_get_md_raw(md_t * ptr)7261991Sheppo md_get_md_raw(md_t *ptr)
7271991Sheppo {
7281991Sheppo 	md_impl_t *mdp;
7291991Sheppo 
7301991Sheppo 	mdp = (md_impl_t *)ptr;
7311991Sheppo 	if (mdp ==  NULL)
7321991Sheppo 		return (NULL);
7331991Sheppo 	return (mdp->caddr);
7341991Sheppo }
7351991Sheppo 
7361991Sheppo /*
7371991Sheppo  * This is called before an MD structure is intialized, so
7381991Sheppo  * it walks the raw MD looking for the generation property.
7391991Sheppo  */
7401991Sheppo static uint64_t
mach_descrip_find_md_gen(caddr_t ptr)7411991Sheppo mach_descrip_find_md_gen(caddr_t ptr)
7421991Sheppo {
7431991Sheppo 	md_header_t	*hdrp;
7441991Sheppo 	md_element_t	*mdep;
7451991Sheppo 	md_element_t	*rootnode = NULL;
7461991Sheppo 	md_element_t	*elem = NULL;
7471991Sheppo 	char		*namep;
7481991Sheppo 	boolean_t	done;
7491991Sheppo 	int		idx;
7501991Sheppo 
7511991Sheppo 	hdrp = (md_header_t *)ptr;
7521991Sheppo 	mdep = (md_element_t *)(ptr + MD_HEADER_SIZE);
7531991Sheppo 	namep = (char *)(ptr + MD_HEADER_SIZE + hdrp->node_blk_sz);
7541991Sheppo 
7551991Sheppo 	/*
7561991Sheppo 	 * Very basic check for alignment to avoid
7571991Sheppo 	 * bus error issues.
7581991Sheppo 	 */
7591991Sheppo 	if ((((uint64_t)ptr) & 7) != 0)
7601991Sheppo 		return (MDESC_INVAL_GEN);
7611991Sheppo 
7621991Sheppo 	if (mdtoh32(hdrp->transport_version) != MD_TRANSPORT_VERSION) {
7631991Sheppo 		return (MDESC_INVAL_GEN);
7641991Sheppo 	}
7651991Sheppo 
7661991Sheppo 	/*
7671991Sheppo 	 * Search for the root node. Perform the walk manually
7681991Sheppo 	 * since the MD structure is not set up yet.
7691991Sheppo 	 */
7701991Sheppo 	for (idx = 0, done = B_FALSE; done == B_FALSE; ) {
7711991Sheppo 
7721991Sheppo 		md_element_t *np = &(mdep[idx]);
7731991Sheppo 
7741991Sheppo 		switch (MDE_TAG(np)) {
7751991Sheppo 		case MDET_LIST_END:
7761991Sheppo 			done = B_TRUE;
7771991Sheppo 			break;
7781991Sheppo 
7791991Sheppo 		case MDET_NODE:
7801991Sheppo 			if (strcmp(namep + MDE_NAME(np), "root") == 0) {
7811991Sheppo 				/* found root node */
7821991Sheppo 				rootnode = np;
7831991Sheppo 				done = B_TRUE;
7841991Sheppo 				break;
7851991Sheppo 			}
7861991Sheppo 			idx = MDE_PROP_INDEX(np);
7871991Sheppo 			break;
7881991Sheppo 
7891991Sheppo 		default:
7901991Sheppo 			/* ignore */
7911991Sheppo 			idx++;
7921991Sheppo 		}
7931991Sheppo 	}
7941991Sheppo 
7951991Sheppo 	if (rootnode == NULL) {
7961991Sheppo 		/* root not found */
7971991Sheppo 		return (MDESC_INVAL_GEN);
7981991Sheppo 	}
7991991Sheppo 
8001991Sheppo 	/* search the rootnode for the generation property */
8011991Sheppo 	for (elem = (rootnode + 1); MDE_TAG(elem) != MDET_NODE_END; elem++) {
8021991Sheppo 
8031991Sheppo 		char *prop_name;
8041991Sheppo 
8051991Sheppo 		/* generation field is a prop_val */
8061991Sheppo 		if (MDE_TAG(elem) != MDET_PROP_VAL)
8071991Sheppo 			continue;
8081991Sheppo 
8091991Sheppo 		prop_name = namep + MDE_NAME(elem);
8101991Sheppo 
8111991Sheppo 		if (strcmp(prop_name, "md-generation#") == 0) {
8121991Sheppo 			return (MDE_PROP_VALUE(elem));
8131991Sheppo 		}
8141991Sheppo 	}
8151991Sheppo 
8161991Sheppo 	return (MDESC_INVAL_GEN);
8171991Sheppo }
8181991Sheppo 
8191991Sheppo /*
8201991Sheppo  * Failed to allocate the list : Return value -1
8211991Sheppo  * md_scan_dag API failed      : Return the result from md_scan_dag API
8221991Sheppo  */
8231991Sheppo int
md_alloc_scan_dag(md_t * ptr,mde_cookie_t startnode,char * node_name,char * dag,mde_cookie_t ** list)8241991Sheppo md_alloc_scan_dag(md_t *ptr,
8251991Sheppo 	mde_cookie_t startnode,
8261991Sheppo 	char *node_name,
8271991Sheppo 	char *dag,
8281991Sheppo 	mde_cookie_t **list)
8291991Sheppo {
8301991Sheppo 	int res;
8311991Sheppo 	md_impl_t *mdp = (md_impl_t *)ptr;
8321991Sheppo 
8331991Sheppo 	*list = (mde_cookie_t *)mdp->allocp(sizeof (mde_cookie_t) *
8341991Sheppo 	    mdp->node_count);
8351991Sheppo 	if (*list == NULL)
8361991Sheppo 		return (-1);
8371991Sheppo 
8381991Sheppo 	res = md_scan_dag(ptr, startnode,
8391991Sheppo 	    md_find_name(ptr, node_name),
8401991Sheppo 	    md_find_name(ptr, dag), *list);
8411991Sheppo 
8421991Sheppo 	/*
8431991Sheppo 	 * If md_scan_dag API returned 0 or -1 then free the buffer
8441991Sheppo 	 * and return -1 to indicate the error from this API.
8451991Sheppo 	 */
8461991Sheppo 	if (res < 1) {
8471991Sheppo 		md_free_scan_dag(ptr, list);
8481991Sheppo 		*list = NULL;
8491991Sheppo 	}
8501991Sheppo 
8511991Sheppo 	return (res);
8521991Sheppo }
8531991Sheppo 
8541991Sheppo void
md_free_scan_dag(md_t * ptr,mde_cookie_t ** list)8551991Sheppo md_free_scan_dag(md_t *ptr,
8561991Sheppo 	mde_cookie_t **list)
8571991Sheppo {
8581991Sheppo 	md_impl_t *mdp = (md_impl_t *)ptr;
8591991Sheppo 
8601991Sheppo 	mdp->freep(*list, sizeof (mde_cookie_t) * mdp->node_count);
8611991Sheppo }
862*11713SPavel.Tatashin@Sun.COM 
863*11713SPavel.Tatashin@Sun.COM /*
864*11713SPavel.Tatashin@Sun.COM  * Return generation number of current machine descriptor. Can be used for
865*11713SPavel.Tatashin@Sun.COM  * performance purposes to avoid requesting new md handle just to see if graph
866*11713SPavel.Tatashin@Sun.COM  * was updated.
867*11713SPavel.Tatashin@Sun.COM  */
868*11713SPavel.Tatashin@Sun.COM uint64_t
md_get_current_gen(void)869*11713SPavel.Tatashin@Sun.COM md_get_current_gen(void)
870*11713SPavel.Tatashin@Sun.COM {
871*11713SPavel.Tatashin@Sun.COM 	uint64_t gen = MDESC_INVAL_GEN;
872*11713SPavel.Tatashin@Sun.COM 
873*11713SPavel.Tatashin@Sun.COM 	mutex_enter(&curr_mach_descrip_lock);
874*11713SPavel.Tatashin@Sun.COM 
875*11713SPavel.Tatashin@Sun.COM 	if (curr_mach_descrip != NULL)
876*11713SPavel.Tatashin@Sun.COM 		gen = (curr_mach_descrip->gen);
877*11713SPavel.Tatashin@Sun.COM 
878*11713SPavel.Tatashin@Sun.COM 	mutex_exit(&curr_mach_descrip_lock);
879*11713SPavel.Tatashin@Sun.COM 
880*11713SPavel.Tatashin@Sun.COM 	return (gen);
881*11713SPavel.Tatashin@Sun.COM }
882