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