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 */
211ae08745Sheppo
227c478bd9Sstevel@tonic-gate /*
23*d2365b01SPavel Tatashin * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
271ae08745Sheppo /*
281ae08745Sheppo * Kernel Machine Description (MD)
291ae08745Sheppo *
301ae08745Sheppo * The Kernel maintains a global copy of the machine description for
311ae08745Sheppo * the system. This is for use by all kernel subsystems and is exported
321ae08745Sheppo * to user applications through the the 'mdesc' device driver. It is
331ae08745Sheppo * initially copied in from the Hypervisor at boot time, but can be
341ae08745Sheppo * updated dynamically on demand. The Kernel provides an interface
351ae08745Sheppo * for consumers to obtain a handle to the global MD. Consumers of the
361ae08745Sheppo * MD must use the specified interfaces. An update interface is provided
371ae08745Sheppo * for platform services to intiate an MD update on notification by a
381ae08745Sheppo * service entity.
391ae08745Sheppo *
401ae08745Sheppo * Locks
411ae08745Sheppo * The current global MD is protected by the curr_mach_descrip_lock.
421ae08745Sheppo * Each Machine description has a lock to synchornize its ref count.
431ae08745Sheppo * The Obsolete MD list is protected by the obs_list_lock.
441ae08745Sheppo */
451ae08745Sheppo
467c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
477c478bd9Sstevel@tonic-gate #include <sys/vm.h>
487c478bd9Sstevel@tonic-gate #include <sys/cpu.h>
497c478bd9Sstevel@tonic-gate #include <sys/intreg.h>
507c478bd9Sstevel@tonic-gate #include <sys/machcpuvar.h>
517c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
527c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
537c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
547c478bd9Sstevel@tonic-gate #include <sys/error.h>
557c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h>
567c478bd9Sstevel@tonic-gate #include <sys/types.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
581ae08745Sheppo #include <sys/mdesc.h>
591ae08745Sheppo #include <sys/mdesc_impl.h>
607c478bd9Sstevel@tonic-gate #include <sys/mach_descrip.h>
611ae08745Sheppo #include <sys/prom_plat.h>
621ae08745Sheppo #include <sys/promif.h>
634bac2208Snarayan #include <sys/ldoms.h>
641ae08745Sheppo
651ae08745Sheppo static void *mach_descrip_strt_meta_alloc(size_t size);
661ae08745Sheppo static void mach_descrip_strt_meta_free(void *buf, size_t size);
671ae08745Sheppo static void *mach_descrip_strt_buf_alloc(size_t size, size_t align);
681ae08745Sheppo static void mach_descrip_strt_buf_free(void *buf, size_t size);
691ae08745Sheppo static void *mach_descrip_buf_alloc(size_t size, size_t align);
701ae08745Sheppo static void *mach_descrip_meta_alloc(size_t size);
711ae08745Sheppo static uint64_t mach_descrip_find_md_gen(caddr_t ptr);
721ae08745Sheppo static void init_md_params(void);
734bac2208Snarayan static void init_domaining_capabilities(md_t *mdp, mde_cookie_t *listp);
741ae08745Sheppo
757c478bd9Sstevel@tonic-gate /*
761ae08745Sheppo * Global ptr of the current generation Machine Description
777c478bd9Sstevel@tonic-gate */
781ae08745Sheppo static machine_descrip_t *curr_mach_descrip;
797c478bd9Sstevel@tonic-gate
801ae08745Sheppo /*
811ae08745Sheppo * Initialized by machine_descrip_startup_init in startup.
821ae08745Sheppo * machine_descript_init will reintialize the structure with
831ae08745Sheppo * the vmem allocators once the vmem is available in the boot up
841ae08745Sheppo * process.
851ae08745Sheppo */
861ae08745Sheppo static machine_descrip_memops_t *curr_mach_descrip_memops = NULL;
877c478bd9Sstevel@tonic-gate
881ae08745Sheppo static machine_descrip_memops_t startup_memops = {
891ae08745Sheppo mach_descrip_strt_buf_alloc,
901ae08745Sheppo mach_descrip_strt_buf_free,
911ae08745Sheppo mach_descrip_strt_meta_alloc,
921ae08745Sheppo mach_descrip_strt_meta_free,
931ae08745Sheppo };
947c478bd9Sstevel@tonic-gate
951ae08745Sheppo static machine_descrip_memops_t mach_descrip_memops = {
961ae08745Sheppo mach_descrip_buf_alloc,
971ae08745Sheppo contig_mem_free,
981ae08745Sheppo mach_descrip_meta_alloc,
991ae08745Sheppo kmem_free,
1001ae08745Sheppo };
1011ae08745Sheppo
1021ae08745Sheppo static kmutex_t curr_mach_descrip_lock;
1031ae08745Sheppo /*
1041ae08745Sheppo * List of obsolete Machine Descriptions
1051ae08745Sheppo * Machine descriptions that have users are put on this list
1061ae08745Sheppo * and freed after the last user has called md_fini_handle.
1071ae08745Sheppo */
1081ae08745Sheppo static machine_descrip_t *obs_machine_descrip_list;
1091ae08745Sheppo
1101ae08745Sheppo static kmutex_t obs_list_lock;
1111ae08745Sheppo
1121ae08745Sheppo static const char alloc_fail_msg[] =
1131ae08745Sheppo "MD: cannot allocate MD buffer of size %ld bytes\n";
1141ae08745Sheppo
1151ae08745Sheppo /*
1164bac2208Snarayan * Global flags that indicate what domaining features are
1174bac2208Snarayan * available, if any. The value is set at boot time based on
1184bac2208Snarayan * the value of the 'domaining-enabled' property in the MD
1194bac2208Snarayan * and the global override flag below. Updates to this
1204bac2208Snarayan * variable after boot are not supported.
1211ae08745Sheppo */
1224bac2208Snarayan uint_t domaining_capabilities;
1231ae08745Sheppo
1241ae08745Sheppo /*
1254bac2208Snarayan * Global override for the 'domaining_capailities' flags. If this
1261ae08745Sheppo * flag is set in /etc/system, domaining features are disabled,
1271ae08745Sheppo * ignoring the value of the 'domaining-enabled' property in
1281ae08745Sheppo * the MD.
1291ae08745Sheppo */
1301ae08745Sheppo uint_t force_domaining_disabled;
1311ae08745Sheppo
1329bb6917bSarao #define META_ALLOC_ALIGN 8
1331ae08745Sheppo #define HAS_GEN(x) (x != MDESC_INVAL_GEN)
1341ae08745Sheppo
1351ae08745Sheppo #ifdef DEBUG
1361ae08745Sheppo static int mach_descrip_debug = 0;
1371ae08745Sheppo
1381ae08745Sheppo #define MDP(ARGS) if (mach_descrip_debug) prom_printf ARGS
1391ae08745Sheppo #define PRINT_LIST() if (mach_descrip_debug) print_obs_list()
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate #ifdef MACH_DESC_DEBUG
1427c478bd9Sstevel@tonic-gate static void
dump_buf(uint8_t * bufp,int size)1437c478bd9Sstevel@tonic-gate dump_buf(uint8_t *bufp, int size)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate int i;
1467c478bd9Sstevel@tonic-gate for (i = 0; i < size; i += 16) {
1477c478bd9Sstevel@tonic-gate int j;
1487c478bd9Sstevel@tonic-gate prom_printf("0x%04x :", i);
1497c478bd9Sstevel@tonic-gate for (j = 0; j < 16 && (i+j) < size; j++)
1507c478bd9Sstevel@tonic-gate prom_printf(" %02x", bufp[i+j]);
1517c478bd9Sstevel@tonic-gate prom_printf("\n");
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate }
1541ae08745Sheppo #endif /* MACH_DESC_DEBUG */
1557c478bd9Sstevel@tonic-gate
1561ae08745Sheppo static void
print_obs_list(void)1571ae08745Sheppo print_obs_list(void)
1587c478bd9Sstevel@tonic-gate {
1591ae08745Sheppo machine_descrip_t *lmdescp;
1601ae08745Sheppo mutex_enter(&obs_list_lock);
1611ae08745Sheppo
1621ae08745Sheppo lmdescp = obs_machine_descrip_list;
1631ae08745Sheppo prom_printf("MD_obs_list->");
1641ae08745Sheppo while (lmdescp != NULL) {
1651ae08745Sheppo prom_printf("g:%ld,r:%d", lmdescp->gen, lmdescp->refcnt);
1661ae08745Sheppo
1671ae08745Sheppo lmdescp = lmdescp->next;
1681ae08745Sheppo prom_printf("->");
1691ae08745Sheppo }
1701ae08745Sheppo prom_printf("NULL\n");
1711ae08745Sheppo mutex_exit(&obs_list_lock);
1721ae08745Sheppo }
1731ae08745Sheppo
1741ae08745Sheppo #else
1751ae08745Sheppo #define MDP(ARGS)
1761ae08745Sheppo #define PRINT_LIST()
1771ae08745Sheppo #endif /* DEBUG */
1781ae08745Sheppo
1791ae08745Sheppo /*
1801ae08745Sheppo * MD obsolete list managment functions
1811ae08745Sheppo */
1821ae08745Sheppo static machine_descrip_t *
md_obs_list_look_up_by_gen(uint64_t gen)1831ae08745Sheppo md_obs_list_look_up_by_gen(uint64_t gen)
1841ae08745Sheppo {
1851ae08745Sheppo machine_descrip_t *mdescp;
1861ae08745Sheppo
1871ae08745Sheppo mutex_enter(&obs_list_lock);
1881ae08745Sheppo mdescp = obs_machine_descrip_list;
1891ae08745Sheppo
1901ae08745Sheppo while (mdescp != NULL) {
1911ae08745Sheppo if (mdescp->gen == gen) {
1921ae08745Sheppo mutex_exit(&obs_list_lock);
1931ae08745Sheppo return (mdescp);
1941ae08745Sheppo }
1951ae08745Sheppo mdescp = mdescp->next;
1961ae08745Sheppo }
1971ae08745Sheppo
1981ae08745Sheppo mutex_exit(&obs_list_lock);
1991ae08745Sheppo return (mdescp);
2001ae08745Sheppo }
2011ae08745Sheppo
2021ae08745Sheppo static void
md_obs_list_remove(machine_descrip_t * mdescp)2031ae08745Sheppo md_obs_list_remove(machine_descrip_t *mdescp)
2041ae08745Sheppo {
2051ae08745Sheppo machine_descrip_t *lmdescp;
2061ae08745Sheppo
2071ae08745Sheppo mutex_enter(&obs_list_lock);
2081ae08745Sheppo
2091ae08745Sheppo lmdescp = obs_machine_descrip_list;
2101ae08745Sheppo
2111ae08745Sheppo if (obs_machine_descrip_list == mdescp) {
2121ae08745Sheppo obs_machine_descrip_list = mdescp->next;
2131ae08745Sheppo } else {
2141ae08745Sheppo while (lmdescp != NULL) {
2151ae08745Sheppo if (lmdescp->next == mdescp) {
2161ae08745Sheppo lmdescp->next = mdescp->next;
2171ae08745Sheppo mdescp->next = NULL;
2181ae08745Sheppo break;
2191ae08745Sheppo }
2201ae08745Sheppo lmdescp = lmdescp->next;
2211ae08745Sheppo }
2221ae08745Sheppo }
2231ae08745Sheppo mutex_exit(&obs_list_lock);
2241ae08745Sheppo PRINT_LIST();
2251ae08745Sheppo }
2261ae08745Sheppo
2271ae08745Sheppo static void
md_obs_list_add(machine_descrip_t * mdescp)2281ae08745Sheppo md_obs_list_add(machine_descrip_t *mdescp)
2291ae08745Sheppo {
2301ae08745Sheppo mutex_enter(&obs_list_lock);
2311ae08745Sheppo
2321ae08745Sheppo mdescp->next = obs_machine_descrip_list;
2331ae08745Sheppo obs_machine_descrip_list = mdescp;
2341ae08745Sheppo
2351ae08745Sheppo mutex_exit(&obs_list_lock);
2361ae08745Sheppo PRINT_LIST();
2371ae08745Sheppo }
2381ae08745Sheppo
2391ae08745Sheppo /*
2401ae08745Sheppo * Allocate a machine_descrip meta structure and intitialize it.
2411ae08745Sheppo */
2421ae08745Sheppo static machine_descrip_t *
new_mach_descrip(void)2431ae08745Sheppo new_mach_descrip(void)
2441ae08745Sheppo {
2451ae08745Sheppo machine_descrip_t *mdescp;
2461ae08745Sheppo
2471ae08745Sheppo mdescp = (machine_descrip_t *)(*curr_mach_descrip_memops->meta_allocp)
2481ae08745Sheppo (sizeof (machine_descrip_t));
2491ae08745Sheppo if (mdescp != NULL) {
2501ae08745Sheppo bzero(mdescp, sizeof (*mdescp));
2511ae08745Sheppo mdescp->memops = curr_mach_descrip_memops;
2521ae08745Sheppo mutex_init(&mdescp->lock, NULL, MUTEX_DRIVER, NULL);
2531ae08745Sheppo }
2541ae08745Sheppo
2551ae08745Sheppo return (mdescp);
2561ae08745Sheppo }
2571ae08745Sheppo
2581ae08745Sheppo /*
2591ae08745Sheppo * Free a machine_descrip meta structure and intitialize it.
2601ae08745Sheppo * Also free the MD buffer.
2611ae08745Sheppo */
2621ae08745Sheppo static void
destroy_machine_descrip(machine_descrip_t * mdescp)2631ae08745Sheppo destroy_machine_descrip(machine_descrip_t *mdescp)
2641ae08745Sheppo {
2651ae08745Sheppo machine_descrip_memops_t *mdesc_memopsp;
2661ae08745Sheppo
2671ae08745Sheppo ASSERT((mdescp != NULL));
2681ae08745Sheppo
2691ae08745Sheppo mdesc_memopsp = mdescp->memops;
2701ae08745Sheppo if (mdescp->memops == NULL)
2711ae08745Sheppo panic("destroy_machine_descrip: memops NULL\n");
2721ae08745Sheppo
2731ae08745Sheppo (*mdesc_memopsp->buf_freep)(mdescp->va, mdescp->space);
2741ae08745Sheppo mutex_destroy(&mdescp->lock);
2751ae08745Sheppo (*mdesc_memopsp->meta_freep)(mdescp, sizeof (*mdescp));
2761ae08745Sheppo }
2771ae08745Sheppo
2781ae08745Sheppo /*
2791ae08745Sheppo * Call into the Hypervisor to retrieve the most recent copy of the
2801ae08745Sheppo * machine description. If references to the current MD are active
2811ae08745Sheppo * stow it in the obsolete MD list and update the current MD reference
2821ae08745Sheppo * with the new one.
2831ae08745Sheppo * The obsolete list contains one MD per generation. If the firmware
2841ae08745Sheppo * doesn't support MD generation fail the call.
2851ae08745Sheppo */
2861ae08745Sheppo int
mach_descrip_update(void)2871ae08745Sheppo mach_descrip_update(void)
2881ae08745Sheppo {
2891ae08745Sheppo uint64_t md_size0, md_size;
2901ae08745Sheppo uint64_t md_space = 0;
2911ae08745Sheppo uint64_t hvret;
2921ae08745Sheppo caddr_t tbuf = NULL;
2931ae08745Sheppo uint64_t tbuf_pa;
2941ae08745Sheppo uint64_t tgen;
2951ae08745Sheppo int ret = 0;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate MDP(("MD: Requesting buffer size\n"));
2987c478bd9Sstevel@tonic-gate
2991ae08745Sheppo ASSERT((curr_mach_descrip != NULL));
3001ae08745Sheppo
3011ae08745Sheppo mutex_enter(&curr_mach_descrip_lock);
3027c478bd9Sstevel@tonic-gate
303ea841a36Sarao /*
3041ae08745Sheppo * If the required MD size changes between our first call
3051ae08745Sheppo * to hv_mach_desc (to find the required buf size) and the
306d1a9c4c1Sjm22469 * second call (to get the actual MD) and our allocated
307d1a9c4c1Sjm22469 * memory is insufficient, loop until we have allocated
308d1a9c4c1Sjm22469 * sufficient space.
309ea841a36Sarao */
3101ae08745Sheppo do {
3111ae08745Sheppo if (tbuf != NULL)
3121ae08745Sheppo (*curr_mach_descrip_memops->buf_freep)(tbuf, md_space);
3137c478bd9Sstevel@tonic-gate
3141ae08745Sheppo md_size0 = 0LL;
3151ae08745Sheppo (void) hv_mach_desc((uint64_t)0, &md_size0);
3161ae08745Sheppo MDP(("MD: buffer size is %ld\n", md_size0));
3177c478bd9Sstevel@tonic-gate
3181ae08745Sheppo /*
3191ae08745Sheppo * Align allocated space to nearest page.
3201ae08745Sheppo * contig_mem_alloc_align() requires a power of 2 alignment.
3211ae08745Sheppo */
3221ae08745Sheppo md_space = P2ROUNDUP(md_size0, PAGESIZE);
3231ae08745Sheppo MDP(("MD: allocated space is %ld\n", md_space));
3247c478bd9Sstevel@tonic-gate
3251ae08745Sheppo tbuf = (caddr_t)(*curr_mach_descrip_memops->buf_allocp)
3261ae08745Sheppo (md_space, PAGESIZE);
3271ae08745Sheppo if (tbuf == NULL) {
3281ae08745Sheppo ret = -1;
3291ae08745Sheppo goto done;
3301ae08745Sheppo }
3317c478bd9Sstevel@tonic-gate
3321ae08745Sheppo tbuf_pa = va_to_pa(tbuf);
333d1a9c4c1Sjm22469 md_size = md_space;
3341ae08745Sheppo hvret = hv_mach_desc(tbuf_pa, &md_size);
3351ae08745Sheppo MDP(("MD: HV return code = %ld\n", hvret));
3367c478bd9Sstevel@tonic-gate
3371ae08745Sheppo /*
3381ae08745Sheppo * We get H_EINVAL if our buffer size is too small. In
3391ae08745Sheppo * that case stay in the loop, reallocate the buffer
3401ae08745Sheppo * and try again.
3411ae08745Sheppo */
3421ae08745Sheppo if (hvret != H_EOK && hvret != H_EINVAL) {
3431ae08745Sheppo MDP(("MD: Failed with code %ld from HV\n", hvret));
3441ae08745Sheppo ret = -1;
3451ae08745Sheppo goto done;
3461ae08745Sheppo }
3477c478bd9Sstevel@tonic-gate
348d1a9c4c1Sjm22469 } while (md_space < md_size);
3497c478bd9Sstevel@tonic-gate
3501ae08745Sheppo tgen = mach_descrip_find_md_gen(tbuf);
3511ae08745Sheppo
3521ae08745Sheppo #ifdef DEBUG
3531ae08745Sheppo if (!HAS_GEN(tgen)) {
3541ae08745Sheppo MDP(("MD: generation number not found\n"));
3551ae08745Sheppo } else
3561ae08745Sheppo MDP(("MD: generation number %ld\n", tgen));
3571ae08745Sheppo #endif /* DEBUG */
3581ae08745Sheppo
3591ae08745Sheppo if (curr_mach_descrip->va != NULL) {
3601ae08745Sheppo
3611ae08745Sheppo /* check for the same generation number */
3621ae08745Sheppo if (HAS_GEN(tgen) && ((curr_mach_descrip->gen == tgen) &&
3631ae08745Sheppo (curr_mach_descrip->size == md_size))) {
3641ae08745Sheppo #ifdef DEBUG
3651ae08745Sheppo /*
3661ae08745Sheppo * Pedantic Check for generation number. If the
3671ae08745Sheppo * generation number is the same, make sure the
3681ae08745Sheppo * MDs are really identical.
3691ae08745Sheppo */
3701ae08745Sheppo if (bcmp(curr_mach_descrip->va, tbuf, md_size) != 0) {
3711ae08745Sheppo cmn_err(CE_WARN, "machine_descrip_update: MDs "
3721ae08745Sheppo "with the same generation (%ld) are not "
3731ae08745Sheppo "identical", tgen);
3741ae08745Sheppo ret = -1;
3751ae08745Sheppo goto done;
3761ae08745Sheppo }
3771ae08745Sheppo #endif
3781ae08745Sheppo ret = 0;
3791ae08745Sheppo goto done;
3801ae08745Sheppo }
3811ae08745Sheppo
3821ae08745Sheppo /* check for generations moving backwards */
3831ae08745Sheppo if (HAS_GEN(tgen) && HAS_GEN(curr_mach_descrip->gen) &&
3841ae08745Sheppo (curr_mach_descrip->gen > tgen)) {
3851ae08745Sheppo cmn_err(CE_WARN, "machine_descrip_update: new MD"
3861ae08745Sheppo " older generation (%ld) than current MD (%ld)",
3871ae08745Sheppo tgen, curr_mach_descrip->gen);
3881ae08745Sheppo ret = -1;
3891ae08745Sheppo goto done;
3901ae08745Sheppo }
3911ae08745Sheppo
3921ae08745Sheppo if (curr_mach_descrip->refcnt == 0) {
3931ae08745Sheppo
3941ae08745Sheppo MDP(("MD: freeing old md buffer gen %ld\n",
3951ae08745Sheppo curr_mach_descrip->gen));
3961ae08745Sheppo
3971ae08745Sheppo /* Free old space */
3981ae08745Sheppo ASSERT(curr_mach_descrip->space > 0);
3991ae08745Sheppo
4001ae08745Sheppo (*curr_mach_descrip_memops->buf_freep)
4011ae08745Sheppo (curr_mach_descrip->va, curr_mach_descrip->space);
4027c478bd9Sstevel@tonic-gate } else {
4031ae08745Sheppo if (!HAS_GEN(tgen)) {
4041ae08745Sheppo /*
4051ae08745Sheppo * No update support if FW
4061ae08745Sheppo * doesn't have MD generation id
4071ae08745Sheppo * feature.
4081ae08745Sheppo */
4091ae08745Sheppo prom_printf("WARNING: F/W does not support MD "
4101ae08745Sheppo "generation count, MD update failed\n");
4111ae08745Sheppo ret = -1;
4121ae08745Sheppo goto done;
4131ae08745Sheppo }
4141ae08745Sheppo
4151ae08745Sheppo MDP(("MD: adding to obs list %ld\n",
4161ae08745Sheppo curr_mach_descrip->gen));
4171ae08745Sheppo
4181ae08745Sheppo md_obs_list_add(curr_mach_descrip);
4191ae08745Sheppo
4201ae08745Sheppo curr_mach_descrip = new_mach_descrip();
4211ae08745Sheppo
4221ae08745Sheppo if (curr_mach_descrip == NULL) {
4231ae08745Sheppo panic("Allocation for machine description"
4241ae08745Sheppo " failed\n");
4251ae08745Sheppo }
4261ae08745Sheppo }
4271ae08745Sheppo }
4281ae08745Sheppo
4291ae08745Sheppo curr_mach_descrip->va = tbuf;
4301ae08745Sheppo curr_mach_descrip->gen = tgen;
4311ae08745Sheppo curr_mach_descrip->size = md_size;
4321ae08745Sheppo curr_mach_descrip->space = md_space;
4331ae08745Sheppo
4347c478bd9Sstevel@tonic-gate #ifdef MACH_DESC_DEBUG
4351ae08745Sheppo dump_buf((uint8_t *)curr_mach_descrip->va, md_size);
4367c478bd9Sstevel@tonic-gate #endif /* MACH_DESC_DEBUG */
4377c478bd9Sstevel@tonic-gate
4381ae08745Sheppo mutex_exit(&curr_mach_descrip_lock);
4391ae08745Sheppo return (ret);
4401ae08745Sheppo
4411ae08745Sheppo done:
4421ae08745Sheppo if (tbuf != NULL)
4431ae08745Sheppo (*curr_mach_descrip_memops->buf_freep)(tbuf, md_space);
4441ae08745Sheppo mutex_exit(&curr_mach_descrip_lock);
4451ae08745Sheppo return (ret);
4461ae08745Sheppo }
4471ae08745Sheppo
4481ae08745Sheppo static void *
mach_descrip_buf_alloc(size_t size,size_t align)4491ae08745Sheppo mach_descrip_buf_alloc(size_t size, size_t align)
4501ae08745Sheppo {
4511ae08745Sheppo void *p;
4521ae08745Sheppo
4531ae08745Sheppo if ((p = contig_mem_alloc_align(size, align)) == NULL)
4541ae08745Sheppo cmn_err(CE_WARN, alloc_fail_msg, size);
4551ae08745Sheppo
4561ae08745Sheppo return (p);
4571ae08745Sheppo }
4581ae08745Sheppo
4591ae08745Sheppo static void *
mach_descrip_strt_meta_alloc(size_t size)4601ae08745Sheppo mach_descrip_strt_meta_alloc(size_t size)
4611ae08745Sheppo {
4629bb6917bSarao return (mach_descrip_strt_buf_alloc(size, META_ALLOC_ALIGN));
4631ae08745Sheppo }
4641ae08745Sheppo
4651ae08745Sheppo static void
mach_descrip_strt_meta_free(void * buf,size_t size)4661ae08745Sheppo mach_descrip_strt_meta_free(void *buf, size_t size)
4671ae08745Sheppo {
4689bb6917bSarao mach_descrip_strt_buf_free(buf, size);
4691ae08745Sheppo }
4701ae08745Sheppo
4711ae08745Sheppo static void *
mach_descrip_strt_buf_alloc(size_t size,size_t align)4721ae08745Sheppo mach_descrip_strt_buf_alloc(size_t size, size_t align)
4731ae08745Sheppo {
4741ae08745Sheppo void *p = prom_alloc((caddr_t)0, size, align);
4751ae08745Sheppo
4761ae08745Sheppo if (p == NULL)
4771ae08745Sheppo prom_printf(alloc_fail_msg, size);
4781ae08745Sheppo
4791ae08745Sheppo return (p);
4801ae08745Sheppo }
4811ae08745Sheppo
4821ae08745Sheppo static void
mach_descrip_strt_buf_free(void * buf,size_t size)4831ae08745Sheppo mach_descrip_strt_buf_free(void *buf, size_t size)
4841ae08745Sheppo {
4851ae08745Sheppo prom_free((caddr_t)buf, size);
4861ae08745Sheppo }
4871ae08745Sheppo
4881ae08745Sheppo static void *
mach_descrip_meta_alloc(size_t size)4891ae08745Sheppo mach_descrip_meta_alloc(size_t size)
4901ae08745Sheppo {
4911ae08745Sheppo return (kmem_alloc(size, KM_SLEEP));
4921ae08745Sheppo }
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate /*
4951ae08745Sheppo * Initialize the kernel's Machine Description(MD) framework
4961ae08745Sheppo * early on in startup during mlsetup() so consumers
4971ae08745Sheppo * can get to the MD before the VM system has been initialized.
4981ae08745Sheppo *
4991ae08745Sheppo * Also get the most recent version of the MD.
5007c478bd9Sstevel@tonic-gate */
5011ae08745Sheppo void
mach_descrip_startup_init(void)5021ae08745Sheppo mach_descrip_startup_init(void)
5031ae08745Sheppo {
5047c478bd9Sstevel@tonic-gate
5051ae08745Sheppo mutex_init(&curr_mach_descrip_lock, NULL, MUTEX_DRIVER, NULL);
5061ae08745Sheppo mutex_init(&obs_list_lock, NULL, MUTEX_DRIVER, NULL);
5071ae08745Sheppo
5081ae08745Sheppo obs_machine_descrip_list = NULL;
5091ae08745Sheppo
5101ae08745Sheppo curr_mach_descrip_memops = &startup_memops;
5111ae08745Sheppo
5121ae08745Sheppo curr_mach_descrip = new_mach_descrip();
5131ae08745Sheppo if (curr_mach_descrip == NULL)
5141ae08745Sheppo panic("Allocation for machine description failed\n");
5151ae08745Sheppo
5161ae08745Sheppo if (mach_descrip_update())
5171ae08745Sheppo panic("Machine description initialization failed\n");
5181ae08745Sheppo
5191ae08745Sheppo }
5201ae08745Sheppo
5211ae08745Sheppo /*
5221ae08745Sheppo * Counterpart to the above init function. Free up resources
5231ae08745Sheppo * allocated at startup by mach_descrip_startup_setup().
5241ae08745Sheppo * And reset machine description framework state.
5251ae08745Sheppo *
5261ae08745Sheppo * All consumers must have fini'ed their handles at this point.
5271ae08745Sheppo */
5281ae08745Sheppo void
mach_descrip_startup_fini(void)5291ae08745Sheppo mach_descrip_startup_fini(void)
5301ae08745Sheppo {
5311ae08745Sheppo
5321ae08745Sheppo ASSERT((curr_mach_descrip != NULL));
5331ae08745Sheppo ASSERT((curr_mach_descrip->refcnt == 0));
5341ae08745Sheppo ASSERT((obs_machine_descrip_list == NULL));
5351ae08745Sheppo
5361ae08745Sheppo destroy_machine_descrip(curr_mach_descrip);
5371ae08745Sheppo curr_mach_descrip = NULL;
5381ae08745Sheppo curr_mach_descrip_memops = NULL;
5391ae08745Sheppo }
5401ae08745Sheppo
5411ae08745Sheppo /*
5421ae08745Sheppo * Initialize the kernel's Machine Description(MD) framework
5431ae08745Sheppo * after the the VM system has been initialized.
5441ae08745Sheppo *
5451ae08745Sheppo * Also get the most recent version of the MD.
5461ae08745Sheppo * Assumes that the machine description frame work is in a clean
5471ae08745Sheppo * state and the machine description intialized during startup
5481ae08745Sheppo * has been cleaned up and resources deallocated.
5491ae08745Sheppo */
5501ae08745Sheppo void
mach_descrip_init(void)5511ae08745Sheppo mach_descrip_init(void)
5521ae08745Sheppo {
5531ae08745Sheppo ASSERT((curr_mach_descrip == NULL &&
5541ae08745Sheppo curr_mach_descrip_memops == NULL));
5551ae08745Sheppo
5561ae08745Sheppo curr_mach_descrip_memops = &mach_descrip_memops;
5571ae08745Sheppo
5581ae08745Sheppo curr_mach_descrip = new_mach_descrip();
5591ae08745Sheppo if (curr_mach_descrip == NULL)
5601ae08745Sheppo panic("Allocation for machine description failed\n");
5611ae08745Sheppo
5621ae08745Sheppo if (mach_descrip_update())
5631ae08745Sheppo panic("Machine description intialization failed\n");
5641ae08745Sheppo
5651ae08745Sheppo /* read in global params */
5661ae08745Sheppo init_md_params();
5671ae08745Sheppo }
5681ae08745Sheppo
5691ae08745Sheppo /*
5701ae08745Sheppo * Client interface to get a handle to the current MD.
5711ae08745Sheppo * The md_fini_handle() interface should be used to
5721ae08745Sheppo * clean up the refernce to the MD returned by this function.
5731ae08745Sheppo */
5741ae08745Sheppo md_t *
md_get_handle(void)5751ae08745Sheppo md_get_handle(void)
5761ae08745Sheppo {
5771ae08745Sheppo md_t *mdp;
5781ae08745Sheppo
579d1a9c4c1Sjm22469 mdp = NULL;
580d1a9c4c1Sjm22469
5811ae08745Sheppo mutex_enter(&curr_mach_descrip_lock);
5821ae08745Sheppo
583d1a9c4c1Sjm22469 if (curr_mach_descrip != NULL) {
5841ae08745Sheppo
5851ae08745Sheppo mdp = md_init_intern(curr_mach_descrip->va,
5861ae08745Sheppo curr_mach_descrip->memops->meta_allocp,
5871ae08745Sheppo curr_mach_descrip->memops->meta_freep);
5881ae08745Sheppo
589d1a9c4c1Sjm22469 if (mdp != NULL)
590d1a9c4c1Sjm22469 curr_mach_descrip->refcnt++;
591d1a9c4c1Sjm22469 }
592d1a9c4c1Sjm22469
5931ae08745Sheppo mutex_exit(&curr_mach_descrip_lock);
5941ae08745Sheppo
5951ae08745Sheppo return (mdp);
5961ae08745Sheppo }
5971ae08745Sheppo
5981ae08745Sheppo /*
5991ae08745Sheppo * Client interface to clean up the refernce to the MD returned
6001ae08745Sheppo * by md_get_handle().
6011ae08745Sheppo */
6021ae08745Sheppo int
md_fini_handle(md_t * ptr)6031ae08745Sheppo md_fini_handle(md_t *ptr)
6041ae08745Sheppo {
6051ae08745Sheppo machine_descrip_t *mdescp;
6061ae08745Sheppo md_impl_t *mdp;
6071ae08745Sheppo
6081ae08745Sheppo
6091ae08745Sheppo mdp = (md_impl_t *)ptr;
6101ae08745Sheppo
6111ae08745Sheppo if (mdp == NULL)
6121ae08745Sheppo return (-1);
6131ae08745Sheppo /*
6141ae08745Sheppo * Check if mdp is current MD gen
6151ae08745Sheppo */
6161ae08745Sheppo mutex_enter(&curr_mach_descrip_lock);
6171ae08745Sheppo
6181ae08745Sheppo if (curr_mach_descrip->gen == mdp->gen) {
6191ae08745Sheppo curr_mach_descrip->refcnt--;
6201ae08745Sheppo mutex_exit(&curr_mach_descrip_lock);
6211ae08745Sheppo goto fini;
6221ae08745Sheppo }
6231ae08745Sheppo mutex_exit(&curr_mach_descrip_lock);
6241ae08745Sheppo
6251ae08745Sheppo /*
6261ae08745Sheppo * MD is in the obsolete list
6271ae08745Sheppo */
6281ae08745Sheppo mdescp = md_obs_list_look_up_by_gen(mdp->gen);
6291ae08745Sheppo if (mdescp == NULL)
6301ae08745Sheppo return (-1);
6311ae08745Sheppo
6321ae08745Sheppo mutex_enter(&mdescp->lock);
6331ae08745Sheppo mdescp->refcnt--;
6341ae08745Sheppo if (mdescp->refcnt == 0) {
6351ae08745Sheppo md_obs_list_remove(mdescp);
6361ae08745Sheppo mutex_exit(&mdescp->lock);
6371ae08745Sheppo destroy_machine_descrip(mdescp);
6381ae08745Sheppo goto fini;
6391ae08745Sheppo }
6401ae08745Sheppo mutex_exit(&mdescp->lock);
6411ae08745Sheppo
6421ae08745Sheppo fini:
6431ae08745Sheppo return (md_fini(ptr));
6441ae08745Sheppo }
6451ae08745Sheppo
6461ae08745Sheppo /*
6471ae08745Sheppo * General purpose initialization function used to extract parameters
6481ae08745Sheppo * from the MD during the boot process. This is called immediately after
6491ae08745Sheppo * the in kernel copy of the MD has been initialized so that global
6501ae08745Sheppo * flags are available to various subsystems as they get initialized.
6511ae08745Sheppo */
6521ae08745Sheppo static void
init_md_params(void)6531ae08745Sheppo init_md_params(void)
6541ae08745Sheppo {
6551ae08745Sheppo md_t *mdp;
6561ae08745Sheppo int num_nodes;
6571ae08745Sheppo mde_cookie_t *listp;
6581ae08745Sheppo int listsz;
6591ae08745Sheppo
6601ae08745Sheppo mdp = md_get_handle();
6611ae08745Sheppo ASSERT(mdp);
6621ae08745Sheppo num_nodes = md_node_count(mdp);
6631ae08745Sheppo ASSERT(num_nodes >= 0);
6641ae08745Sheppo
6651ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
6661ae08745Sheppo listp = (mde_cookie_t *)
6671ae08745Sheppo (*curr_mach_descrip_memops->meta_allocp)(listsz);
6681ae08745Sheppo
6691ae08745Sheppo /*
6701ae08745Sheppo * Import various parameters from the MD. For now,
6711ae08745Sheppo * the only parameter of interest is whether or not
6721ae08745Sheppo * domaining features are supported.
6731ae08745Sheppo */
6744bac2208Snarayan init_domaining_capabilities(mdp, listp);
6751ae08745Sheppo
6761ae08745Sheppo (*curr_mach_descrip_memops->meta_freep)(listp, listsz);
6771ae08745Sheppo (void) md_fini_handle(mdp);
6781ae08745Sheppo }
6791ae08745Sheppo
6801ae08745Sheppo static void
init_domaining_capabilities(md_t * mdp,mde_cookie_t * listp)6814bac2208Snarayan init_domaining_capabilities(md_t *mdp, mde_cookie_t *listp)
6821ae08745Sheppo {
6831ae08745Sheppo mde_cookie_t rootnode;
6841ae08745Sheppo int num_nodes;
6851ae08745Sheppo uint64_t val = 0;
6861ae08745Sheppo
6871ae08745Sheppo rootnode = md_root_node(mdp);
6881ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
6891ae08745Sheppo
6901ae08745Sheppo num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
6911ae08745Sheppo md_find_name(mdp, "fwd"), listp);
6921ae08745Sheppo
6931ae08745Sheppo /* should only be one platform node */
6941ae08745Sheppo ASSERT(num_nodes == 1);
6951ae08745Sheppo
6961ae08745Sheppo if (md_get_prop_val(mdp, *listp, "domaining-enabled", &val) != 0) {
6971ae08745Sheppo /*
6981ae08745Sheppo * The property is not present. This implies
6991ae08745Sheppo * that the firmware does not support domaining
7001ae08745Sheppo * features.
7011ae08745Sheppo */
7021ae08745Sheppo MDP(("'domaining-enabled' property not present\n"));
7031ae08745Sheppo
7044bac2208Snarayan domaining_capabilities = 0;
7051ae08745Sheppo return;
7061ae08745Sheppo }
7071ae08745Sheppo
7084bac2208Snarayan domaining_capabilities = DOMAINING_SUPPORTED;
7091ae08745Sheppo
7104bac2208Snarayan if (val == 1) {
7114bac2208Snarayan if (force_domaining_disabled) {
7124bac2208Snarayan MDP(("domaining manually disabled\n"));
7134bac2208Snarayan } else {
7144bac2208Snarayan domaining_capabilities |= DOMAINING_ENABLED;
7154bac2208Snarayan }
7164bac2208Snarayan }
7174bac2208Snarayan
7184bac2208Snarayan MDP(("domaining_capabilities= 0x%x\n", domaining_capabilities));
7191ae08745Sheppo }
7201ae08745Sheppo
7211ae08745Sheppo /*
7221ae08745Sheppo * Client interface to get a pointer to the raw MD buffer
7231ae08745Sheppo * Private to kernel and mdesc driver.
7241ae08745Sheppo */
7251ae08745Sheppo caddr_t
md_get_md_raw(md_t * ptr)7261ae08745Sheppo md_get_md_raw(md_t *ptr)
7271ae08745Sheppo {
7281ae08745Sheppo md_impl_t *mdp;
7291ae08745Sheppo
7301ae08745Sheppo mdp = (md_impl_t *)ptr;
7311ae08745Sheppo if (mdp == NULL)
7321ae08745Sheppo return (NULL);
7331ae08745Sheppo return (mdp->caddr);
7341ae08745Sheppo }
7351ae08745Sheppo
7361ae08745Sheppo /*
7371ae08745Sheppo * This is called before an MD structure is intialized, so
7381ae08745Sheppo * it walks the raw MD looking for the generation property.
7391ae08745Sheppo */
7401ae08745Sheppo static uint64_t
mach_descrip_find_md_gen(caddr_t ptr)7411ae08745Sheppo mach_descrip_find_md_gen(caddr_t ptr)
7421ae08745Sheppo {
7431ae08745Sheppo md_header_t *hdrp;
7441ae08745Sheppo md_element_t *mdep;
7451ae08745Sheppo md_element_t *rootnode = NULL;
7461ae08745Sheppo md_element_t *elem = NULL;
7471ae08745Sheppo char *namep;
7481ae08745Sheppo boolean_t done;
7491ae08745Sheppo int idx;
7501ae08745Sheppo
7511ae08745Sheppo hdrp = (md_header_t *)ptr;
7521ae08745Sheppo mdep = (md_element_t *)(ptr + MD_HEADER_SIZE);
7531ae08745Sheppo namep = (char *)(ptr + MD_HEADER_SIZE + hdrp->node_blk_sz);
7541ae08745Sheppo
7551ae08745Sheppo /*
7561ae08745Sheppo * Very basic check for alignment to avoid
7571ae08745Sheppo * bus error issues.
7581ae08745Sheppo */
7591ae08745Sheppo if ((((uint64_t)ptr) & 7) != 0)
7601ae08745Sheppo return (MDESC_INVAL_GEN);
7611ae08745Sheppo
7621ae08745Sheppo if (mdtoh32(hdrp->transport_version) != MD_TRANSPORT_VERSION) {
7631ae08745Sheppo return (MDESC_INVAL_GEN);
7641ae08745Sheppo }
7651ae08745Sheppo
7661ae08745Sheppo /*
7671ae08745Sheppo * Search for the root node. Perform the walk manually
7681ae08745Sheppo * since the MD structure is not set up yet.
7691ae08745Sheppo */
7701ae08745Sheppo for (idx = 0, done = B_FALSE; done == B_FALSE; ) {
7711ae08745Sheppo
7721ae08745Sheppo md_element_t *np = &(mdep[idx]);
7731ae08745Sheppo
7741ae08745Sheppo switch (MDE_TAG(np)) {
7751ae08745Sheppo case MDET_LIST_END:
7761ae08745Sheppo done = B_TRUE;
7771ae08745Sheppo break;
7781ae08745Sheppo
7791ae08745Sheppo case MDET_NODE:
7801ae08745Sheppo if (strcmp(namep + MDE_NAME(np), "root") == 0) {
7811ae08745Sheppo /* found root node */
7821ae08745Sheppo rootnode = np;
7831ae08745Sheppo done = B_TRUE;
7841ae08745Sheppo break;
7851ae08745Sheppo }
7861ae08745Sheppo idx = MDE_PROP_INDEX(np);
7871ae08745Sheppo break;
7881ae08745Sheppo
7891ae08745Sheppo default:
7901ae08745Sheppo /* ignore */
7911ae08745Sheppo idx++;
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate }
7941ae08745Sheppo
7951ae08745Sheppo if (rootnode == NULL) {
7961ae08745Sheppo /* root not found */
7971ae08745Sheppo return (MDESC_INVAL_GEN);
7981ae08745Sheppo }
7991ae08745Sheppo
8001ae08745Sheppo /* search the rootnode for the generation property */
8011ae08745Sheppo for (elem = (rootnode + 1); MDE_TAG(elem) != MDET_NODE_END; elem++) {
8021ae08745Sheppo
8031ae08745Sheppo char *prop_name;
8041ae08745Sheppo
8051ae08745Sheppo /* generation field is a prop_val */
8061ae08745Sheppo if (MDE_TAG(elem) != MDET_PROP_VAL)
8071ae08745Sheppo continue;
8081ae08745Sheppo
8091ae08745Sheppo prop_name = namep + MDE_NAME(elem);
8101ae08745Sheppo
8111ae08745Sheppo if (strcmp(prop_name, "md-generation#") == 0) {
8121ae08745Sheppo return (MDE_PROP_VALUE(elem));
8131ae08745Sheppo }
8141ae08745Sheppo }
8151ae08745Sheppo
8161ae08745Sheppo return (MDESC_INVAL_GEN);
8171ae08745Sheppo }
8181ae08745Sheppo
8191ae08745Sheppo /*
8201ae08745Sheppo * Failed to allocate the list : Return value -1
8211ae08745Sheppo * md_scan_dag API failed : Return the result from md_scan_dag API
8221ae08745Sheppo */
8231ae08745Sheppo int
md_alloc_scan_dag(md_t * ptr,mde_cookie_t startnode,char * node_name,char * dag,mde_cookie_t ** list)8241ae08745Sheppo md_alloc_scan_dag(md_t *ptr,
8251ae08745Sheppo mde_cookie_t startnode,
8261ae08745Sheppo char *node_name,
8271ae08745Sheppo char *dag,
8281ae08745Sheppo mde_cookie_t **list)
8291ae08745Sheppo {
8301ae08745Sheppo int res;
8311ae08745Sheppo md_impl_t *mdp = (md_impl_t *)ptr;
8321ae08745Sheppo
8331ae08745Sheppo *list = (mde_cookie_t *)mdp->allocp(sizeof (mde_cookie_t) *
8341ae08745Sheppo mdp->node_count);
8351ae08745Sheppo if (*list == NULL)
8361ae08745Sheppo return (-1);
8371ae08745Sheppo
8381ae08745Sheppo res = md_scan_dag(ptr, startnode,
8391ae08745Sheppo md_find_name(ptr, node_name),
8401ae08745Sheppo md_find_name(ptr, dag), *list);
8411ae08745Sheppo
8421ae08745Sheppo /*
8431ae08745Sheppo * If md_scan_dag API returned 0 or -1 then free the buffer
8441ae08745Sheppo * and return -1 to indicate the error from this API.
8451ae08745Sheppo */
8461ae08745Sheppo if (res < 1) {
8471ae08745Sheppo md_free_scan_dag(ptr, list);
8481ae08745Sheppo *list = NULL;
8491ae08745Sheppo }
8501ae08745Sheppo
8511ae08745Sheppo return (res);
8521ae08745Sheppo }
8531ae08745Sheppo
8541ae08745Sheppo void
md_free_scan_dag(md_t * ptr,mde_cookie_t ** list)8551ae08745Sheppo md_free_scan_dag(md_t *ptr,
8561ae08745Sheppo mde_cookie_t **list)
8571ae08745Sheppo {
8581ae08745Sheppo md_impl_t *mdp = (md_impl_t *)ptr;
8591ae08745Sheppo
8601ae08745Sheppo mdp->freep(*list, sizeof (mde_cookie_t) * mdp->node_count);
8617c478bd9Sstevel@tonic-gate }
862*d2365b01SPavel Tatashin
863*d2365b01SPavel Tatashin /*
864*d2365b01SPavel Tatashin * Return generation number of current machine descriptor. Can be used for
865*d2365b01SPavel Tatashin * performance purposes to avoid requesting new md handle just to see if graph
866*d2365b01SPavel Tatashin * was updated.
867*d2365b01SPavel Tatashin */
868*d2365b01SPavel Tatashin uint64_t
md_get_current_gen(void)869*d2365b01SPavel Tatashin md_get_current_gen(void)
870*d2365b01SPavel Tatashin {
871*d2365b01SPavel Tatashin uint64_t gen = MDESC_INVAL_GEN;
872*d2365b01SPavel Tatashin
873*d2365b01SPavel Tatashin mutex_enter(&curr_mach_descrip_lock);
874*d2365b01SPavel Tatashin
875*d2365b01SPavel Tatashin if (curr_mach_descrip != NULL)
876*d2365b01SPavel Tatashin gen = (curr_mach_descrip->gen);
877*d2365b01SPavel Tatashin
878*d2365b01SPavel Tatashin mutex_exit(&curr_mach_descrip_lock);
879*d2365b01SPavel Tatashin
880*d2365b01SPavel Tatashin return (gen);
881*d2365b01SPavel Tatashin }
882