xref: /titanic_44/usr/src/uts/common/syscall/lgrpsys.c (revision fd435bccec40cb841f712413108d8577422fd9ab)
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
5c6402783Sakolb  * Common Development and Distribution License (the "License").
6c6402783Sakolb  * 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  */
21c6402783Sakolb 
227c478bd9Sstevel@tonic-gate /*
23c6402783Sakolb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * lgroup system calls
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/systm.h>
377c478bd9Sstevel@tonic-gate #include <sys/mman.h>
387c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
397c478bd9Sstevel@tonic-gate #include <sys/lgrp.h>
407c478bd9Sstevel@tonic-gate #include <sys/lgrp_user.h>
417c478bd9Sstevel@tonic-gate #include <sys/promif.h>		/* for prom_printf() */
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <vm/as.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* definitions for mi_validity */
487c478bd9Sstevel@tonic-gate #define	VALID_ADDR	1
497c478bd9Sstevel@tonic-gate #define	VALID_REQ	2
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * run through the given number of addresses and requests and return the
537c478bd9Sstevel@tonic-gate  * corresponding memory information for each address
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate static int
meminfo(int addr_count,struct meminfo * mip)567c478bd9Sstevel@tonic-gate meminfo(int addr_count, struct meminfo *mip)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 	size_t		in_size, out_size, req_size, val_size;
597c478bd9Sstevel@tonic-gate 	struct as	*as;
607c478bd9Sstevel@tonic-gate 	struct hat	*hat;
617c478bd9Sstevel@tonic-gate 	int		i, j, out_idx, info_count;
627c478bd9Sstevel@tonic-gate 	lgrp_t		*lgrp;
637c478bd9Sstevel@tonic-gate 	pfn_t		pfn;
647c478bd9Sstevel@tonic-gate 	ssize_t		pgsz;
657c478bd9Sstevel@tonic-gate 	int		*req_array, *val_array;
667c478bd9Sstevel@tonic-gate 	uint64_t	*in_array, *out_array;
677c478bd9Sstevel@tonic-gate 	uint64_t	addr, paddr;
687c478bd9Sstevel@tonic-gate 	uintptr_t	vaddr;
697c478bd9Sstevel@tonic-gate 	int		ret = 0;
707c478bd9Sstevel@tonic-gate 	struct meminfo minfo;
717c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
727c478bd9Sstevel@tonic-gate 	struct meminfo32 minfo32;
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	/*
767c478bd9Sstevel@tonic-gate 	 * Make sure that there is at least one address to translate and
777c478bd9Sstevel@tonic-gate 	 * limit how many virtual addresses the kernel can do per call
787c478bd9Sstevel@tonic-gate 	 */
797c478bd9Sstevel@tonic-gate 	if (addr_count < 1)
807c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
817c478bd9Sstevel@tonic-gate 	else if (addr_count > MAX_MEMINFO_CNT)
827c478bd9Sstevel@tonic-gate 		addr_count = MAX_MEMINFO_CNT;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
857c478bd9Sstevel@tonic-gate 		if (copyin(mip, &minfo, sizeof (struct meminfo)))
867c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
897c478bd9Sstevel@tonic-gate 	else {
907c478bd9Sstevel@tonic-gate 		bzero(&minfo, sizeof (minfo));
917c478bd9Sstevel@tonic-gate 		if (copyin(mip, &minfo32, sizeof (struct meminfo32)))
927c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
937c478bd9Sstevel@tonic-gate 		minfo.mi_inaddr = (const uint64_t *)(uintptr_t)
947c478bd9Sstevel@tonic-gate 		    minfo32.mi_inaddr;
957c478bd9Sstevel@tonic-gate 		minfo.mi_info_req = (const uint_t *)(uintptr_t)
967c478bd9Sstevel@tonic-gate 		    minfo32.mi_info_req;
977c478bd9Sstevel@tonic-gate 		minfo.mi_info_count = minfo32.mi_info_count;
987c478bd9Sstevel@tonic-gate 		minfo.mi_outdata = (uint64_t *)(uintptr_t)
997c478bd9Sstevel@tonic-gate 		    minfo32.mi_outdata;
1007c478bd9Sstevel@tonic-gate 		minfo.mi_validity = (uint_t *)(uintptr_t)
1017c478bd9Sstevel@tonic-gate 		    minfo32.mi_validity;
1027c478bd9Sstevel@tonic-gate 	}
1037c478bd9Sstevel@tonic-gate #endif
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * all the input parameters have been copied in:-
1067c478bd9Sstevel@tonic-gate 	 * addr_count - number of input addresses
1077c478bd9Sstevel@tonic-gate 	 * minfo.mi_inaddr - array of input addresses
1087c478bd9Sstevel@tonic-gate 	 * minfo.mi_info_req - array of types of information requested
1097c478bd9Sstevel@tonic-gate 	 * minfo.mi_info_count - no. of pieces of info requested for each addr
1107c478bd9Sstevel@tonic-gate 	 * minfo.mi_outdata - array into which the results are placed
1117c478bd9Sstevel@tonic-gate 	 * minfo.mi_validity -  array containing bitwise result codes; 0th bit
1127c478bd9Sstevel@tonic-gate 	 *			evaluates validity of corresponding input
1137c478bd9Sstevel@tonic-gate 	 *			address, 1st bit validity of response to first
1147c478bd9Sstevel@tonic-gate 	 *			member of info_req, etc.
1157c478bd9Sstevel@tonic-gate 	 */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	/* make sure mi_info_count is within limit */
1187c478bd9Sstevel@tonic-gate 	info_count = minfo.mi_info_count;
1197c478bd9Sstevel@tonic-gate 	if (info_count < 1 || info_count > MAX_MEMINFO_REQ)
1207c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/*
1237c478bd9Sstevel@tonic-gate 	 * allocate buffer in_array for the input addresses and copy them in
1247c478bd9Sstevel@tonic-gate 	 */
1257c478bd9Sstevel@tonic-gate 	in_size = sizeof (uint64_t) * addr_count;
1267c478bd9Sstevel@tonic-gate 	in_array = kmem_alloc(in_size, KM_SLEEP);
1277c478bd9Sstevel@tonic-gate 	if (copyin(minfo.mi_inaddr, in_array, in_size)) {
1287c478bd9Sstevel@tonic-gate 		kmem_free(in_array, in_size);
1297c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * allocate buffer req_array for the input info_reqs and copy them in
1347c478bd9Sstevel@tonic-gate 	 */
1357c478bd9Sstevel@tonic-gate 	req_size = sizeof (uint_t) * info_count;
1367c478bd9Sstevel@tonic-gate 	req_array = kmem_alloc(req_size, KM_SLEEP);
1377c478bd9Sstevel@tonic-gate 	if (copyin(minfo.mi_info_req, req_array, req_size)) {
1387c478bd9Sstevel@tonic-gate 		kmem_free(req_array, req_size);
1397c478bd9Sstevel@tonic-gate 		kmem_free(in_array, in_size);
1407c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * allocate buffer out_array which holds the results and will have
1457c478bd9Sstevel@tonic-gate 	 * to be copied out later
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 	out_size = sizeof (uint64_t) * addr_count * info_count;
1487c478bd9Sstevel@tonic-gate 	out_array = kmem_alloc(out_size, KM_SLEEP);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * allocate buffer val_array which holds the validity bits and will
1527c478bd9Sstevel@tonic-gate 	 * have to be copied out later
1537c478bd9Sstevel@tonic-gate 	 */
1547c478bd9Sstevel@tonic-gate 	val_size = sizeof (uint_t) * addr_count;
1557c478bd9Sstevel@tonic-gate 	val_array = kmem_alloc(val_size, KM_SLEEP);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	if ((req_array[0] & MEMINFO_MASK) == MEMINFO_PLGRP) {
1587c478bd9Sstevel@tonic-gate 		/* find the corresponding lgroup for each physical address */
1597c478bd9Sstevel@tonic-gate 		for (i = 0; i < addr_count; i++) {
1607c478bd9Sstevel@tonic-gate 			paddr = in_array[i];
1617c478bd9Sstevel@tonic-gate 			pfn = btop(paddr);
1627c478bd9Sstevel@tonic-gate 			lgrp = lgrp_pfn_to_lgrp(pfn);
1637c478bd9Sstevel@tonic-gate 			if (lgrp) {
1647c478bd9Sstevel@tonic-gate 				out_array[i] = lgrp->lgrp_id;
1657c478bd9Sstevel@tonic-gate 				val_array[i] = VALID_ADDR | VALID_REQ;
1667c478bd9Sstevel@tonic-gate 			} else {
1677c478bd9Sstevel@tonic-gate 				out_array[i] = NULL;
1687c478bd9Sstevel@tonic-gate 				val_array[i] = 0;
1697c478bd9Sstevel@tonic-gate 			}
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 	} else {
1727c478bd9Sstevel@tonic-gate 		/* get the corresponding memory info for each virtual address */
1737c478bd9Sstevel@tonic-gate 		as = curproc->p_as;
1747c478bd9Sstevel@tonic-gate 
175*fd435bccSJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_READER);
1767c478bd9Sstevel@tonic-gate 		hat = as->a_hat;
1777c478bd9Sstevel@tonic-gate 		for (i = out_idx = 0; i < addr_count; i++, out_idx +=
1787c478bd9Sstevel@tonic-gate 		    info_count) {
1797c478bd9Sstevel@tonic-gate 			addr = in_array[i];
1807c478bd9Sstevel@tonic-gate 			vaddr = (uintptr_t)(addr & ~PAGEOFFSET);
1817c478bd9Sstevel@tonic-gate 			if (!as_segat(as, (caddr_t)vaddr)) {
1827c478bd9Sstevel@tonic-gate 				val_array[i] = 0;
1837c478bd9Sstevel@tonic-gate 				continue;
1847c478bd9Sstevel@tonic-gate 			}
1857c478bd9Sstevel@tonic-gate 			val_array[i] = VALID_ADDR;
1867c478bd9Sstevel@tonic-gate 			pfn = hat_getpfnum(hat, (caddr_t)vaddr);
1877c478bd9Sstevel@tonic-gate 			if (pfn != PFN_INVALID) {
1887c478bd9Sstevel@tonic-gate 				paddr = (uint64_t)((pfn << PAGESHIFT) |
1897c478bd9Sstevel@tonic-gate 					(addr & PAGEOFFSET));
1907c478bd9Sstevel@tonic-gate 				for (j = 0; j < info_count; j++) {
1917c478bd9Sstevel@tonic-gate 					switch (req_array[j] & MEMINFO_MASK) {
1927c478bd9Sstevel@tonic-gate 					case MEMINFO_VPHYSICAL:
1937c478bd9Sstevel@tonic-gate 						/*
1947c478bd9Sstevel@tonic-gate 						 * return the physical address
1957c478bd9Sstevel@tonic-gate 						 * corresponding to the input
1967c478bd9Sstevel@tonic-gate 						 * virtual address
1977c478bd9Sstevel@tonic-gate 						 */
1987c478bd9Sstevel@tonic-gate 						out_array[out_idx + j] = paddr;
1997c478bd9Sstevel@tonic-gate 						val_array[i] |= VALID_REQ << j;
2007c478bd9Sstevel@tonic-gate 						break;
2017c478bd9Sstevel@tonic-gate 					case MEMINFO_VLGRP:
2027c478bd9Sstevel@tonic-gate 						/*
2037c478bd9Sstevel@tonic-gate 						 * return the lgroup of physical
2047c478bd9Sstevel@tonic-gate 						 * page corresponding to the
2057c478bd9Sstevel@tonic-gate 						 * input virtual address
2067c478bd9Sstevel@tonic-gate 						 */
2077c478bd9Sstevel@tonic-gate 						lgrp = lgrp_pfn_to_lgrp(pfn);
2087c478bd9Sstevel@tonic-gate 						if (lgrp) {
2097c478bd9Sstevel@tonic-gate 							out_array[out_idx + j] =
2107c478bd9Sstevel@tonic-gate 								lgrp->lgrp_id;
2117c478bd9Sstevel@tonic-gate 							val_array[i] |=
2127c478bd9Sstevel@tonic-gate 								VALID_REQ << j;
2137c478bd9Sstevel@tonic-gate 						}
2147c478bd9Sstevel@tonic-gate 						break;
2157c478bd9Sstevel@tonic-gate 					case MEMINFO_VPAGESIZE:
2167c478bd9Sstevel@tonic-gate 						/*
2177c478bd9Sstevel@tonic-gate 						 * return the size of physical
2187c478bd9Sstevel@tonic-gate 						 * page corresponding to the
2197c478bd9Sstevel@tonic-gate 						 * input virtual address
2207c478bd9Sstevel@tonic-gate 						 */
2217c478bd9Sstevel@tonic-gate 						pgsz = hat_getpagesize(hat,
2227c478bd9Sstevel@tonic-gate 							(caddr_t)vaddr);
2237c478bd9Sstevel@tonic-gate 						if (pgsz != -1) {
2247c478bd9Sstevel@tonic-gate 							out_array[out_idx + j] =
2257c478bd9Sstevel@tonic-gate 									pgsz;
2267c478bd9Sstevel@tonic-gate 							val_array[i] |=
2277c478bd9Sstevel@tonic-gate 								VALID_REQ << j;
2287c478bd9Sstevel@tonic-gate 						}
2297c478bd9Sstevel@tonic-gate 						break;
2307c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPLCNT:
2317c478bd9Sstevel@tonic-gate 						/*
2327c478bd9Sstevel@tonic-gate 						 * for future use:-
2337c478bd9Sstevel@tonic-gate 						 * return the no. replicated
2347c478bd9Sstevel@tonic-gate 						 * physical pages corresponding
2357c478bd9Sstevel@tonic-gate 						 * to the input virtual address,
2367c478bd9Sstevel@tonic-gate 						 * so it is always 0 at the
2377c478bd9Sstevel@tonic-gate 						 * moment
2387c478bd9Sstevel@tonic-gate 						 */
2397c478bd9Sstevel@tonic-gate 						out_array[out_idx + j] = 0;
2407c478bd9Sstevel@tonic-gate 						val_array[i] |= VALID_REQ << j;
2417c478bd9Sstevel@tonic-gate 						break;
2427c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPL:
2437c478bd9Sstevel@tonic-gate 						/*
2447c478bd9Sstevel@tonic-gate 						 * for future use:-
2457c478bd9Sstevel@tonic-gate 						 * return the nth physical
2467c478bd9Sstevel@tonic-gate 						 * replica of the specified
2477c478bd9Sstevel@tonic-gate 						 * virtual address
2487c478bd9Sstevel@tonic-gate 						 */
2497c478bd9Sstevel@tonic-gate 						break;
2507c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPL_LGRP:
2517c478bd9Sstevel@tonic-gate 						/*
2527c478bd9Sstevel@tonic-gate 						 * for future use:-
2537c478bd9Sstevel@tonic-gate 						 * return the lgroup of nth
2547c478bd9Sstevel@tonic-gate 						 * physical replica of the
2557c478bd9Sstevel@tonic-gate 						 * specified virtual address
2567c478bd9Sstevel@tonic-gate 						 */
2577c478bd9Sstevel@tonic-gate 						break;
2587c478bd9Sstevel@tonic-gate 					case MEMINFO_PLGRP:
2597c478bd9Sstevel@tonic-gate 						/*
2607c478bd9Sstevel@tonic-gate 						 * this is for physical address
2617c478bd9Sstevel@tonic-gate 						 * only, shouldn't mix with
2627c478bd9Sstevel@tonic-gate 						 * virtual address
2637c478bd9Sstevel@tonic-gate 						 */
2647c478bd9Sstevel@tonic-gate 						break;
2657c478bd9Sstevel@tonic-gate 					default:
2667c478bd9Sstevel@tonic-gate 						break;
2677c478bd9Sstevel@tonic-gate 					}
2687c478bd9Sstevel@tonic-gate 				}
2697c478bd9Sstevel@tonic-gate 			}
2707c478bd9Sstevel@tonic-gate 		}
271*fd435bccSJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/* copy out the results and validity bits and free the buffers */
2757c478bd9Sstevel@tonic-gate 	if ((copyout(out_array, minfo.mi_outdata, out_size) != 0) ||
2767c478bd9Sstevel@tonic-gate 		(copyout(val_array, minfo.mi_validity, val_size) != 0))
2777c478bd9Sstevel@tonic-gate 		ret = set_errno(EFAULT);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	kmem_free(in_array, in_size);
2807c478bd9Sstevel@tonic-gate 	kmem_free(out_array, out_size);
2817c478bd9Sstevel@tonic-gate 	kmem_free(req_array, req_size);
2827c478bd9Sstevel@tonic-gate 	kmem_free(val_array, val_size);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	return (ret);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * Initialize lgroup affinities for thread
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate void
lgrp_affinity_init(lgrp_affinity_t ** bufaddr)2927c478bd9Sstevel@tonic-gate lgrp_affinity_init(lgrp_affinity_t **bufaddr)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	if (bufaddr)
2957c478bd9Sstevel@tonic-gate 		*bufaddr = NULL;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Free lgroup affinities for thread and set to NULL
3017c478bd9Sstevel@tonic-gate  * just in case thread gets recycled
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate void
lgrp_affinity_free(lgrp_affinity_t ** bufaddr)3047c478bd9Sstevel@tonic-gate lgrp_affinity_free(lgrp_affinity_t **bufaddr)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	if (bufaddr && *bufaddr) {
3077c478bd9Sstevel@tonic-gate 		kmem_free(*bufaddr, nlgrpsmax * sizeof (lgrp_affinity_t));
3087c478bd9Sstevel@tonic-gate 		*bufaddr = NULL;
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate #define	P_ANY	-2	/* cookie specifying any ID */
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate  * Find LWP with given ID in specified process and get its affinity for
3187c478bd9Sstevel@tonic-gate  * specified lgroup
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate lgrp_affinity_t
lgrp_affinity_get_thread(proc_t * p,id_t lwpid,lgrp_id_t lgrp)3217c478bd9Sstevel@tonic-gate lgrp_affinity_get_thread(proc_t *p, id_t lwpid, lgrp_id_t lgrp)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	lgrp_affinity_t aff;
3247c478bd9Sstevel@tonic-gate 	int		found;
3257c478bd9Sstevel@tonic-gate 	kthread_t	*t;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	aff = LGRP_AFF_NONE;
3307c478bd9Sstevel@tonic-gate 	found = 0;
3317c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
3327c478bd9Sstevel@tonic-gate 	/*
3337c478bd9Sstevel@tonic-gate 	 * The process may be executing in proc_exit() and its p->p_list may be
3347c478bd9Sstevel@tonic-gate 	 * already NULL.
3357c478bd9Sstevel@tonic-gate 	 */
3367c478bd9Sstevel@tonic-gate 	if (t == NULL)
3377c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	do {
3407c478bd9Sstevel@tonic-gate 		if (t->t_tid == lwpid || lwpid == P_ANY) {
3417c478bd9Sstevel@tonic-gate 			thread_lock(t);
3427c478bd9Sstevel@tonic-gate 			/*
3437c478bd9Sstevel@tonic-gate 			 * Check to see whether caller has permission to set
3447c478bd9Sstevel@tonic-gate 			 * affinity for LWP
3457c478bd9Sstevel@tonic-gate 			 */
3467c478bd9Sstevel@tonic-gate 			if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
3477c478bd9Sstevel@tonic-gate 				thread_unlock(t);
3487c478bd9Sstevel@tonic-gate 				return (set_errno(EPERM));
3497c478bd9Sstevel@tonic-gate 			}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			if (t->t_lgrp_affinity)
3527c478bd9Sstevel@tonic-gate 				aff = t->t_lgrp_affinity[lgrp];
3537c478bd9Sstevel@tonic-gate 			thread_unlock(t);
3547c478bd9Sstevel@tonic-gate 			found = 1;
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
3587c478bd9Sstevel@tonic-gate 	if (!found)
3597c478bd9Sstevel@tonic-gate 		aff = set_errno(ESRCH);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	return (aff);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate  * Get lgroup affinity for given LWP
3677c478bd9Sstevel@tonic-gate  */
3687c478bd9Sstevel@tonic-gate lgrp_affinity_t
lgrp_affinity_get(lgrp_affinity_args_t * ap)3697c478bd9Sstevel@tonic-gate lgrp_affinity_get(lgrp_affinity_args_t *ap)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		aff;
3727c478bd9Sstevel@tonic-gate 	lgrp_affinity_args_t	args;
3737c478bd9Sstevel@tonic-gate 	id_t			id;
3747c478bd9Sstevel@tonic-gate 	idtype_t		idtype;
3757c478bd9Sstevel@tonic-gate 	lgrp_id_t		lgrp;
3767c478bd9Sstevel@tonic-gate 	proc_t			*p;
3777c478bd9Sstevel@tonic-gate 	kthread_t		*t;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/*
3807c478bd9Sstevel@tonic-gate 	 * Copyin arguments
3817c478bd9Sstevel@tonic-gate 	 */
3827c478bd9Sstevel@tonic-gate 	if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
3837c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	id = args.id;
3867c478bd9Sstevel@tonic-gate 	idtype = args.idtype;
3877c478bd9Sstevel@tonic-gate 	lgrp = args.lgrp;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * Check for invalid lgroup
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	if (lgrp < 0 || lgrp == LGRP_NONE)
3937c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/*
3967c478bd9Sstevel@tonic-gate 	 * Check for existing lgroup
3977c478bd9Sstevel@tonic-gate 	 */
3987c478bd9Sstevel@tonic-gate 	if (lgrp > lgrp_alloc_max)
3997c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Get lgroup affinity for given LWP or process
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	switch (idtype) {
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	case P_LWPID:
4077c478bd9Sstevel@tonic-gate 		/*
4087c478bd9Sstevel@tonic-gate 		 * LWP in current process
4097c478bd9Sstevel@tonic-gate 		 */
4107c478bd9Sstevel@tonic-gate 		p = curproc;
4117c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
4127c478bd9Sstevel@tonic-gate 		if (id != P_MYID)	/* different thread */
4137c478bd9Sstevel@tonic-gate 			aff = lgrp_affinity_get_thread(p, id, lgrp);
4147c478bd9Sstevel@tonic-gate 		else {			/* current thread */
4157c478bd9Sstevel@tonic-gate 			aff = LGRP_AFF_NONE;
4167c478bd9Sstevel@tonic-gate 			t = curthread;
4177c478bd9Sstevel@tonic-gate 			thread_lock(t);
4187c478bd9Sstevel@tonic-gate 			if (t->t_lgrp_affinity)
4197c478bd9Sstevel@tonic-gate 				aff = t->t_lgrp_affinity[lgrp];
4207c478bd9Sstevel@tonic-gate 			thread_unlock(t);
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
4237c478bd9Sstevel@tonic-gate 		break;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	case P_PID:
4267c478bd9Sstevel@tonic-gate 		/*
4277c478bd9Sstevel@tonic-gate 		 * Process
4287c478bd9Sstevel@tonic-gate 		 */
4297c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		if (id == P_MYID)
4327c478bd9Sstevel@tonic-gate 			p = curproc;
4337c478bd9Sstevel@tonic-gate 		else {
4347c478bd9Sstevel@tonic-gate 			p = prfind(id);
4357c478bd9Sstevel@tonic-gate 			if (p == NULL) {
4367c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4377c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
4387c478bd9Sstevel@tonic-gate 			}
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
4427c478bd9Sstevel@tonic-gate 		aff = lgrp_affinity_get_thread(p, P_ANY, lgrp);
4437c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4467c478bd9Sstevel@tonic-gate 		break;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	default:
4497c478bd9Sstevel@tonic-gate 		aff = set_errno(EINVAL);
4507c478bd9Sstevel@tonic-gate 		break;
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	return (aff);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * Find lgroup for which this thread has most affinity in specified partition
45903400a71Sjjc  * starting from home lgroup unless specified starting lgroup is preferred
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate lpl_t *
lgrp_affinity_best(kthread_t * t,struct cpupart * cpupart,lgrp_id_t start,boolean_t prefer_start)46203400a71Sjjc lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start,
46303400a71Sjjc     boolean_t prefer_start)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*affs;
4667c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	best_aff;
4677c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
46803400a71Sjjc 	lgrp_id_t	finish;
4697c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
4707c478bd9Sstevel@tonic-gate 	lgrp_id_t	lgrpid;
4717c478bd9Sstevel@tonic-gate 	lpl_t		*lpl;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
4747c478bd9Sstevel@tonic-gate 	ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) ||
4757c478bd9Sstevel@tonic-gate 	    (MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t)));
4767c478bd9Sstevel@tonic-gate 	ASSERT(cpupart != NULL);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL)
4797c478bd9Sstevel@tonic-gate 		return (NULL);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	affs = t->t_lgrp_affinity;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/*
4847c478bd9Sstevel@tonic-gate 	 * Thread bound to CPU
4857c478bd9Sstevel@tonic-gate 	 */
4867c478bd9Sstevel@tonic-gate 	if (t->t_bind_cpu != PBIND_NONE) {
4877c478bd9Sstevel@tonic-gate 		cpu_t	*cp;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		/*
49003400a71Sjjc 		 * Find which lpl has most affinity among leaf lpl directly
49103400a71Sjjc 		 * containing CPU and its ancestor lpls
4927c478bd9Sstevel@tonic-gate 		 */
4937c478bd9Sstevel@tonic-gate 		cp = cpu[t->t_bind_cpu];
49403400a71Sjjc 
49503400a71Sjjc 		best_lpl = lpl = cp->cpu_lpl;
49603400a71Sjjc 		best_aff = affs[best_lpl->lpl_lgrpid];
49703400a71Sjjc 		while (lpl->lpl_parent != NULL) {
49803400a71Sjjc 			lpl = lpl->lpl_parent;
49903400a71Sjjc 			lgrpid = lpl->lpl_lgrpid;
50003400a71Sjjc 			if (affs[lgrpid] > best_aff) {
50103400a71Sjjc 				best_lpl = lpl;
50203400a71Sjjc 				best_aff = affs[lgrpid];
50303400a71Sjjc 			}
50403400a71Sjjc 		}
50503400a71Sjjc 		return (best_lpl);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/*
50903400a71Sjjc 	 * Start searching from home lgroup unless given starting lgroup is
51003400a71Sjjc 	 * preferred or home lgroup isn't in given pset.  Use root lgroup as
51103400a71Sjjc 	 * starting point if both home and starting lgroups aren't in given
51203400a71Sjjc 	 * pset.
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	ASSERT(start >= 0 && start <= lgrp_alloc_max);
5157c478bd9Sstevel@tonic-gate 	home = t->t_lpl->lpl_lgrpid;
51603400a71Sjjc 	if (!prefer_start && LGRP_CPUS_IN_PART(home, cpupart))
51703400a71Sjjc 		lgrpid = home;
51803400a71Sjjc 	else if (start != LGRP_NONE && LGRP_CPUS_IN_PART(start, cpupart))
51903400a71Sjjc 		lgrpid = start;
520c6402783Sakolb 	else
52103400a71Sjjc 		lgrpid = LGRP_ROOTID;
5227c478bd9Sstevel@tonic-gate 
52303400a71Sjjc 	best_lpl = &cpupart->cp_lgrploads[lgrpid];
52403400a71Sjjc 	best_aff = affs[lgrpid];
52503400a71Sjjc 	finish = lgrpid;
5267c478bd9Sstevel@tonic-gate 	do {
5277c478bd9Sstevel@tonic-gate 		/*
5287c478bd9Sstevel@tonic-gate 		 * Skip any lgroups that don't have CPU resources
5297c478bd9Sstevel@tonic-gate 		 * in this processor set.
5307c478bd9Sstevel@tonic-gate 		 */
5317c478bd9Sstevel@tonic-gate 		if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) {
5327c478bd9Sstevel@tonic-gate 			if (++lgrpid > lgrp_alloc_max)
5337c478bd9Sstevel@tonic-gate 				lgrpid = 0;	/* wrap the search */
5347c478bd9Sstevel@tonic-gate 			continue;
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		/*
5387c478bd9Sstevel@tonic-gate 		 * Find lgroup with most affinity
5397c478bd9Sstevel@tonic-gate 		 */
5407c478bd9Sstevel@tonic-gate 		lpl = &cpupart->cp_lgrploads[lgrpid];
5417c478bd9Sstevel@tonic-gate 		if (affs[lgrpid] > best_aff) {
5427c478bd9Sstevel@tonic-gate 			best_aff = affs[lgrpid];
5437c478bd9Sstevel@tonic-gate 			best_lpl = lpl;
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		if (++lgrpid > lgrp_alloc_max)
5477c478bd9Sstevel@tonic-gate 			lgrpid = 0;	/* wrap the search */
5487c478bd9Sstevel@tonic-gate 
54903400a71Sjjc 	} while (lgrpid != finish);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/*
5527c478bd9Sstevel@tonic-gate 	 * No lgroup (in this pset) with any affinity
5537c478bd9Sstevel@tonic-gate 	 */
5547c478bd9Sstevel@tonic-gate 	if (best_aff == LGRP_AFF_NONE)
5557c478bd9Sstevel@tonic-gate 		return (NULL);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	lgrpid = best_lpl->lpl_lgrpid;
5587c478bd9Sstevel@tonic-gate 	ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	return (best_lpl);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate  * Set thread's affinity for given lgroup
5667c478bd9Sstevel@tonic-gate  */
5677c478bd9Sstevel@tonic-gate int
lgrp_affinity_set_thread(kthread_t * t,lgrp_id_t lgrp,lgrp_affinity_t aff,lgrp_affinity_t ** aff_buf)5687c478bd9Sstevel@tonic-gate lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff,
5697c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf)
5707c478bd9Sstevel@tonic-gate {
571c6402783Sakolb 	lgrp_affinity_t	*affs;
572c6402783Sakolb 	lgrp_id_t	best;
5737c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
5747c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
5757c478bd9Sstevel@tonic-gate 	int		retval;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
5787c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	retval = 0;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	thread_lock(t);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	/*
5857c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
5867c478bd9Sstevel@tonic-gate 	 * thread
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
5897c478bd9Sstevel@tonic-gate 		thread_unlock(t);
5907c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL) {
5947c478bd9Sstevel@tonic-gate 		if (aff == LGRP_AFF_NONE) {
5957c478bd9Sstevel@tonic-gate 			thread_unlock(t);
5967c478bd9Sstevel@tonic-gate 			return (0);
5977c478bd9Sstevel@tonic-gate 		}
5987c478bd9Sstevel@tonic-gate 		ASSERT(aff_buf != NULL && *aff_buf != NULL);
5997c478bd9Sstevel@tonic-gate 		t->t_lgrp_affinity = *aff_buf;
6007c478bd9Sstevel@tonic-gate 		*aff_buf = NULL;
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
603c6402783Sakolb 	affs = t->t_lgrp_affinity;
604c6402783Sakolb 	affs[lgrp] = aff;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/*
6077c478bd9Sstevel@tonic-gate 	 * Find lgroup for which thread has most affinity,
608c6402783Sakolb 	 * starting with lgroup for which affinity being set
6097c478bd9Sstevel@tonic-gate 	 */
61003400a71Sjjc 	best_lpl = lgrp_affinity_best(t, t->t_cpupart, lgrp, B_TRUE);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/*
613c6402783Sakolb 	 * Rehome if found lgroup with more affinity than home or lgroup for
614c6402783Sakolb 	 * which affinity is being set has same affinity as home
6157c478bd9Sstevel@tonic-gate 	 */
616c6402783Sakolb 	home = t->t_lpl->lpl_lgrpid;
617c6402783Sakolb 	if (best_lpl != NULL && best_lpl != t->t_lpl) {
618c6402783Sakolb 		best = best_lpl->lpl_lgrpid;
619c6402783Sakolb 		if (affs[best] > affs[home] || (affs[best] == affs[home] &&
620c6402783Sakolb 		    best == lgrp))
6217c478bd9Sstevel@tonic-gate 			lgrp_move_thread(t, best_lpl, 1);
622c6402783Sakolb 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	thread_unlock(t);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	return (retval);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate  * Set process' affinity for specified lgroup
6327c478bd9Sstevel@tonic-gate  */
6337c478bd9Sstevel@tonic-gate int
lgrp_affinity_set_proc(proc_t * p,lgrp_id_t lgrp,lgrp_affinity_t aff,lgrp_affinity_t ** aff_buf_array)6347c478bd9Sstevel@tonic-gate lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff,
6357c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf_array)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*buf;
6387c478bd9Sstevel@tonic-gate 	int		err = 0;
6397c478bd9Sstevel@tonic-gate 	int		i;
6407c478bd9Sstevel@tonic-gate 	int		retval;
6417c478bd9Sstevel@tonic-gate 	kthread_t	*t;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock));
6447c478bd9Sstevel@tonic-gate 	ASSERT(aff_buf_array != NULL);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	i = 0;
6477c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
6487c478bd9Sstevel@tonic-gate 	if (t != NULL) {
6497c478bd9Sstevel@tonic-gate 		do {
6507c478bd9Sstevel@tonic-gate 			/*
6517c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for thread
6527c478bd9Sstevel@tonic-gate 			 */
6537c478bd9Sstevel@tonic-gate 			buf = aff_buf_array[i];
6547c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 			if (err == 0 && retval != 0)
6577c478bd9Sstevel@tonic-gate 				err = retval;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 			/*
6607c478bd9Sstevel@tonic-gate 			 * Advance pointer to next buffer
6617c478bd9Sstevel@tonic-gate 			 */
6627c478bd9Sstevel@tonic-gate 			if (buf == NULL) {
6637c478bd9Sstevel@tonic-gate 				ASSERT(i < p->p_lwpcnt);
6647c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = NULL;
6657c478bd9Sstevel@tonic-gate 				i++;
6667c478bd9Sstevel@tonic-gate 			}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 	return (err);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate  * Set LWP's or process' affinity for specified lgroup
6767c478bd9Sstevel@tonic-gate  *
6777c478bd9Sstevel@tonic-gate  * When setting affinities, pidlock, process p_lock, and thread_lock()
6787c478bd9Sstevel@tonic-gate  * need to be held in that order to protect target thread's pset, process,
6797c478bd9Sstevel@tonic-gate  * process contents, and thread contents.  thread_lock() does splhigh(),
6807c478bd9Sstevel@tonic-gate  * so it ends up having similiar effect as kpreempt_disable(), so it will
6817c478bd9Sstevel@tonic-gate  * protect calls to lgrp_move_thread() and lgrp_choose() from pset changes.
6827c478bd9Sstevel@tonic-gate  */
6837c478bd9Sstevel@tonic-gate int
lgrp_affinity_set(lgrp_affinity_args_t * ap)6847c478bd9Sstevel@tonic-gate lgrp_affinity_set(lgrp_affinity_args_t *ap)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		aff;
6877c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		*aff_buf;
6887c478bd9Sstevel@tonic-gate 	lgrp_affinity_args_t	args;
6897c478bd9Sstevel@tonic-gate 	id_t			id;
6907c478bd9Sstevel@tonic-gate 	idtype_t		idtype;
6917c478bd9Sstevel@tonic-gate 	lgrp_id_t		lgrp;
6927c478bd9Sstevel@tonic-gate 	int			nthreads;
6937c478bd9Sstevel@tonic-gate 	proc_t			*p;
6947c478bd9Sstevel@tonic-gate 	int			retval;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * Copyin arguments
6987c478bd9Sstevel@tonic-gate 	 */
6997c478bd9Sstevel@tonic-gate 	if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
7007c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	idtype = args.idtype;
7037c478bd9Sstevel@tonic-gate 	id = args.id;
7047c478bd9Sstevel@tonic-gate 	lgrp = args.lgrp;
7057c478bd9Sstevel@tonic-gate 	aff = args.aff;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	/*
7087c478bd9Sstevel@tonic-gate 	 * Check for invalid lgroup
7097c478bd9Sstevel@tonic-gate 	 */
7107c478bd9Sstevel@tonic-gate 	if (lgrp < 0 || lgrp == LGRP_NONE)
7117c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/*
7147c478bd9Sstevel@tonic-gate 	 * Check for existing lgroup
7157c478bd9Sstevel@tonic-gate 	 */
7167c478bd9Sstevel@tonic-gate 	if (lgrp > lgrp_alloc_max)
7177c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	/*
7207c478bd9Sstevel@tonic-gate 	 * Check for legal affinity
7217c478bd9Sstevel@tonic-gate 	 */
7227c478bd9Sstevel@tonic-gate 	if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK &&
7237c478bd9Sstevel@tonic-gate 	    aff != LGRP_AFF_STRONG)
7247c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	/*
7277c478bd9Sstevel@tonic-gate 	 * Must be process or LWP ID
7287c478bd9Sstevel@tonic-gate 	 */
7297c478bd9Sstevel@tonic-gate 	if (idtype != P_LWPID && idtype != P_PID)
7307c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * Set given LWP's or process' affinity for specified lgroup
7347c478bd9Sstevel@tonic-gate 	 */
7357c478bd9Sstevel@tonic-gate 	switch (idtype) {
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	case P_LWPID:
7387c478bd9Sstevel@tonic-gate 		/*
7397c478bd9Sstevel@tonic-gate 		 * Allocate memory for thread's lgroup affinities
7407c478bd9Sstevel@tonic-gate 		 * ahead of time w/o holding locks
7417c478bd9Sstevel@tonic-gate 		 */
7427c478bd9Sstevel@tonic-gate 		aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t),
7437c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		p = curproc;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		/*
7487c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
7497c478bd9Sstevel@tonic-gate 		 */
7507c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
7517c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
7527c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(curthread, lgrp, aff,
7537c478bd9Sstevel@tonic-gate 			    &aff_buf);
7547c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
7557c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
7567c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
7577c478bd9Sstevel@tonic-gate 			int		found = 0;
7587c478bd9Sstevel@tonic-gate 			kthread_t	*t;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
7617c478bd9Sstevel@tonic-gate 			do {
7627c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
7637c478bd9Sstevel@tonic-gate 					retval = lgrp_affinity_set_thread(t,
7647c478bd9Sstevel@tonic-gate 					    lgrp, aff, &aff_buf);
7657c478bd9Sstevel@tonic-gate 					found = 1;
7667c478bd9Sstevel@tonic-gate 					break;
7677c478bd9Sstevel@tonic-gate 				}
7687c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
7697c478bd9Sstevel@tonic-gate 			if (!found)
7707c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		/*
7757c478bd9Sstevel@tonic-gate 		 * Free memory for lgroup affinities,
7767c478bd9Sstevel@tonic-gate 		 * since thread didn't need it
7777c478bd9Sstevel@tonic-gate 		 */
7787c478bd9Sstevel@tonic-gate 		if (aff_buf)
7797c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf,
7807c478bd9Sstevel@tonic-gate 			    nlgrpsmax * sizeof (lgrp_affinity_t));
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		break;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	case P_PID:
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 		do {
7877c478bd9Sstevel@tonic-gate 			lgrp_affinity_t	**aff_buf_array;
7887c478bd9Sstevel@tonic-gate 			int		i;
7897c478bd9Sstevel@tonic-gate 			size_t		size;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 			/*
7927c478bd9Sstevel@tonic-gate 			 * Get process
7937c478bd9Sstevel@tonic-gate 			 */
7947c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 			if (id == P_MYID)
7977c478bd9Sstevel@tonic-gate 				p = curproc;
7987c478bd9Sstevel@tonic-gate 			else
7997c478bd9Sstevel@tonic-gate 				p = prfind(id);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 			if (p == NULL) {
8027c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
8037c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
8047c478bd9Sstevel@tonic-gate 			}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 			/*
8077c478bd9Sstevel@tonic-gate 			 * Get number of threads in process
8087c478bd9Sstevel@tonic-gate 			 *
8097c478bd9Sstevel@tonic-gate 			 * NOTE: Only care about user processes,
8107c478bd9Sstevel@tonic-gate 			 *	 so p_lwpcnt should be number of threads.
8117c478bd9Sstevel@tonic-gate 			 */
8127c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
8137c478bd9Sstevel@tonic-gate 			nthreads = p->p_lwpcnt;
8147c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 			if (nthreads < 1)
8197c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 			/*
8227c478bd9Sstevel@tonic-gate 			 * Preallocate memory for lgroup affinities for
8237c478bd9Sstevel@tonic-gate 			 * each thread in process now to avoid holding
8247c478bd9Sstevel@tonic-gate 			 * any locks.  Allocate an array to hold a buffer
8257c478bd9Sstevel@tonic-gate 			 * for each thread.
8267c478bd9Sstevel@tonic-gate 			 */
8277c478bd9Sstevel@tonic-gate 			aff_buf_array = kmem_zalloc(nthreads *
8287c478bd9Sstevel@tonic-gate 			    sizeof (lgrp_affinity_t *), KM_SLEEP);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 			size = nlgrpsmax * sizeof (lgrp_affinity_t);
8317c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
8327c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 			/*
8377c478bd9Sstevel@tonic-gate 			 * Get process again since dropped locks to allocate
8387c478bd9Sstevel@tonic-gate 			 * memory (except current process)
8397c478bd9Sstevel@tonic-gate 			 */
8407c478bd9Sstevel@tonic-gate 			if (id != P_MYID)
8417c478bd9Sstevel@tonic-gate 				p = prfind(id);
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 			/*
8447c478bd9Sstevel@tonic-gate 			 * Process went away after we dropped locks and before
8457c478bd9Sstevel@tonic-gate 			 * reacquiring them, so drop locks, free memory, and
8467c478bd9Sstevel@tonic-gate 			 * return.
8477c478bd9Sstevel@tonic-gate 			 */
8487c478bd9Sstevel@tonic-gate 			if (p == NULL) {
8497c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
8507c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
8517c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8527c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
8537c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
8547c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
8557c478bd9Sstevel@tonic-gate 			}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 			/*
8607c478bd9Sstevel@tonic-gate 			 * See whether number of threads is same
8617c478bd9Sstevel@tonic-gate 			 * If not, drop locks, free memory, and try again
8627c478bd9Sstevel@tonic-gate 			 */
8637c478bd9Sstevel@tonic-gate 			if (nthreads != p->p_lwpcnt) {
8647c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
8657c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
8667c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
8677c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8687c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
8697c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
8707c478bd9Sstevel@tonic-gate 				continue;
8717c478bd9Sstevel@tonic-gate 			}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 			/*
8747c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for threads in process
8757c478bd9Sstevel@tonic-gate 			 */
8767c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_proc(p, lgrp, aff,
8777c478bd9Sstevel@tonic-gate 			    aff_buf_array);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
8807c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 			/*
8837c478bd9Sstevel@tonic-gate 			 * Free any leftover memory, since some threads may
8847c478bd9Sstevel@tonic-gate 			 * have already allocated memory and set lgroup
8857c478bd9Sstevel@tonic-gate 			 * affinities before
8867c478bd9Sstevel@tonic-gate 			 */
8877c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
8887c478bd9Sstevel@tonic-gate 				if (aff_buf_array[i] != NULL)
8897c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8907c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf_array,
8917c478bd9Sstevel@tonic-gate 			    nthreads * sizeof (lgrp_affinity_t *));
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 			break;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 		} while (nthreads != p->p_lwpcnt);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		break;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	default:
9007c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
9017c478bd9Sstevel@tonic-gate 		break;
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	return (retval);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate /*
9097c478bd9Sstevel@tonic-gate  * Return the latest generation number for the lgroup hierarchy
9107c478bd9Sstevel@tonic-gate  * with the given view
9117c478bd9Sstevel@tonic-gate  */
9127c478bd9Sstevel@tonic-gate lgrp_gen_t
lgrp_generation(lgrp_view_t view)9137c478bd9Sstevel@tonic-gate lgrp_generation(lgrp_view_t view)
9147c478bd9Sstevel@tonic-gate {
9157c478bd9Sstevel@tonic-gate 	cpupart_t	*cpupart;
9167c478bd9Sstevel@tonic-gate 	uint_t		gen;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	kpreempt_disable();
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/*
9217c478bd9Sstevel@tonic-gate 	 * Determine generation number for given view
9227c478bd9Sstevel@tonic-gate 	 */
9237c478bd9Sstevel@tonic-gate 	if (view == LGRP_VIEW_OS)
9247c478bd9Sstevel@tonic-gate 		/*
9257c478bd9Sstevel@tonic-gate 		 * Return generation number of lgroup hierarchy for OS view
9267c478bd9Sstevel@tonic-gate 		 */
9277c478bd9Sstevel@tonic-gate 		gen = lgrp_gen;
9287c478bd9Sstevel@tonic-gate 	else {
9297c478bd9Sstevel@tonic-gate 		/*
9307c478bd9Sstevel@tonic-gate 		 * For caller's view, use generation numbers for lgroup
9317c478bd9Sstevel@tonic-gate 		 * hierarchy and caller's pset
9327c478bd9Sstevel@tonic-gate 		 * NOTE: Caller needs to check for change in pset ID
9337c478bd9Sstevel@tonic-gate 		 */
9347c478bd9Sstevel@tonic-gate 		cpupart = curthread->t_cpupart;
9357c478bd9Sstevel@tonic-gate 		ASSERT(cpupart);
9367c478bd9Sstevel@tonic-gate 		gen = lgrp_gen + cpupart->cp_gen;
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	kpreempt_enable();
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	return (gen);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate lgrp_id_t
lgrp_home_thread(kthread_t * t)9467c478bd9Sstevel@tonic-gate lgrp_home_thread(kthread_t *t)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
9517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	thread_lock(t);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/*
9567c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
9577c478bd9Sstevel@tonic-gate 	 * thread
9587c478bd9Sstevel@tonic-gate 	 */
9597c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
9607c478bd9Sstevel@tonic-gate 		thread_unlock(t);
9617c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	home = lgrp_home_id(t);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	thread_unlock(t);
9677c478bd9Sstevel@tonic-gate 	return (home);
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate /*
9727c478bd9Sstevel@tonic-gate  * Get home lgroup of given process or thread
9737c478bd9Sstevel@tonic-gate  */
9747c478bd9Sstevel@tonic-gate lgrp_id_t
lgrp_home_get(idtype_t idtype,id_t id)9757c478bd9Sstevel@tonic-gate lgrp_home_get(idtype_t idtype, id_t id)
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate 	proc_t		*p;
9787c478bd9Sstevel@tonic-gate 	lgrp_id_t	retval;
9797c478bd9Sstevel@tonic-gate 	kthread_t	*t;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	/*
9827c478bd9Sstevel@tonic-gate 	 * Get home lgroup of given LWP or process
9837c478bd9Sstevel@tonic-gate 	 */
9847c478bd9Sstevel@tonic-gate 	switch (idtype) {
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	case P_LWPID:
9877c478bd9Sstevel@tonic-gate 		p = curproc;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 		/*
9907c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
9917c478bd9Sstevel@tonic-gate 		 */
9927c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
9937c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
9947c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(curthread);
9957c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
9967c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
9977c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
9987c478bd9Sstevel@tonic-gate 			int	found = 0;
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
10017c478bd9Sstevel@tonic-gate 			do {
10027c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
10037c478bd9Sstevel@tonic-gate 					retval = lgrp_home_thread(t);
10047c478bd9Sstevel@tonic-gate 					found = 1;
10057c478bd9Sstevel@tonic-gate 					break;
10067c478bd9Sstevel@tonic-gate 				}
10077c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
10087c478bd9Sstevel@tonic-gate 			if (!found)
10097c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
10107c478bd9Sstevel@tonic-gate 		}
10117c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
10127c478bd9Sstevel@tonic-gate 		break;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	case P_PID:
10157c478bd9Sstevel@tonic-gate 		/*
10167c478bd9Sstevel@tonic-gate 		 * Get process
10177c478bd9Sstevel@tonic-gate 		 */
10187c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		if (id == P_MYID)
10217c478bd9Sstevel@tonic-gate 			p = curproc;
10227c478bd9Sstevel@tonic-gate 		else
10237c478bd9Sstevel@tonic-gate 			p = prfind(id);
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 		if (p == NULL) {
10267c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
10277c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
10317c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
10327c478bd9Sstevel@tonic-gate 		if (t == NULL)
10337c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
10347c478bd9Sstevel@tonic-gate 		else
10357c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(t);
10367c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		break;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	default:
10437c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
10447c478bd9Sstevel@tonic-gate 		break;
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	return (retval);
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate  * Return latency between "from" and "to" lgroups
10537c478bd9Sstevel@tonic-gate  *
10547c478bd9Sstevel@tonic-gate  * This latency number can only be used for relative comparison
10557c478bd9Sstevel@tonic-gate  * between lgroups on the running system, cannot be used across platforms,
10567c478bd9Sstevel@tonic-gate  * and may not reflect the actual latency.  It is platform and implementation
10577c478bd9Sstevel@tonic-gate  * specific, so platform gets to decide its value.  It would be nice if the
10587c478bd9Sstevel@tonic-gate  * number was at least proportional to make comparisons more meaningful though.
10597c478bd9Sstevel@tonic-gate  */
10607c478bd9Sstevel@tonic-gate int
lgrp_latency(lgrp_id_t from,lgrp_id_t to)10617c478bd9Sstevel@tonic-gate lgrp_latency(lgrp_id_t from, lgrp_id_t to)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate 	lgrp_t		*from_lgrp;
10647c478bd9Sstevel@tonic-gate 	int		i;
10657c478bd9Sstevel@tonic-gate 	int		latency;
10667c478bd9Sstevel@tonic-gate 	int		latency_max;
10677c478bd9Sstevel@tonic-gate 	lgrp_t		*to_lgrp;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	if (from < 0 || to < 0)
10727c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if (from > lgrp_alloc_max || to > lgrp_alloc_max)
10757c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	from_lgrp = lgrp_table[from];
10787c478bd9Sstevel@tonic-gate 	to_lgrp = lgrp_table[to];
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) {
10817c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	/*
10857c478bd9Sstevel@tonic-gate 	 * Get latency for same lgroup
10867c478bd9Sstevel@tonic-gate 	 */
10877c478bd9Sstevel@tonic-gate 	if (from == to) {
10887c478bd9Sstevel@tonic-gate 		latency = from_lgrp->lgrp_latency;
10897c478bd9Sstevel@tonic-gate 		return (latency);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	/*
10937c478bd9Sstevel@tonic-gate 	 * Get latency between leaf lgroups
10947c478bd9Sstevel@tonic-gate 	 */
10957c478bd9Sstevel@tonic-gate 	if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0)
10967c478bd9Sstevel@tonic-gate 		return (lgrp_plat_latency(from_lgrp->lgrp_plathand,
10977c478bd9Sstevel@tonic-gate 		    to_lgrp->lgrp_plathand));
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	/*
11007c478bd9Sstevel@tonic-gate 	 * Determine max latency between resources in two lgroups
11017c478bd9Sstevel@tonic-gate 	 */
11027c478bd9Sstevel@tonic-gate 	latency_max = 0;
11037c478bd9Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
11047c478bd9Sstevel@tonic-gate 		lgrp_t	*from_rsrc;
11057c478bd9Sstevel@tonic-gate 		int	j;
11067c478bd9Sstevel@tonic-gate 		lgrp_t	*to_rsrc;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		from_rsrc = lgrp_table[i];
11097c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(from_rsrc) ||
11107c478bd9Sstevel@tonic-gate 		    !klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i))
11117c478bd9Sstevel@tonic-gate 			continue;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		for (j = 0; j <= lgrp_alloc_max; j++) {
11147c478bd9Sstevel@tonic-gate 			to_rsrc = lgrp_table[j];
11157c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to_rsrc) ||
11167c478bd9Sstevel@tonic-gate 			    klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM],
11177c478bd9Sstevel@tonic-gate 			    j) == 0)
11187c478bd9Sstevel@tonic-gate 				continue;
11197c478bd9Sstevel@tonic-gate 			latency = lgrp_plat_latency(from_rsrc->lgrp_plathand,
11207c478bd9Sstevel@tonic-gate 			    to_rsrc->lgrp_plathand);
11217c478bd9Sstevel@tonic-gate 			if (latency > latency_max)
11227c478bd9Sstevel@tonic-gate 				latency_max = latency;
11237c478bd9Sstevel@tonic-gate 		}
11247c478bd9Sstevel@tonic-gate 	}
11257c478bd9Sstevel@tonic-gate 	return (latency_max);
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate  * Return lgroup interface version number
11317c478bd9Sstevel@tonic-gate  * 0 - none
11327c478bd9Sstevel@tonic-gate  * 1 - original
11337c478bd9Sstevel@tonic-gate  * 2 - lgrp_latency_cookie() and lgrp_resources() added
11347c478bd9Sstevel@tonic-gate  */
11357c478bd9Sstevel@tonic-gate int
lgrp_version(int version)11367c478bd9Sstevel@tonic-gate lgrp_version(int version)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate 	/*
11397c478bd9Sstevel@tonic-gate 	 * Return LGRP_VER_NONE when requested version isn't supported
11407c478bd9Sstevel@tonic-gate 	 */
11417c478bd9Sstevel@tonic-gate 	if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT)
11427c478bd9Sstevel@tonic-gate 		return (LGRP_VER_NONE);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/*
11457c478bd9Sstevel@tonic-gate 	 * Return current version when LGRP_VER_NONE passed in
11467c478bd9Sstevel@tonic-gate 	 */
11477c478bd9Sstevel@tonic-gate 	if (version == LGRP_VER_NONE)
11487c478bd9Sstevel@tonic-gate 		return (LGRP_VER_CURRENT);
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	/*
11517c478bd9Sstevel@tonic-gate 	 * Otherwise, return supported version.
11527c478bd9Sstevel@tonic-gate 	 */
11537c478bd9Sstevel@tonic-gate 	return (version);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate /*
11587c478bd9Sstevel@tonic-gate  * Snapshot of lgroup hieararchy
11597c478bd9Sstevel@tonic-gate  *
11607c478bd9Sstevel@tonic-gate  * One snapshot is kept and is based on the kernel's native data model, so
11617c478bd9Sstevel@tonic-gate  * a 32-bit snapshot is kept for the 32-bit kernel and a 64-bit one for the
11627c478bd9Sstevel@tonic-gate  * 64-bit kernel.  If a 32-bit user wants a snapshot from the 64-bit kernel,
11637c478bd9Sstevel@tonic-gate  * the kernel generates a 32-bit snapshot from the data in its 64-bit snapshot.
11647c478bd9Sstevel@tonic-gate  *
11657c478bd9Sstevel@tonic-gate  * The format is defined by lgroup snapshot header and the layout of
11667c478bd9Sstevel@tonic-gate  * the snapshot in memory is as follows:
11677c478bd9Sstevel@tonic-gate  * 1) lgroup snapshot header
11687c478bd9Sstevel@tonic-gate  *    - specifies format of snapshot
11697c478bd9Sstevel@tonic-gate  *    - defined by lgrp_snapshot_header_t
11707c478bd9Sstevel@tonic-gate  * 2) lgroup info array
11717c478bd9Sstevel@tonic-gate  *    - contains information about each lgroup
11727c478bd9Sstevel@tonic-gate  *    - one element for each lgroup
11737c478bd9Sstevel@tonic-gate  *    - each element is defined by lgrp_info_t
11747c478bd9Sstevel@tonic-gate  * 3) lgroup CPU ID array
11757c478bd9Sstevel@tonic-gate  *    - contains list (array) of CPU IDs for each lgroup
11767c478bd9Sstevel@tonic-gate  *    - lgrp_info_t points into array and specifies how many CPUs belong to
11777c478bd9Sstevel@tonic-gate  *      given lgroup
11787c478bd9Sstevel@tonic-gate  * 4) lgroup parents array
11797c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of parents for each lgroup
11807c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11817c478bd9Sstevel@tonic-gate  * 5) lgroup children array
11827c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of children for each lgroup
11837c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11847c478bd9Sstevel@tonic-gate  * 6) lgroup resources array
11857c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of resources for each lgroup
11867c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11877c478bd9Sstevel@tonic-gate  * 7) lgroup latency table
11887c478bd9Sstevel@tonic-gate  *    - contains latency from each lgroup to each of other lgroups
11897c478bd9Sstevel@tonic-gate  *
11907c478bd9Sstevel@tonic-gate  * NOTE:  Must use nlgrpsmax for per lgroup data structures because lgroups
11917c478bd9Sstevel@tonic-gate  *	  may be sparsely allocated.
11927c478bd9Sstevel@tonic-gate  */
11937c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t	*lgrp_snap = NULL;	/* lgroup snapshot */
11947c478bd9Sstevel@tonic-gate static kmutex_t		lgrp_snap_lock;		/* snapshot lock */
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate  * Take a snapshot of lgroup hierarchy and return size of buffer
11997c478bd9Sstevel@tonic-gate  * needed to hold snapshot
12007c478bd9Sstevel@tonic-gate  */
12017c478bd9Sstevel@tonic-gate static int
lgrp_snapshot(void)12027c478bd9Sstevel@tonic-gate lgrp_snapshot(void)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate 	size_t		bitmask_size;
12057c478bd9Sstevel@tonic-gate 	size_t		bitmasks_size;
12067c478bd9Sstevel@tonic-gate 	size_t		bufsize;
12077c478bd9Sstevel@tonic-gate 	int		cpu_index;
12087c478bd9Sstevel@tonic-gate 	size_t		cpuids_size;
12097c478bd9Sstevel@tonic-gate 	int		i;
12107c478bd9Sstevel@tonic-gate 	int		j;
12117c478bd9Sstevel@tonic-gate 	size_t		info_size;
12127c478bd9Sstevel@tonic-gate 	size_t		lats_size;
12137c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_children;
12147c478bd9Sstevel@tonic-gate 	processorid_t	*lgrp_cpuids;
12157c478bd9Sstevel@tonic-gate 	lgrp_info_t	*lgrp_info;
12167c478bd9Sstevel@tonic-gate 	int		**lgrp_lats;
12177c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_parents;
12187c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_rsets;
12197c478bd9Sstevel@tonic-gate 	ulong_t		*lgrpset;
12207c478bd9Sstevel@tonic-gate 	int		snap_ncpus;
12217c478bd9Sstevel@tonic-gate 	int		snap_nlgrps;
12227c478bd9Sstevel@tonic-gate 	int		snap_nlgrpsmax;
12237c478bd9Sstevel@tonic-gate 	size_t		snap_hdr_size;
12247c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
12257c478bd9Sstevel@tonic-gate 	model_t		model = DATAMODEL_NATIVE;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	/*
12287c478bd9Sstevel@tonic-gate 	 * Have up-to-date snapshot, so check to see whether caller is 32-bit
12297c478bd9Sstevel@tonic-gate 	 * program and need to return size of 32-bit snapshot now.
12307c478bd9Sstevel@tonic-gate 	 */
12317c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
12327c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32 && lgrp_snap &&
12337c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_gen == lgrp_gen) {
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 		/*
12387c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
12397c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
12407c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
12417c478bd9Sstevel@tonic-gate 		 */
12427c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
12437c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
12447c478bd9Sstevel@tonic-gate 		info_size =
12457c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
12467c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
12477c478bd9Sstevel@tonic-gate 		cpuids_size =
12487c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
12497c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		/*
12527c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for parents, children, and resources
12537c478bd9Sstevel@tonic-gate 		 * for each lgroup and pset lgroup set
12547c478bd9Sstevel@tonic-gate 		 */
12557c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
12567c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
12577c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		/*
12607c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
12617c478bd9Sstevel@tonic-gate 		 */
12627c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (caddr32_t) +
12637c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
12667c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
12677c478bd9Sstevel@tonic-gate 		return (bufsize);
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	/*
12727c478bd9Sstevel@tonic-gate 	 * Check whether snapshot is up-to-date
12737c478bd9Sstevel@tonic-gate 	 * Free it and take another one if not
12747c478bd9Sstevel@tonic-gate 	 */
12757c478bd9Sstevel@tonic-gate 	if (lgrp_snap) {
12767c478bd9Sstevel@tonic-gate 		if (lgrp_snap->ss_gen == lgrp_gen)
12777c478bd9Sstevel@tonic-gate 			return (lgrp_snap->ss_size);
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, lgrp_snap->ss_size);
12807c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/*
12847c478bd9Sstevel@tonic-gate 	 * Allocate memory for snapshot
12857c478bd9Sstevel@tonic-gate 	 * w/o holding cpu_lock while waiting for memory
12867c478bd9Sstevel@tonic-gate 	 */
12877c478bd9Sstevel@tonic-gate 	while (lgrp_snap == NULL) {
12887c478bd9Sstevel@tonic-gate 		int	old_generation;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 		/*
12917c478bd9Sstevel@tonic-gate 		 * Take snapshot of lgroup generation number
12927c478bd9Sstevel@tonic-gate 		 * and configuration size dependent information
12937c478bd9Sstevel@tonic-gate 		 * NOTE: Only count number of online CPUs,
12947c478bd9Sstevel@tonic-gate 		 * since only online CPUs appear in lgroups.
12957c478bd9Sstevel@tonic-gate 		 */
12967c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
12977c478bd9Sstevel@tonic-gate 		old_generation = lgrp_gen;
12987c478bd9Sstevel@tonic-gate 		snap_ncpus = ncpus_online;
12997c478bd9Sstevel@tonic-gate 		snap_nlgrps = nlgrps;
13007c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = nlgrpsmax;
13017c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		/*
13047c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for snapshot,
13057c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
13067c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
13077c478bd9Sstevel@tonic-gate 		 */
13087c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
13097c478bd9Sstevel@tonic-gate 		    sizeof (void *));
13107c478bd9Sstevel@tonic-gate 		info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
13117c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
13127c478bd9Sstevel@tonic-gate 		cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
13137c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
13147c478bd9Sstevel@tonic-gate 		/*
13157c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for pset lgroup set and  parents,
13167c478bd9Sstevel@tonic-gate 		 * children, and resource sets for each lgroup
13177c478bd9Sstevel@tonic-gate 		 */
13187c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
13197c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
13207c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 		/*
13237c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
13247c478bd9Sstevel@tonic-gate 		 */
13257c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (int *) +
13267c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
13297c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 		/*
13327c478bd9Sstevel@tonic-gate 		 * Allocate memory for buffer
13337c478bd9Sstevel@tonic-gate 		 */
13347c478bd9Sstevel@tonic-gate 		lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP);
13357c478bd9Sstevel@tonic-gate 		if (lgrp_snap == NULL)
13367c478bd9Sstevel@tonic-gate 			return (set_errno(ENOMEM));
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 		/*
13397c478bd9Sstevel@tonic-gate 		 * Check whether generation number has changed
13407c478bd9Sstevel@tonic-gate 		 */
13417c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
13427c478bd9Sstevel@tonic-gate 		if (lgrp_gen == old_generation)
13437c478bd9Sstevel@tonic-gate 			break;		/* hasn't change, so done. */
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 		/*
13467c478bd9Sstevel@tonic-gate 		 * Generation number changed, so free memory and try again.
13477c478bd9Sstevel@tonic-gate 		 */
13487c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
13497c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, bufsize);
13507c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	/*
13547c478bd9Sstevel@tonic-gate 	 * Fill in lgroup snapshot header
13557c478bd9Sstevel@tonic-gate 	 * (including pointers to tables of lgroup info, CPU IDs, and parents
13567c478bd9Sstevel@tonic-gate 	 * and children)
13577c478bd9Sstevel@tonic-gate 	 */
13587c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_version = LGRP_VER_CURRENT;
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	/*
13617c478bd9Sstevel@tonic-gate 	 * XXX For now, liblgrp only needs to know whether the hierarchy
13627c478bd9Sstevel@tonic-gate 	 * XXX only has one level or not
13637c478bd9Sstevel@tonic-gate 	 */
13647c478bd9Sstevel@tonic-gate 	if (snap_nlgrps == 1)
13657c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 1;
13667c478bd9Sstevel@tonic-gate 	else
13677c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 2;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_root = LGRP_ROOTID;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps;
13727c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax;
13737c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_ncpus = snap_ncpus;
13747c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_gen = lgrp_gen;
13757c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_view = LGRP_VIEW_OS;
13767c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_pset = 0;		/* NOTE: caller should set if needed */
13777c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_size = bufsize;
13787c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_magic = (uintptr_t)lgrp_snap;
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_info = lgrp_info =
13817c478bd9Sstevel@tonic-gate 	    (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_cpuids = lgrp_cpuids =
13847c478bd9Sstevel@tonic-gate 	    (processorid_t *)((uintptr_t)lgrp_info + info_size);
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_lgrpset = lgrpset =
13877c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size);
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_parents = lgrp_parents =
13907c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrpset + bitmask_size);
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_children = lgrp_children =
13937c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax *
13947c478bd9Sstevel@tonic-gate 	    bitmask_size));
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_rsets = lgrp_rsets =
13977c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax *
13987c478bd9Sstevel@tonic-gate 	    bitmask_size));
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_latencies = lgrp_lats =
14017c478bd9Sstevel@tonic-gate 	    (int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT *
14027c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax * bitmask_size));
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	/*
14057c478bd9Sstevel@tonic-gate 	 * Fill in lgroup information
14067c478bd9Sstevel@tonic-gate 	 */
14077c478bd9Sstevel@tonic-gate 	cpu_index = 0;
14087c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
14097c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
14107c478bd9Sstevel@tonic-gate 		int		cpu_count;
14117c478bd9Sstevel@tonic-gate 		struct cpu	*head;
14127c478bd9Sstevel@tonic-gate 		int		k;
14137c478bd9Sstevel@tonic-gate 		lgrp_t		*lgrp;
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 		lgrp = lgrp_table[i];
14167c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(lgrp)) {
14177c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info[i], sizeof (lgrp_info[i]));
14187c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_lgrpid = LGRP_NONE;
14197c478bd9Sstevel@tonic-gate 			continue;
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_lgrpid = i;
14237c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_latency = lgrp->lgrp_latency;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 		/*
14267c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, and lgroup resources
14277c478bd9Sstevel@tonic-gate 		 */
14287c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_parents =
14297c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size));
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		if (lgrp->lgrp_parent)
14327c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_info[i].info_parents,
14337c478bd9Sstevel@tonic-gate 			    lgrp->lgrp_parent->lgrp_id);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_children =
14367c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size));
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++)
14397c478bd9Sstevel@tonic-gate 			if (klgrpset_ismember(lgrp->lgrp_children, j))
14407c478bd9Sstevel@tonic-gate 				BT_SET(lgrp_info[i].info_children, j);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_rset =
14437c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_rsets +
14447c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 		for (j = 0; j < LGRP_RSRC_COUNT; j++) {
14477c478bd9Sstevel@tonic-gate 			ulong_t	*rset;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 			rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset +
14507c478bd9Sstevel@tonic-gate 			    (j * bitmask_size));
14517c478bd9Sstevel@tonic-gate 			for (k = 0; k < snap_nlgrpsmax; k++)
14527c478bd9Sstevel@tonic-gate 				if (klgrpset_ismember(lgrp->lgrp_set[j], k))
14537c478bd9Sstevel@tonic-gate 					BT_SET(rset, k);
14547c478bd9Sstevel@tonic-gate 		}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 		/*
14577c478bd9Sstevel@tonic-gate 		 * Fill in CPU IDs
14587c478bd9Sstevel@tonic-gate 		 */
14597c478bd9Sstevel@tonic-gate 		cpu_count = 0;
14607c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_cpuids = NULL;
14617c478bd9Sstevel@tonic-gate 		cp = head = lgrp->lgrp_cpu;
14627c478bd9Sstevel@tonic-gate 		if (head != NULL) {
14637c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index];
14647c478bd9Sstevel@tonic-gate 			do {
14657c478bd9Sstevel@tonic-gate 				lgrp_cpuids[cpu_index] = cp->cpu_id;
14667c478bd9Sstevel@tonic-gate 				cpu_index++;
14677c478bd9Sstevel@tonic-gate 				cpu_count++;
14687c478bd9Sstevel@tonic-gate 				cp = cp->cpu_next_lgrp;
14697c478bd9Sstevel@tonic-gate 			} while (cp != head);
14707c478bd9Sstevel@tonic-gate 		}
14717c478bd9Sstevel@tonic-gate 		ASSERT(cpu_count == lgrp->lgrp_cpucnt);
14727c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_ncpus = cpu_count;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 		/*
14757c478bd9Sstevel@tonic-gate 		 * Fill in memory sizes for lgroups that directly contain
14767c478bd9Sstevel@tonic-gate 		 * memory
14777c478bd9Sstevel@tonic-gate 		 */
14787c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) {
14797c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_free =
14807c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
14817c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_install =
14827c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL);
14837c478bd9Sstevel@tonic-gate 		}
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 		/*
14867c478bd9Sstevel@tonic-gate 		 * Fill in latency table and buffer
14877c478bd9Sstevel@tonic-gate 		 */
14887c478bd9Sstevel@tonic-gate 		lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax *
14897c478bd9Sstevel@tonic-gate 		    sizeof (int *) + i * snap_nlgrpsmax * sizeof (int));
14907c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
14917c478bd9Sstevel@tonic-gate 			lgrp_t	*to;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 			to = lgrp_table[j];
14947c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to))
14957c478bd9Sstevel@tonic-gate 				continue;
14967c478bd9Sstevel@tonic-gate 			lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id,
14977c478bd9Sstevel@tonic-gate 			    to->lgrp_id);
14987c478bd9Sstevel@tonic-gate 		}
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
15067c478bd9Sstevel@tonic-gate 	/*
15077c478bd9Sstevel@tonic-gate 	 * Check to see whether caller is 32-bit program and need to return
15087c478bd9Sstevel@tonic-gate 	 * size of 32-bit snapshot now that snapshot has been taken/updated.
15097c478bd9Sstevel@tonic-gate 	 * May not have been able to do this earlier if snapshot was out of
15107c478bd9Sstevel@tonic-gate 	 * date or didn't exist yet.
15117c478bd9Sstevel@tonic-gate 	 */
15127c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 		/*
15177c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
15187c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
15197c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
15207c478bd9Sstevel@tonic-gate 		 */
15217c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
15227c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
15237c478bd9Sstevel@tonic-gate 		info_size =
15247c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
15257c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
15267c478bd9Sstevel@tonic-gate 		cpuids_size =
15277c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
15287c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
15317c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) +
15327c478bd9Sstevel@tonic-gate 		    1) * bitmask_size;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 		/*
15367c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
15377c478bd9Sstevel@tonic-gate 		 */
15387c478bd9Sstevel@tonic-gate 		lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
15397c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
15427c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
15437c478bd9Sstevel@tonic-gate 		return (bufsize);
15447c478bd9Sstevel@tonic-gate 	}
15457c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	return (lgrp_snap->ss_size);
15487c478bd9Sstevel@tonic-gate }
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate  * Copy snapshot into given user buffer, fix up any pointers in buffer to point
15537c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, and return size of buffer
15547c478bd9Sstevel@tonic-gate  * needed to hold snapshot
15557c478bd9Sstevel@tonic-gate  */
15567c478bd9Sstevel@tonic-gate static int
lgrp_snapshot_copy(char * buf,size_t bufsize)15577c478bd9Sstevel@tonic-gate lgrp_snapshot_copy(char *buf, size_t bufsize)
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate 	size_t			bitmask_size;
15607c478bd9Sstevel@tonic-gate 	int			cpu_index;
15617c478bd9Sstevel@tonic-gate 	size_t			cpuids_size;
15627c478bd9Sstevel@tonic-gate 	int			i;
15637c478bd9Sstevel@tonic-gate 	size_t			info_size;
15647c478bd9Sstevel@tonic-gate 	lgrp_info_t		*lgrp_info;
15657c478bd9Sstevel@tonic-gate 	int			retval;
15667c478bd9Sstevel@tonic-gate 	size_t			snap_hdr_size;
15677c478bd9Sstevel@tonic-gate 	int			snap_ncpus;
15687c478bd9Sstevel@tonic-gate 	int			snap_nlgrpsmax;
15697c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header_t	*user_snap;
15707c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info;
15717c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info_buffer;
15727c478bd9Sstevel@tonic-gate 	processorid_t		*user_cpuids;
15737c478bd9Sstevel@tonic-gate 	ulong_t			*user_lgrpset;
15747c478bd9Sstevel@tonic-gate 	ulong_t			*user_parents;
15757c478bd9Sstevel@tonic-gate 	ulong_t			*user_children;
15767c478bd9Sstevel@tonic-gate 	int			**user_lats;
15777c478bd9Sstevel@tonic-gate 	int			**user_lats_buffer;
15787c478bd9Sstevel@tonic-gate 	ulong_t			*user_rsets;
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
15817c478bd9Sstevel@tonic-gate 		return (0);
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0)
15847c478bd9Sstevel@tonic-gate 		return (lgrp_snap->ss_size);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	/*
15877c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
15887c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
15897c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
15907c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
15917c478bd9Sstevel@tonic-gate 	 */
15927c478bd9Sstevel@tonic-gate 	if (bufsize < lgrp_snap->ss_size)
15937c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
15967c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	/*
15997c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
16007c478bd9Sstevel@tonic-gate 	 */
16017c478bd9Sstevel@tonic-gate 	kpreempt_disable();
16027c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
16037c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
16047c478bd9Sstevel@tonic-gate 		    i)) {
16057c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_snap->ss_lgrpset, i);
16067c478bd9Sstevel@tonic-gate 		}
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 	kpreempt_enable();
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/*
16117c478bd9Sstevel@tonic-gate 	 * Copy lgroup snapshot (snapshot header, lgroup info, and CPU IDs)
16127c478bd9Sstevel@tonic-gate 	 * into user buffer all at once
16137c478bd9Sstevel@tonic-gate 	 */
16147c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0)
16157c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	/*
16187c478bd9Sstevel@tonic-gate 	 * Round up sizes of lgroup snapshot header and info for alignment
16197c478bd9Sstevel@tonic-gate 	 */
16207c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
16217c478bd9Sstevel@tonic-gate 	    sizeof (void *));
16227c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
16237c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
16247c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
16257c478bd9Sstevel@tonic-gate 	    sizeof (ulong_t));
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	/*
16307c478bd9Sstevel@tonic-gate 	 * Calculate pointers into user buffer for lgroup snapshot header,
16317c478bd9Sstevel@tonic-gate 	 * info, and CPU IDs
16327c478bd9Sstevel@tonic-gate 	 */
16337c478bd9Sstevel@tonic-gate 	user_snap = (lgrp_snapshot_header_t *)buf;
16347c478bd9Sstevel@tonic-gate 	user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size);
16357c478bd9Sstevel@tonic-gate 	user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size);
16367c478bd9Sstevel@tonic-gate 	user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size);
16377c478bd9Sstevel@tonic-gate 	user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size);
16387c478bd9Sstevel@tonic-gate 	user_children = (ulong_t *)((uintptr_t)user_parents +
16397c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
16407c478bd9Sstevel@tonic-gate 	user_rsets = (ulong_t *)((uintptr_t)user_children +
16417c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
16427c478bd9Sstevel@tonic-gate 	user_lats = (int **)((uintptr_t)user_rsets +
16437c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size));
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	/*
16467c478bd9Sstevel@tonic-gate 	 * Copyout magic number (ie. pointer to beginning of buffer)
16477c478bd9Sstevel@tonic-gate 	 */
16487c478bd9Sstevel@tonic-gate 	if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0)
16497c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	/*
16527c478bd9Sstevel@tonic-gate 	 * Fix up pointers in user buffer to point into user buffer
16537c478bd9Sstevel@tonic-gate 	 * not kernel snapshot
16547c478bd9Sstevel@tonic-gate 	 */
16557c478bd9Sstevel@tonic-gate 	if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0)
16567c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	if (copyout(&user_cpuids, &user_snap->ss_cpuids,
16597c478bd9Sstevel@tonic-gate 	    sizeof (user_cpuids)) != 0)
16607c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	if (copyout(&user_lgrpset, &user_snap->ss_lgrpset,
16637c478bd9Sstevel@tonic-gate 	    sizeof (user_lgrpset)) != 0)
16647c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	if (copyout(&user_parents, &user_snap->ss_parents,
16677c478bd9Sstevel@tonic-gate 	    sizeof (user_parents)) != 0)
16687c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (copyout(&user_children, &user_snap->ss_children,
16717c478bd9Sstevel@tonic-gate 	    sizeof (user_children)) != 0)
16727c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	if (copyout(&user_rsets, &user_snap->ss_rsets,
16757c478bd9Sstevel@tonic-gate 	    sizeof (user_rsets)) != 0)
16767c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	if (copyout(&user_lats, &user_snap->ss_latencies,
16797c478bd9Sstevel@tonic-gate 	    sizeof (user_lats)) != 0)
16807c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/*
16837c478bd9Sstevel@tonic-gate 	 * Make copies of lgroup info and latency table, fix up pointers,
16847c478bd9Sstevel@tonic-gate 	 * and then copy them into user buffer
16857c478bd9Sstevel@tonic-gate 	 */
16867c478bd9Sstevel@tonic-gate 	user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP);
16877c478bd9Sstevel@tonic-gate 	if (user_info_buffer == NULL)
16887c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
16917c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
16927c478bd9Sstevel@tonic-gate 	if (user_lats_buffer == NULL) {
16937c478bd9Sstevel@tonic-gate 		kmem_free(user_info_buffer, info_size);
16947c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
16957c478bd9Sstevel@tonic-gate 	}
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
16987c478bd9Sstevel@tonic-gate 	bcopy(lgrp_info, user_info_buffer, info_size);
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	cpu_index = 0;
17017c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
17027c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 		/*
17057c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
17067c478bd9Sstevel@tonic-gate 		 */
17077c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_lgrpid == LGRP_NONE)
17087c478bd9Sstevel@tonic-gate 			continue;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 		/*
17117c478bd9Sstevel@tonic-gate 		 * Update free memory size since it changes frequently
17127c478bd9Sstevel@tonic-gate 		 * Only do so for lgroups directly containing memory
17137c478bd9Sstevel@tonic-gate 		 *
17147c478bd9Sstevel@tonic-gate 		 * NOTE: This must be done before changing the pointers to
17157c478bd9Sstevel@tonic-gate 		 *	 point into user space since we need to dereference
17167c478bd9Sstevel@tonic-gate 		 *	 lgroup resource set
17177c478bd9Sstevel@tonic-gate 		 */
17187c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
17197c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
17207c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i))
17217c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_mem_free =
17227c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 		/*
17257c478bd9Sstevel@tonic-gate 		 * Fix up pointers to parents, children, resources, and
17267c478bd9Sstevel@tonic-gate 		 * latencies
17277c478bd9Sstevel@tonic-gate 		 */
17287c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_parents =
17297c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_parents + (i * bitmask_size));
17307c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_children =
17317c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_children + (i * bitmask_size));
17327c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_rset =
17337c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_rsets +
17347c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
17357c478bd9Sstevel@tonic-gate 		user_lats_buffer[i] = (int *)((uintptr_t)user_lats +
17367c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax *
17377c478bd9Sstevel@tonic-gate 		    sizeof (int)));
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 		/*
17407c478bd9Sstevel@tonic-gate 		 * Fix up pointer to CPU IDs
17417c478bd9Sstevel@tonic-gate 		 */
17427c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_ncpus == 0) {
17437c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_cpuids = NULL;
17447c478bd9Sstevel@tonic-gate 			continue;
17457c478bd9Sstevel@tonic-gate 		}
17467c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index];
17477c478bd9Sstevel@tonic-gate 		cpu_index += user_info_buffer[i].info_ncpus;
17487c478bd9Sstevel@tonic-gate 	}
17497c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	/*
17527c478bd9Sstevel@tonic-gate 	 * Copy lgroup info and latency table with pointers fixed up to point
17537c478bd9Sstevel@tonic-gate 	 * into user buffer out to user buffer now
17547c478bd9Sstevel@tonic-gate 	 */
17557c478bd9Sstevel@tonic-gate 	retval = lgrp_snap->ss_size;
17567c478bd9Sstevel@tonic-gate 	if (copyout(user_info_buffer, user_info, info_size) != 0)
17577c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
17587c478bd9Sstevel@tonic-gate 	kmem_free(user_info_buffer, info_size);
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax *
17617c478bd9Sstevel@tonic-gate 	    sizeof (int *)) != 0)
17627c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
17637c478bd9Sstevel@tonic-gate 	kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *));
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	return (retval);
17667c478bd9Sstevel@tonic-gate }
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
17707c478bd9Sstevel@tonic-gate /*
17717c478bd9Sstevel@tonic-gate  * Make 32-bit copy of snapshot, fix up any pointers in buffer to point
17727c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, copy 32-bit snapshot into
17737c478bd9Sstevel@tonic-gate  * given user buffer, and return size of buffer needed to hold snapshot
17747c478bd9Sstevel@tonic-gate  */
17757c478bd9Sstevel@tonic-gate static int
lgrp_snapshot_copy32(caddr32_t buf,size32_t bufsize)17767c478bd9Sstevel@tonic-gate lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate 	size32_t			bitmask_size;
17797c478bd9Sstevel@tonic-gate 	size32_t			bitmasks_size;
17807c478bd9Sstevel@tonic-gate 	size32_t			children_size;
17817c478bd9Sstevel@tonic-gate 	int				cpu_index;
17827c478bd9Sstevel@tonic-gate 	size32_t			cpuids_size;
17837c478bd9Sstevel@tonic-gate 	int				i;
17847c478bd9Sstevel@tonic-gate 	int				j;
17857c478bd9Sstevel@tonic-gate 	size32_t			info_size;
17867c478bd9Sstevel@tonic-gate 	size32_t			lats_size;
17877c478bd9Sstevel@tonic-gate 	lgrp_info_t			*lgrp_info;
17887c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header32_t	*lgrp_snap32;
17897c478bd9Sstevel@tonic-gate 	lgrp_info32_t			*lgrp_info32;
17907c478bd9Sstevel@tonic-gate 	processorid_t			*lgrp_cpuids32;
17917c478bd9Sstevel@tonic-gate 	caddr32_t			*lgrp_lats32;
17927c478bd9Sstevel@tonic-gate 	int				**lgrp_lats32_kernel;
17937c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_set32;
17947c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_parents32;
17957c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_children32;
17967c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_rsets32;
17977c478bd9Sstevel@tonic-gate 	size32_t			parents_size;
17987c478bd9Sstevel@tonic-gate 	size32_t			rsets_size;
17997c478bd9Sstevel@tonic-gate 	size32_t			set_size;
18007c478bd9Sstevel@tonic-gate 	size32_t			snap_hdr_size;
18017c478bd9Sstevel@tonic-gate 	int				snap_ncpus;
18027c478bd9Sstevel@tonic-gate 	int				snap_nlgrpsmax;
18037c478bd9Sstevel@tonic-gate 	size32_t			snap_size;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
18067c478bd9Sstevel@tonic-gate 		return (0);
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
18097c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	/*
18127c478bd9Sstevel@tonic-gate 	 * Calculate size of buffer needed for 32-bit snapshot,
18137c478bd9Sstevel@tonic-gate 	 * rounding up size of each object to allow for alignment
18147c478bd9Sstevel@tonic-gate 	 * of next object in buffer.
18157c478bd9Sstevel@tonic-gate 	 */
18167c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
18177c478bd9Sstevel@tonic-gate 	    sizeof (caddr32_t));
18187c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
18197c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
18207c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
18217c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax);
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	set_size = bitmask_size;
18267c478bd9Sstevel@tonic-gate 	parents_size = snap_nlgrpsmax * bitmask_size;
18277c478bd9Sstevel@tonic-gate 	children_size = snap_nlgrpsmax * bitmask_size;
18287c478bd9Sstevel@tonic-gate 	rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax *
18297c478bd9Sstevel@tonic-gate 	    (int)bitmask_size, sizeof (caddr32_t));
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	bitmasks_size = set_size + parents_size + children_size + rsets_size;
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	/*
18347c478bd9Sstevel@tonic-gate 	 * Size of latency table and buffer
18357c478bd9Sstevel@tonic-gate 	 */
18367c478bd9Sstevel@tonic-gate 	lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
18377c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size +
18407c478bd9Sstevel@tonic-gate 		lats_size;
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0) {
18437c478bd9Sstevel@tonic-gate 		return (snap_size);
18447c478bd9Sstevel@tonic-gate 	}
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	/*
18477c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
18487c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
18497c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
18507c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
18517c478bd9Sstevel@tonic-gate 	 */
18527c478bd9Sstevel@tonic-gate 	if (bufsize < snap_size)
18537c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	/*
18567c478bd9Sstevel@tonic-gate 	 * Make 32-bit copy of snapshot, fix up pointers to point into user
18577c478bd9Sstevel@tonic-gate 	 * buffer not kernel, and then copy whole thing into user buffer
18587c478bd9Sstevel@tonic-gate 	 */
18597c478bd9Sstevel@tonic-gate 	lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP);
18607c478bd9Sstevel@tonic-gate 	if (lgrp_snap32 == NULL)
18617c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 	/*
18647c478bd9Sstevel@tonic-gate 	 * Calculate pointers into 32-bit copy of snapshot
18657c478bd9Sstevel@tonic-gate 	 * for lgroup info, CPU IDs, pset lgroup bitmask, parents, children,
18667c478bd9Sstevel@tonic-gate 	 * resources, and latency table and buffer
18677c478bd9Sstevel@tonic-gate 	 */
18687c478bd9Sstevel@tonic-gate 	lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 +
18697c478bd9Sstevel@tonic-gate 	    snap_hdr_size);
18707c478bd9Sstevel@tonic-gate 	lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size);
18717c478bd9Sstevel@tonic-gate 	lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size);
18727c478bd9Sstevel@tonic-gate 	lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size);
18737c478bd9Sstevel@tonic-gate 	lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size);
18747c478bd9Sstevel@tonic-gate 	lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size);
18757c478bd9Sstevel@tonic-gate 	lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	/*
18787c478bd9Sstevel@tonic-gate 	 * Make temporary lgroup latency table of pointers for kernel to use
18797c478bd9Sstevel@tonic-gate 	 * to fill in rows of table with latencies from each lgroup
18807c478bd9Sstevel@tonic-gate 	 */
18817c478bd9Sstevel@tonic-gate 	lgrp_lats32_kernel =  kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
18827c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
18837c478bd9Sstevel@tonic-gate 	if (lgrp_lats32_kernel == NULL) {
18847c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
18857c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	/*
18897c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit lgroup snapshot header
18907c478bd9Sstevel@tonic-gate 	 * (with pointers into user's buffer for lgroup info, CPU IDs,
18917c478bd9Sstevel@tonic-gate 	 * bit masks, and latencies)
18927c478bd9Sstevel@tonic-gate 	 */
18937c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_version = lgrp_snap->ss_version;
18947c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_levels = lgrp_snap->ss_levels;
18957c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os =
18967c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_nlgrps;
18977c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax;
18987c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_root = lgrp_snap->ss_root;
18997c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus;
19007c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_gen = lgrp_snap->ss_gen;
19017c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_view = LGRP_VIEW_OS;
19027c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_size = snap_size;
19037c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_magic = buf;
19047c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_info = buf + snap_hdr_size;
19057c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size;
19067c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size;
19077c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size;
19087c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_children = lgrp_snap32->ss_parents +
19097c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
19107c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_rsets = lgrp_snap32->ss_children +
19117c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
19127c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets +
19137c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	/*
19167c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
19177c478bd9Sstevel@tonic-gate 	 */
19187c478bd9Sstevel@tonic-gate 	kpreempt_disable();
19197c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
19207c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
19217c478bd9Sstevel@tonic-gate 		    i)) {
19227c478bd9Sstevel@tonic-gate 			BT_SET32(lgrp_set32, i);
19237c478bd9Sstevel@tonic-gate 		}
19247c478bd9Sstevel@tonic-gate 	}
19257c478bd9Sstevel@tonic-gate 	kpreempt_enable();
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	/*
19287c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit copy of lgroup info and fix up pointers
19297c478bd9Sstevel@tonic-gate 	 * to point into user's buffer instead of kernel's
19307c478bd9Sstevel@tonic-gate 	 */
19317c478bd9Sstevel@tonic-gate 	cpu_index = 0;
19327c478bd9Sstevel@tonic-gate 	lgrp_info = lgrp_snap->ss_info;
19337c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
19347c478bd9Sstevel@tonic-gate 		uint_t	*children;
19357c478bd9Sstevel@tonic-gate 		uint_t	*lgrp_rset;
19367c478bd9Sstevel@tonic-gate 		uint_t	*parents;
19377c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 		/*
19407c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
19417c478bd9Sstevel@tonic-gate 		 */
19427c478bd9Sstevel@tonic-gate 		if (lgrp_info[i].info_lgrpid == LGRP_NONE) {
19437c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info32[i], sizeof (lgrp_info32[i]));
19447c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_lgrpid = LGRP_NONE;
19457c478bd9Sstevel@tonic-gate 			continue;
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 		/*
19497c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, lgroup resource set, and
19507c478bd9Sstevel@tonic-gate 		 * latencies from snapshot
19517c478bd9Sstevel@tonic-gate 		 */
19527c478bd9Sstevel@tonic-gate 		parents = (uint_t *)((uintptr_t)lgrp_parents32 +
19537c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
19547c478bd9Sstevel@tonic-gate 		children = (uint_t *)((uintptr_t)lgrp_children32 +
19557c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
19567c478bd9Sstevel@tonic-gate 		snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets +
19577c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax)));
19587c478bd9Sstevel@tonic-gate 		lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 +
19597c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
19607c478bd9Sstevel@tonic-gate 		lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 +
19617c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19627c478bd9Sstevel@tonic-gate 		    sizeof (int));
19637c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
19647c478bd9Sstevel@tonic-gate 			int	k;
19657c478bd9Sstevel@tonic-gate 			uint_t	*rset;
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_parents[i], j))
19687c478bd9Sstevel@tonic-gate 				BT_SET32(parents, j);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_children[i], j))
19717c478bd9Sstevel@tonic-gate 				BT_SET32(children, j);
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 			for (k = 0; k < LGRP_RSRC_COUNT; k++) {
19747c478bd9Sstevel@tonic-gate 				rset = (uint_t *)((uintptr_t)lgrp_rset +
19757c478bd9Sstevel@tonic-gate 				    k * bitmask_size);
19767c478bd9Sstevel@tonic-gate 				if (BT_TEST(&snap_rset[k], j))
19777c478bd9Sstevel@tonic-gate 					BT_SET32(rset, j);
19787c478bd9Sstevel@tonic-gate 			}
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 			lgrp_lats32_kernel[i][j] =
19817c478bd9Sstevel@tonic-gate 			    lgrp_snap->ss_latencies[i][j];
19827c478bd9Sstevel@tonic-gate 		}
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 		/*
19857c478bd9Sstevel@tonic-gate 		 * Fix up pointer to latency buffer
19867c478bd9Sstevel@tonic-gate 		 */
19877c478bd9Sstevel@tonic-gate 		lgrp_lats32[i] = lgrp_snap32->ss_latencies +
19887c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19897c478bd9Sstevel@tonic-gate 		    sizeof (int);
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 		/*
19927c478bd9Sstevel@tonic-gate 		 * Fix up pointers for parents, children, and resources
19937c478bd9Sstevel@tonic-gate 		 */
19947c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_parents = lgrp_snap32->ss_parents +
19957c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
19967c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_children = lgrp_snap32->ss_children +
19977c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
19987c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets +
19997c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 		/*
20027c478bd9Sstevel@tonic-gate 		 * Fill in memory and CPU info
20037c478bd9Sstevel@tonic-gate 		 * Only fill in memory for lgroups directly containing memory
20047c478bd9Sstevel@tonic-gate 		 */
20057c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
20067c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
20077c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i)) {
20087c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_free = lgrp_mem_size(i,
20097c478bd9Sstevel@tonic-gate 			    LGRP_MEM_SIZE_FREE);
20107c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_install =
20117c478bd9Sstevel@tonic-gate 			    lgrp_info[i].info_mem_install;
20127c478bd9Sstevel@tonic-gate 		}
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid;
20177c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_latency = lgrp_info[i].info_latency;
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 		if (lgrp_info32[i].info_ncpus == 0) {
20207c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_cpuids = 0;
20217c478bd9Sstevel@tonic-gate 			continue;
20227c478bd9Sstevel@tonic-gate 		}
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 		/*
20257c478bd9Sstevel@tonic-gate 		 * Fix up pointer for CPU IDs
20267c478bd9Sstevel@tonic-gate 		 */
20277c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids +
20287c478bd9Sstevel@tonic-gate 		    (cpu_index * sizeof (processorid_t));
20297c478bd9Sstevel@tonic-gate 		cpu_index += lgrp_info32[i].info_ncpus;
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	/*
20347c478bd9Sstevel@tonic-gate 	 * Copy lgroup CPU IDs into 32-bit snapshot
20357c478bd9Sstevel@tonic-gate 	 * before copying it out into user's buffer
20367c478bd9Sstevel@tonic-gate 	 */
20377c478bd9Sstevel@tonic-gate 	bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size);
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 	/*
20407c478bd9Sstevel@tonic-gate 	 * Copy 32-bit lgroup snapshot into user's buffer all at once
20417c478bd9Sstevel@tonic-gate 	 */
20427c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) {
20437c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
20447c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20457c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
20467c478bd9Sstevel@tonic-gate 	}
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_snap32, snap_size);
20497c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	return (snap_size);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate int
lgrpsys(int subcode,long ia,void * ap)20577c478bd9Sstevel@tonic-gate lgrpsys(int subcode, long ia, void *ap)
20587c478bd9Sstevel@tonic-gate {
20597c478bd9Sstevel@tonic-gate 	size_t	bufsize;
20607c478bd9Sstevel@tonic-gate 	int	latency;
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	switch (subcode) {
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_GET:
20657c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_get((lgrp_affinity_args_t *)ap));
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_SET:
20687c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_set((lgrp_affinity_args_t *)ap));
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	case LGRP_SYS_GENERATION:
20717c478bd9Sstevel@tonic-gate 		return (lgrp_generation(ia));
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	case LGRP_SYS_HOME:
20747c478bd9Sstevel@tonic-gate 		return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap));
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	case LGRP_SYS_LATENCY:
20777c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
20787c478bd9Sstevel@tonic-gate 		latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap);
20797c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
20807c478bd9Sstevel@tonic-gate 		return (latency);
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	case LGRP_SYS_MEMINFO:
20837c478bd9Sstevel@tonic-gate 		return (meminfo(ia, (struct meminfo *)ap));
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	case LGRP_SYS_VERSION:
20867c478bd9Sstevel@tonic-gate 		return (lgrp_version(ia));
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 	case LGRP_SYS_SNAPSHOT:
20897c478bd9Sstevel@tonic-gate 		mutex_enter(&lgrp_snap_lock);
20907c478bd9Sstevel@tonic-gate 		bufsize = lgrp_snapshot();
20917c478bd9Sstevel@tonic-gate 		if (ap && ia > 0) {
20927c478bd9Sstevel@tonic-gate 			if (get_udatamodel() == DATAMODEL_NATIVE)
20937c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy(ap, ia);
20947c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
20957c478bd9Sstevel@tonic-gate 			else
20967c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy32(
20977c478bd9Sstevel@tonic-gate 				    (caddr32_t)(uintptr_t)ap, ia);
20987c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
20997c478bd9Sstevel@tonic-gate 		}
21007c478bd9Sstevel@tonic-gate 		mutex_exit(&lgrp_snap_lock);
21017c478bd9Sstevel@tonic-gate 		return (bufsize);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	default:
21047c478bd9Sstevel@tonic-gate 		break;
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	}
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	return (set_errno(EINVAL));
21097c478bd9Sstevel@tonic-gate }
2110