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