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 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 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 * 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 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 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 * 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 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 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 * 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 * 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 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 * 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 4831ae08745Sheppo mach_descrip_strt_buf_free(void *buf, size_t size) 4841ae08745Sheppo { 4851ae08745Sheppo prom_free((caddr_t)buf, size); 4861ae08745Sheppo } 4871ae08745Sheppo 4881ae08745Sheppo static void * 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 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 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 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 * 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 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 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 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 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 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 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 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 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