xref: /titanic_44/usr/src/uts/common/syscall/lgrpsys.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * lgroup system calls
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/lgrp.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/lgrp_user.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>		/* for prom_printf() */
42*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <vm/as.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /* definitions for mi_validity */
48*7c478bd9Sstevel@tonic-gate #define	VALID_ADDR	1
49*7c478bd9Sstevel@tonic-gate #define	VALID_REQ	2
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * run through the given number of addresses and requests and return the
53*7c478bd9Sstevel@tonic-gate  * corresponding memory information for each address
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate static int
56*7c478bd9Sstevel@tonic-gate meminfo(int addr_count, struct meminfo *mip)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	size_t		in_size, out_size, req_size, val_size;
59*7c478bd9Sstevel@tonic-gate 	struct as	*as;
60*7c478bd9Sstevel@tonic-gate 	struct hat	*hat;
61*7c478bd9Sstevel@tonic-gate 	int		i, j, out_idx, info_count;
62*7c478bd9Sstevel@tonic-gate 	lgrp_t		*lgrp;
63*7c478bd9Sstevel@tonic-gate 	pfn_t		pfn;
64*7c478bd9Sstevel@tonic-gate 	ssize_t		pgsz;
65*7c478bd9Sstevel@tonic-gate 	int		*req_array, *val_array;
66*7c478bd9Sstevel@tonic-gate 	uint64_t	*in_array, *out_array;
67*7c478bd9Sstevel@tonic-gate 	uint64_t	addr, paddr;
68*7c478bd9Sstevel@tonic-gate 	uintptr_t	vaddr;
69*7c478bd9Sstevel@tonic-gate 	int		ret = 0;
70*7c478bd9Sstevel@tonic-gate 	struct meminfo minfo;
71*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
72*7c478bd9Sstevel@tonic-gate 	struct meminfo32 minfo32;
73*7c478bd9Sstevel@tonic-gate #endif
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	/*
76*7c478bd9Sstevel@tonic-gate 	 * Make sure that there is at least one address to translate and
77*7c478bd9Sstevel@tonic-gate 	 * limit how many virtual addresses the kernel can do per call
78*7c478bd9Sstevel@tonic-gate 	 */
79*7c478bd9Sstevel@tonic-gate 	if (addr_count < 1)
80*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
81*7c478bd9Sstevel@tonic-gate 	else if (addr_count > MAX_MEMINFO_CNT)
82*7c478bd9Sstevel@tonic-gate 		addr_count = MAX_MEMINFO_CNT;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
85*7c478bd9Sstevel@tonic-gate 		if (copyin(mip, &minfo, sizeof (struct meminfo)))
86*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
87*7c478bd9Sstevel@tonic-gate 	}
88*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
89*7c478bd9Sstevel@tonic-gate 	else {
90*7c478bd9Sstevel@tonic-gate 		bzero(&minfo, sizeof (minfo));
91*7c478bd9Sstevel@tonic-gate 		if (copyin(mip, &minfo32, sizeof (struct meminfo32)))
92*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
93*7c478bd9Sstevel@tonic-gate 		minfo.mi_inaddr = (const uint64_t *)(uintptr_t)
94*7c478bd9Sstevel@tonic-gate 		    minfo32.mi_inaddr;
95*7c478bd9Sstevel@tonic-gate 		minfo.mi_info_req = (const uint_t *)(uintptr_t)
96*7c478bd9Sstevel@tonic-gate 		    minfo32.mi_info_req;
97*7c478bd9Sstevel@tonic-gate 		minfo.mi_info_count = minfo32.mi_info_count;
98*7c478bd9Sstevel@tonic-gate 		minfo.mi_outdata = (uint64_t *)(uintptr_t)
99*7c478bd9Sstevel@tonic-gate 		    minfo32.mi_outdata;
100*7c478bd9Sstevel@tonic-gate 		minfo.mi_validity = (uint_t *)(uintptr_t)
101*7c478bd9Sstevel@tonic-gate 		    minfo32.mi_validity;
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate #endif
104*7c478bd9Sstevel@tonic-gate 	/*
105*7c478bd9Sstevel@tonic-gate 	 * all the input parameters have been copied in:-
106*7c478bd9Sstevel@tonic-gate 	 * addr_count - number of input addresses
107*7c478bd9Sstevel@tonic-gate 	 * minfo.mi_inaddr - array of input addresses
108*7c478bd9Sstevel@tonic-gate 	 * minfo.mi_info_req - array of types of information requested
109*7c478bd9Sstevel@tonic-gate 	 * minfo.mi_info_count - no. of pieces of info requested for each addr
110*7c478bd9Sstevel@tonic-gate 	 * minfo.mi_outdata - array into which the results are placed
111*7c478bd9Sstevel@tonic-gate 	 * minfo.mi_validity -  array containing bitwise result codes; 0th bit
112*7c478bd9Sstevel@tonic-gate 	 *			evaluates validity of corresponding input
113*7c478bd9Sstevel@tonic-gate 	 *			address, 1st bit validity of response to first
114*7c478bd9Sstevel@tonic-gate 	 *			member of info_req, etc.
115*7c478bd9Sstevel@tonic-gate 	 */
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/* make sure mi_info_count is within limit */
118*7c478bd9Sstevel@tonic-gate 	info_count = minfo.mi_info_count;
119*7c478bd9Sstevel@tonic-gate 	if (info_count < 1 || info_count > MAX_MEMINFO_REQ)
120*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	/*
123*7c478bd9Sstevel@tonic-gate 	 * allocate buffer in_array for the input addresses and copy them in
124*7c478bd9Sstevel@tonic-gate 	 */
125*7c478bd9Sstevel@tonic-gate 	in_size = sizeof (uint64_t) * addr_count;
126*7c478bd9Sstevel@tonic-gate 	in_array = kmem_alloc(in_size, KM_SLEEP);
127*7c478bd9Sstevel@tonic-gate 	if (copyin(minfo.mi_inaddr, in_array, in_size)) {
128*7c478bd9Sstevel@tonic-gate 		kmem_free(in_array, in_size);
129*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	/*
133*7c478bd9Sstevel@tonic-gate 	 * allocate buffer req_array for the input info_reqs and copy them in
134*7c478bd9Sstevel@tonic-gate 	 */
135*7c478bd9Sstevel@tonic-gate 	req_size = sizeof (uint_t) * info_count;
136*7c478bd9Sstevel@tonic-gate 	req_array = kmem_alloc(req_size, KM_SLEEP);
137*7c478bd9Sstevel@tonic-gate 	if (copyin(minfo.mi_info_req, req_array, req_size)) {
138*7c478bd9Sstevel@tonic-gate 		kmem_free(req_array, req_size);
139*7c478bd9Sstevel@tonic-gate 		kmem_free(in_array, in_size);
140*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
141*7c478bd9Sstevel@tonic-gate 	}
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * allocate buffer out_array which holds the results and will have
145*7c478bd9Sstevel@tonic-gate 	 * to be copied out later
146*7c478bd9Sstevel@tonic-gate 	 */
147*7c478bd9Sstevel@tonic-gate 	out_size = sizeof (uint64_t) * addr_count * info_count;
148*7c478bd9Sstevel@tonic-gate 	out_array = kmem_alloc(out_size, KM_SLEEP);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	/*
151*7c478bd9Sstevel@tonic-gate 	 * allocate buffer val_array which holds the validity bits and will
152*7c478bd9Sstevel@tonic-gate 	 * have to be copied out later
153*7c478bd9Sstevel@tonic-gate 	 */
154*7c478bd9Sstevel@tonic-gate 	val_size = sizeof (uint_t) * addr_count;
155*7c478bd9Sstevel@tonic-gate 	val_array = kmem_alloc(val_size, KM_SLEEP);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if ((req_array[0] & MEMINFO_MASK) == MEMINFO_PLGRP) {
158*7c478bd9Sstevel@tonic-gate 		/* find the corresponding lgroup for each physical address */
159*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < addr_count; i++) {
160*7c478bd9Sstevel@tonic-gate 			paddr = in_array[i];
161*7c478bd9Sstevel@tonic-gate 			pfn = btop(paddr);
162*7c478bd9Sstevel@tonic-gate 			lgrp = lgrp_pfn_to_lgrp(pfn);
163*7c478bd9Sstevel@tonic-gate 			if (lgrp) {
164*7c478bd9Sstevel@tonic-gate 				out_array[i] = lgrp->lgrp_id;
165*7c478bd9Sstevel@tonic-gate 				val_array[i] = VALID_ADDR | VALID_REQ;
166*7c478bd9Sstevel@tonic-gate 			} else {
167*7c478bd9Sstevel@tonic-gate 				out_array[i] = NULL;
168*7c478bd9Sstevel@tonic-gate 				val_array[i] = 0;
169*7c478bd9Sstevel@tonic-gate 			}
170*7c478bd9Sstevel@tonic-gate 		}
171*7c478bd9Sstevel@tonic-gate 	} else {
172*7c478bd9Sstevel@tonic-gate 		/* get the corresponding memory info for each virtual address */
173*7c478bd9Sstevel@tonic-gate 		as = curproc->p_as;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
176*7c478bd9Sstevel@tonic-gate 		hat = as->a_hat;
177*7c478bd9Sstevel@tonic-gate 		for (i = out_idx = 0; i < addr_count; i++, out_idx +=
178*7c478bd9Sstevel@tonic-gate 		    info_count) {
179*7c478bd9Sstevel@tonic-gate 			addr = in_array[i];
180*7c478bd9Sstevel@tonic-gate 			vaddr = (uintptr_t)(addr & ~PAGEOFFSET);
181*7c478bd9Sstevel@tonic-gate 			if (!as_segat(as, (caddr_t)vaddr)) {
182*7c478bd9Sstevel@tonic-gate 				val_array[i] = 0;
183*7c478bd9Sstevel@tonic-gate 				continue;
184*7c478bd9Sstevel@tonic-gate 			}
185*7c478bd9Sstevel@tonic-gate 			val_array[i] = VALID_ADDR;
186*7c478bd9Sstevel@tonic-gate 			pfn = hat_getpfnum(hat, (caddr_t)vaddr);
187*7c478bd9Sstevel@tonic-gate 			if (pfn != PFN_INVALID) {
188*7c478bd9Sstevel@tonic-gate 				paddr = (uint64_t)((pfn << PAGESHIFT) |
189*7c478bd9Sstevel@tonic-gate 					(addr & PAGEOFFSET));
190*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < info_count; j++) {
191*7c478bd9Sstevel@tonic-gate 					switch (req_array[j] & MEMINFO_MASK) {
192*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VPHYSICAL:
193*7c478bd9Sstevel@tonic-gate 						/*
194*7c478bd9Sstevel@tonic-gate 						 * return the physical address
195*7c478bd9Sstevel@tonic-gate 						 * corresponding to the input
196*7c478bd9Sstevel@tonic-gate 						 * virtual address
197*7c478bd9Sstevel@tonic-gate 						 */
198*7c478bd9Sstevel@tonic-gate 						out_array[out_idx + j] = paddr;
199*7c478bd9Sstevel@tonic-gate 						val_array[i] |= VALID_REQ << j;
200*7c478bd9Sstevel@tonic-gate 						break;
201*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VLGRP:
202*7c478bd9Sstevel@tonic-gate 						/*
203*7c478bd9Sstevel@tonic-gate 						 * return the lgroup of physical
204*7c478bd9Sstevel@tonic-gate 						 * page corresponding to the
205*7c478bd9Sstevel@tonic-gate 						 * input virtual address
206*7c478bd9Sstevel@tonic-gate 						 */
207*7c478bd9Sstevel@tonic-gate 						lgrp = lgrp_pfn_to_lgrp(pfn);
208*7c478bd9Sstevel@tonic-gate 						if (lgrp) {
209*7c478bd9Sstevel@tonic-gate 							out_array[out_idx + j] =
210*7c478bd9Sstevel@tonic-gate 								lgrp->lgrp_id;
211*7c478bd9Sstevel@tonic-gate 							val_array[i] |=
212*7c478bd9Sstevel@tonic-gate 								VALID_REQ << j;
213*7c478bd9Sstevel@tonic-gate 						}
214*7c478bd9Sstevel@tonic-gate 						break;
215*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VPAGESIZE:
216*7c478bd9Sstevel@tonic-gate 						/*
217*7c478bd9Sstevel@tonic-gate 						 * return the size of physical
218*7c478bd9Sstevel@tonic-gate 						 * page corresponding to the
219*7c478bd9Sstevel@tonic-gate 						 * input virtual address
220*7c478bd9Sstevel@tonic-gate 						 */
221*7c478bd9Sstevel@tonic-gate 						pgsz = hat_getpagesize(hat,
222*7c478bd9Sstevel@tonic-gate 							(caddr_t)vaddr);
223*7c478bd9Sstevel@tonic-gate 						if (pgsz != -1) {
224*7c478bd9Sstevel@tonic-gate 							out_array[out_idx + j] =
225*7c478bd9Sstevel@tonic-gate 									pgsz;
226*7c478bd9Sstevel@tonic-gate 							val_array[i] |=
227*7c478bd9Sstevel@tonic-gate 								VALID_REQ << j;
228*7c478bd9Sstevel@tonic-gate 						}
229*7c478bd9Sstevel@tonic-gate 						break;
230*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPLCNT:
231*7c478bd9Sstevel@tonic-gate 						/*
232*7c478bd9Sstevel@tonic-gate 						 * for future use:-
233*7c478bd9Sstevel@tonic-gate 						 * return the no. replicated
234*7c478bd9Sstevel@tonic-gate 						 * physical pages corresponding
235*7c478bd9Sstevel@tonic-gate 						 * to the input virtual address,
236*7c478bd9Sstevel@tonic-gate 						 * so it is always 0 at the
237*7c478bd9Sstevel@tonic-gate 						 * moment
238*7c478bd9Sstevel@tonic-gate 						 */
239*7c478bd9Sstevel@tonic-gate 						out_array[out_idx + j] = 0;
240*7c478bd9Sstevel@tonic-gate 						val_array[i] |= VALID_REQ << j;
241*7c478bd9Sstevel@tonic-gate 						break;
242*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPL:
243*7c478bd9Sstevel@tonic-gate 						/*
244*7c478bd9Sstevel@tonic-gate 						 * for future use:-
245*7c478bd9Sstevel@tonic-gate 						 * return the nth physical
246*7c478bd9Sstevel@tonic-gate 						 * replica of the specified
247*7c478bd9Sstevel@tonic-gate 						 * virtual address
248*7c478bd9Sstevel@tonic-gate 						 */
249*7c478bd9Sstevel@tonic-gate 						break;
250*7c478bd9Sstevel@tonic-gate 					case MEMINFO_VREPL_LGRP:
251*7c478bd9Sstevel@tonic-gate 						/*
252*7c478bd9Sstevel@tonic-gate 						 * for future use:-
253*7c478bd9Sstevel@tonic-gate 						 * return the lgroup of nth
254*7c478bd9Sstevel@tonic-gate 						 * physical replica of the
255*7c478bd9Sstevel@tonic-gate 						 * specified virtual address
256*7c478bd9Sstevel@tonic-gate 						 */
257*7c478bd9Sstevel@tonic-gate 						break;
258*7c478bd9Sstevel@tonic-gate 					case MEMINFO_PLGRP:
259*7c478bd9Sstevel@tonic-gate 						/*
260*7c478bd9Sstevel@tonic-gate 						 * this is for physical address
261*7c478bd9Sstevel@tonic-gate 						 * only, shouldn't mix with
262*7c478bd9Sstevel@tonic-gate 						 * virtual address
263*7c478bd9Sstevel@tonic-gate 						 */
264*7c478bd9Sstevel@tonic-gate 						break;
265*7c478bd9Sstevel@tonic-gate 					default:
266*7c478bd9Sstevel@tonic-gate 						break;
267*7c478bd9Sstevel@tonic-gate 					}
268*7c478bd9Sstevel@tonic-gate 				}
269*7c478bd9Sstevel@tonic-gate 			}
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	/* copy out the results and validity bits and free the buffers */
275*7c478bd9Sstevel@tonic-gate 	if ((copyout(out_array, minfo.mi_outdata, out_size) != 0) ||
276*7c478bd9Sstevel@tonic-gate 		(copyout(val_array, minfo.mi_validity, val_size) != 0))
277*7c478bd9Sstevel@tonic-gate 		ret = set_errno(EFAULT);
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	kmem_free(in_array, in_size);
280*7c478bd9Sstevel@tonic-gate 	kmem_free(out_array, out_size);
281*7c478bd9Sstevel@tonic-gate 	kmem_free(req_array, req_size);
282*7c478bd9Sstevel@tonic-gate 	kmem_free(val_array, val_size);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	return (ret);
285*7c478bd9Sstevel@tonic-gate }
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Initialize lgroup affinities for thread
290*7c478bd9Sstevel@tonic-gate  */
291*7c478bd9Sstevel@tonic-gate void
292*7c478bd9Sstevel@tonic-gate lgrp_affinity_init(lgrp_affinity_t **bufaddr)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	if (bufaddr)
295*7c478bd9Sstevel@tonic-gate 		*bufaddr = NULL;
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate /*
300*7c478bd9Sstevel@tonic-gate  * Free lgroup affinities for thread and set to NULL
301*7c478bd9Sstevel@tonic-gate  * just in case thread gets recycled
302*7c478bd9Sstevel@tonic-gate  */
303*7c478bd9Sstevel@tonic-gate void
304*7c478bd9Sstevel@tonic-gate lgrp_affinity_free(lgrp_affinity_t **bufaddr)
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	if (bufaddr && *bufaddr) {
307*7c478bd9Sstevel@tonic-gate 		kmem_free(*bufaddr, nlgrpsmax * sizeof (lgrp_affinity_t));
308*7c478bd9Sstevel@tonic-gate 		*bufaddr = NULL;
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate #define	P_ANY	-2	/* cookie specifying any ID */
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate /*
317*7c478bd9Sstevel@tonic-gate  * Find LWP with given ID in specified process and get its affinity for
318*7c478bd9Sstevel@tonic-gate  * specified lgroup
319*7c478bd9Sstevel@tonic-gate  */
320*7c478bd9Sstevel@tonic-gate lgrp_affinity_t
321*7c478bd9Sstevel@tonic-gate lgrp_affinity_get_thread(proc_t *p, id_t lwpid, lgrp_id_t lgrp)
322*7c478bd9Sstevel@tonic-gate {
323*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t aff;
324*7c478bd9Sstevel@tonic-gate 	int		found;
325*7c478bd9Sstevel@tonic-gate 	kthread_t	*t;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	aff = LGRP_AFF_NONE;
330*7c478bd9Sstevel@tonic-gate 	found = 0;
331*7c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
332*7c478bd9Sstevel@tonic-gate 	/*
333*7c478bd9Sstevel@tonic-gate 	 * The process may be executing in proc_exit() and its p->p_list may be
334*7c478bd9Sstevel@tonic-gate 	 * already NULL.
335*7c478bd9Sstevel@tonic-gate 	 */
336*7c478bd9Sstevel@tonic-gate 	if (t == NULL)
337*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	do {
340*7c478bd9Sstevel@tonic-gate 		if (t->t_tid == lwpid || lwpid == P_ANY) {
341*7c478bd9Sstevel@tonic-gate 			thread_lock(t);
342*7c478bd9Sstevel@tonic-gate 			/*
343*7c478bd9Sstevel@tonic-gate 			 * Check to see whether caller has permission to set
344*7c478bd9Sstevel@tonic-gate 			 * affinity for LWP
345*7c478bd9Sstevel@tonic-gate 			 */
346*7c478bd9Sstevel@tonic-gate 			if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
347*7c478bd9Sstevel@tonic-gate 				thread_unlock(t);
348*7c478bd9Sstevel@tonic-gate 				return (set_errno(EPERM));
349*7c478bd9Sstevel@tonic-gate 			}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 			if (t->t_lgrp_affinity)
352*7c478bd9Sstevel@tonic-gate 				aff = t->t_lgrp_affinity[lgrp];
353*7c478bd9Sstevel@tonic-gate 			thread_unlock(t);
354*7c478bd9Sstevel@tonic-gate 			found = 1;
355*7c478bd9Sstevel@tonic-gate 			break;
356*7c478bd9Sstevel@tonic-gate 		}
357*7c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != p->p_tlist);
358*7c478bd9Sstevel@tonic-gate 	if (!found)
359*7c478bd9Sstevel@tonic-gate 		aff = set_errno(ESRCH);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	return (aff);
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate /*
366*7c478bd9Sstevel@tonic-gate  * Get lgroup affinity for given LWP
367*7c478bd9Sstevel@tonic-gate  */
368*7c478bd9Sstevel@tonic-gate lgrp_affinity_t
369*7c478bd9Sstevel@tonic-gate lgrp_affinity_get(lgrp_affinity_args_t *ap)
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		aff;
372*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_args_t	args;
373*7c478bd9Sstevel@tonic-gate 	id_t			id;
374*7c478bd9Sstevel@tonic-gate 	idtype_t		idtype;
375*7c478bd9Sstevel@tonic-gate 	lgrp_id_t		lgrp;
376*7c478bd9Sstevel@tonic-gate 	proc_t			*p;
377*7c478bd9Sstevel@tonic-gate 	kthread_t		*t;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/*
380*7c478bd9Sstevel@tonic-gate 	 * Copyin arguments
381*7c478bd9Sstevel@tonic-gate 	 */
382*7c478bd9Sstevel@tonic-gate 	if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
383*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	id = args.id;
386*7c478bd9Sstevel@tonic-gate 	idtype = args.idtype;
387*7c478bd9Sstevel@tonic-gate 	lgrp = args.lgrp;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	/*
390*7c478bd9Sstevel@tonic-gate 	 * Check for invalid lgroup
391*7c478bd9Sstevel@tonic-gate 	 */
392*7c478bd9Sstevel@tonic-gate 	if (lgrp < 0 || lgrp == LGRP_NONE)
393*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	/*
396*7c478bd9Sstevel@tonic-gate 	 * Check for existing lgroup
397*7c478bd9Sstevel@tonic-gate 	 */
398*7c478bd9Sstevel@tonic-gate 	if (lgrp > lgrp_alloc_max)
399*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	/*
402*7c478bd9Sstevel@tonic-gate 	 * Get lgroup affinity for given LWP or process
403*7c478bd9Sstevel@tonic-gate 	 */
404*7c478bd9Sstevel@tonic-gate 	switch (idtype) {
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	case P_LWPID:
407*7c478bd9Sstevel@tonic-gate 		/*
408*7c478bd9Sstevel@tonic-gate 		 * LWP in current process
409*7c478bd9Sstevel@tonic-gate 		 */
410*7c478bd9Sstevel@tonic-gate 		p = curproc;
411*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
412*7c478bd9Sstevel@tonic-gate 		if (id != P_MYID)	/* different thread */
413*7c478bd9Sstevel@tonic-gate 			aff = lgrp_affinity_get_thread(p, id, lgrp);
414*7c478bd9Sstevel@tonic-gate 		else {			/* current thread */
415*7c478bd9Sstevel@tonic-gate 			aff = LGRP_AFF_NONE;
416*7c478bd9Sstevel@tonic-gate 			t = curthread;
417*7c478bd9Sstevel@tonic-gate 			thread_lock(t);
418*7c478bd9Sstevel@tonic-gate 			if (t->t_lgrp_affinity)
419*7c478bd9Sstevel@tonic-gate 				aff = t->t_lgrp_affinity[lgrp];
420*7c478bd9Sstevel@tonic-gate 			thread_unlock(t);
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
423*7c478bd9Sstevel@tonic-gate 		break;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	case P_PID:
426*7c478bd9Sstevel@tonic-gate 		/*
427*7c478bd9Sstevel@tonic-gate 		 * Process
428*7c478bd9Sstevel@tonic-gate 		 */
429*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 		if (id == P_MYID)
432*7c478bd9Sstevel@tonic-gate 			p = curproc;
433*7c478bd9Sstevel@tonic-gate 		else {
434*7c478bd9Sstevel@tonic-gate 			p = prfind(id);
435*7c478bd9Sstevel@tonic-gate 			if (p == NULL) {
436*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
437*7c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
438*7c478bd9Sstevel@tonic-gate 			}
439*7c478bd9Sstevel@tonic-gate 		}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
442*7c478bd9Sstevel@tonic-gate 		aff = lgrp_affinity_get_thread(p, P_ANY, lgrp);
443*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
446*7c478bd9Sstevel@tonic-gate 		break;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	default:
449*7c478bd9Sstevel@tonic-gate 		aff = set_errno(EINVAL);
450*7c478bd9Sstevel@tonic-gate 		break;
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	return (aff);
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Find lgroup for which this thread has most affinity in specified partition
459*7c478bd9Sstevel@tonic-gate  */
460*7c478bd9Sstevel@tonic-gate lpl_t *
461*7c478bd9Sstevel@tonic-gate lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start)
462*7c478bd9Sstevel@tonic-gate {
463*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*affs;
464*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	best_aff;
465*7c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
466*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
467*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	lgrpid;
468*7c478bd9Sstevel@tonic-gate 	lpl_t		*lpl;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
471*7c478bd9Sstevel@tonic-gate 	ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) ||
472*7c478bd9Sstevel@tonic-gate 	    (MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t)));
473*7c478bd9Sstevel@tonic-gate 	ASSERT(cpupart != NULL);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL)
476*7c478bd9Sstevel@tonic-gate 		return (NULL);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	affs = t->t_lgrp_affinity;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	/*
481*7c478bd9Sstevel@tonic-gate 	 * Thread bound to CPU
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 	if (t->t_bind_cpu != PBIND_NONE) {
484*7c478bd9Sstevel@tonic-gate 		cpu_t	*cp;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 		/*
487*7c478bd9Sstevel@tonic-gate 		 * See whether thread has more affinity for root lgroup
488*7c478bd9Sstevel@tonic-gate 		 * than lgroup containing CPU
489*7c478bd9Sstevel@tonic-gate 		 */
490*7c478bd9Sstevel@tonic-gate 		cp = cpu[t->t_bind_cpu];
491*7c478bd9Sstevel@tonic-gate 		lpl = cp->cpu_lpl;
492*7c478bd9Sstevel@tonic-gate 		lgrpid = LGRP_ROOTID;
493*7c478bd9Sstevel@tonic-gate 		if (affs[lgrpid] > affs[lpl->lpl_lgrpid])
494*7c478bd9Sstevel@tonic-gate 			return (&cpupart->cp_lgrploads[lgrpid]);
495*7c478bd9Sstevel@tonic-gate 		return (lpl);
496*7c478bd9Sstevel@tonic-gate 	}
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	/*
499*7c478bd9Sstevel@tonic-gate 	 * Start searching at given lgroup
500*7c478bd9Sstevel@tonic-gate 	 */
501*7c478bd9Sstevel@tonic-gate 	ASSERT(start >= 0 && start <= lgrp_alloc_max);
502*7c478bd9Sstevel@tonic-gate 	lgrpid = start;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	/*
505*7c478bd9Sstevel@tonic-gate 	 * Begin with home as best lgroup if it's root or in this pset
506*7c478bd9Sstevel@tonic-gate 	 * Otherwise, use starting lgroup given above as best first.
507*7c478bd9Sstevel@tonic-gate 	 */
508*7c478bd9Sstevel@tonic-gate 	home = t->t_lpl->lpl_lgrpid;
509*7c478bd9Sstevel@tonic-gate 	if (LGRP_CPUS_IN_PART(home, cpupart))
510*7c478bd9Sstevel@tonic-gate 		best_lpl = &cpupart->cp_lgrploads[home];
511*7c478bd9Sstevel@tonic-gate 	else
512*7c478bd9Sstevel@tonic-gate 		best_lpl = &cpupart->cp_lgrploads[lgrpid];
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	best_aff = affs[best_lpl->lpl_lgrpid];
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	do {
517*7c478bd9Sstevel@tonic-gate 		/*
518*7c478bd9Sstevel@tonic-gate 		 * Skip any lgroups that don't have CPU resources
519*7c478bd9Sstevel@tonic-gate 		 * in this processor set.
520*7c478bd9Sstevel@tonic-gate 		 */
521*7c478bd9Sstevel@tonic-gate 		if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) {
522*7c478bd9Sstevel@tonic-gate 			if (++lgrpid > lgrp_alloc_max)
523*7c478bd9Sstevel@tonic-gate 				lgrpid = 0;	/* wrap the search */
524*7c478bd9Sstevel@tonic-gate 			continue;
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 		/*
528*7c478bd9Sstevel@tonic-gate 		 * Find lgroup with most affinity
529*7c478bd9Sstevel@tonic-gate 		 */
530*7c478bd9Sstevel@tonic-gate 		lpl = &cpupart->cp_lgrploads[lgrpid];
531*7c478bd9Sstevel@tonic-gate 		if (affs[lgrpid] > best_aff) {
532*7c478bd9Sstevel@tonic-gate 			best_aff =  affs[lgrpid];
533*7c478bd9Sstevel@tonic-gate 			best_lpl = lpl;
534*7c478bd9Sstevel@tonic-gate 		}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 		if (++lgrpid > lgrp_alloc_max)
537*7c478bd9Sstevel@tonic-gate 			lgrpid = 0;	/* wrap the search */
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	} while (lgrpid != start);
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	/*
542*7c478bd9Sstevel@tonic-gate 	 * No lgroup (in this pset) with any affinity
543*7c478bd9Sstevel@tonic-gate 	 */
544*7c478bd9Sstevel@tonic-gate 	if (best_aff == LGRP_AFF_NONE)
545*7c478bd9Sstevel@tonic-gate 		return (NULL);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	lgrpid = best_lpl->lpl_lgrpid;
548*7c478bd9Sstevel@tonic-gate 	ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0);
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	return (best_lpl);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate /*
555*7c478bd9Sstevel@tonic-gate  * Set thread's affinity for given lgroup
556*7c478bd9Sstevel@tonic-gate  */
557*7c478bd9Sstevel@tonic-gate int
558*7c478bd9Sstevel@tonic-gate lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff,
559*7c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf)
560*7c478bd9Sstevel@tonic-gate {
561*7c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
562*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
563*7c478bd9Sstevel@tonic-gate 	int		retval;
564*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	start;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
567*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	retval = 0;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	thread_lock(t);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	/*
574*7c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
575*7c478bd9Sstevel@tonic-gate 	 * thread
576*7c478bd9Sstevel@tonic-gate 	 */
577*7c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
578*7c478bd9Sstevel@tonic-gate 		thread_unlock(t);
579*7c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL) {
583*7c478bd9Sstevel@tonic-gate 		if (aff == LGRP_AFF_NONE) {
584*7c478bd9Sstevel@tonic-gate 			thread_unlock(t);
585*7c478bd9Sstevel@tonic-gate 			return (0);
586*7c478bd9Sstevel@tonic-gate 		}
587*7c478bd9Sstevel@tonic-gate 		ASSERT(aff_buf != NULL && *aff_buf != NULL);
588*7c478bd9Sstevel@tonic-gate 		t->t_lgrp_affinity = *aff_buf;
589*7c478bd9Sstevel@tonic-gate 		*aff_buf = NULL;
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	t->t_lgrp_affinity[lgrp] = aff;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	/*
595*7c478bd9Sstevel@tonic-gate 	 * Select a new home if the thread's affinity is being cleared
596*7c478bd9Sstevel@tonic-gate 	 */
597*7c478bd9Sstevel@tonic-gate 	if (aff == LGRP_AFF_NONE) {
598*7c478bd9Sstevel@tonic-gate 		lgrp_move_thread(t, lgrp_choose(t, t->t_cpupart), 1);
599*7c478bd9Sstevel@tonic-gate 		thread_unlock(t);
600*7c478bd9Sstevel@tonic-gate 		return (retval);
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	/*
604*7c478bd9Sstevel@tonic-gate 	 * Find lgroup for which thread has most affinity,
605*7c478bd9Sstevel@tonic-gate 	 * starting after home
606*7c478bd9Sstevel@tonic-gate 	 */
607*7c478bd9Sstevel@tonic-gate 	home = t->t_lpl->lpl_lgrpid;
608*7c478bd9Sstevel@tonic-gate 	start = home + 1;
609*7c478bd9Sstevel@tonic-gate 	if (start > lgrp_alloc_max)
610*7c478bd9Sstevel@tonic-gate 		start = 0;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	best_lpl = lgrp_affinity_best(t, t->t_cpupart, start);
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	/*
615*7c478bd9Sstevel@tonic-gate 	 * Rehome if found lgroup with more affinity than home
616*7c478bd9Sstevel@tonic-gate 	 */
617*7c478bd9Sstevel@tonic-gate 	if (best_lpl != NULL && best_lpl != t->t_lpl)
618*7c478bd9Sstevel@tonic-gate 		lgrp_move_thread(t, best_lpl, 1);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	thread_unlock(t);
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	return (retval);
623*7c478bd9Sstevel@tonic-gate }
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate /*
627*7c478bd9Sstevel@tonic-gate  * Set process' affinity for specified lgroup
628*7c478bd9Sstevel@tonic-gate  */
629*7c478bd9Sstevel@tonic-gate int
630*7c478bd9Sstevel@tonic-gate lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff,
631*7c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf_array)
632*7c478bd9Sstevel@tonic-gate {
633*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*buf;
634*7c478bd9Sstevel@tonic-gate 	int		err = 0;
635*7c478bd9Sstevel@tonic-gate 	int		i;
636*7c478bd9Sstevel@tonic-gate 	int		retval;
637*7c478bd9Sstevel@tonic-gate 	kthread_t	*t;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock));
640*7c478bd9Sstevel@tonic-gate 	ASSERT(aff_buf_array != NULL);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	i = 0;
643*7c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
644*7c478bd9Sstevel@tonic-gate 	if (t != NULL) {
645*7c478bd9Sstevel@tonic-gate 		do {
646*7c478bd9Sstevel@tonic-gate 			/*
647*7c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for thread
648*7c478bd9Sstevel@tonic-gate 			 */
649*7c478bd9Sstevel@tonic-gate 			buf = aff_buf_array[i];
650*7c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf);
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 			if (err == 0 && retval != 0)
653*7c478bd9Sstevel@tonic-gate 				err = retval;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 			/*
656*7c478bd9Sstevel@tonic-gate 			 * Advance pointer to next buffer
657*7c478bd9Sstevel@tonic-gate 			 */
658*7c478bd9Sstevel@tonic-gate 			if (buf == NULL) {
659*7c478bd9Sstevel@tonic-gate 				ASSERT(i < p->p_lwpcnt);
660*7c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = NULL;
661*7c478bd9Sstevel@tonic-gate 				i++;
662*7c478bd9Sstevel@tonic-gate 			}
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
665*7c478bd9Sstevel@tonic-gate 	}
666*7c478bd9Sstevel@tonic-gate 	return (err);
667*7c478bd9Sstevel@tonic-gate }
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate /*
671*7c478bd9Sstevel@tonic-gate  * Set LWP's or process' affinity for specified lgroup
672*7c478bd9Sstevel@tonic-gate  *
673*7c478bd9Sstevel@tonic-gate  * When setting affinities, pidlock, process p_lock, and thread_lock()
674*7c478bd9Sstevel@tonic-gate  * need to be held in that order to protect target thread's pset, process,
675*7c478bd9Sstevel@tonic-gate  * process contents, and thread contents.  thread_lock() does splhigh(),
676*7c478bd9Sstevel@tonic-gate  * so it ends up having similiar effect as kpreempt_disable(), so it will
677*7c478bd9Sstevel@tonic-gate  * protect calls to lgrp_move_thread() and lgrp_choose() from pset changes.
678*7c478bd9Sstevel@tonic-gate  */
679*7c478bd9Sstevel@tonic-gate int
680*7c478bd9Sstevel@tonic-gate lgrp_affinity_set(lgrp_affinity_args_t *ap)
681*7c478bd9Sstevel@tonic-gate {
682*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		aff;
683*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		*aff_buf;
684*7c478bd9Sstevel@tonic-gate 	lgrp_affinity_args_t	args;
685*7c478bd9Sstevel@tonic-gate 	id_t			id;
686*7c478bd9Sstevel@tonic-gate 	idtype_t		idtype;
687*7c478bd9Sstevel@tonic-gate 	lgrp_id_t		lgrp;
688*7c478bd9Sstevel@tonic-gate 	int			nthreads;
689*7c478bd9Sstevel@tonic-gate 	proc_t			*p;
690*7c478bd9Sstevel@tonic-gate 	int			retval;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	/*
693*7c478bd9Sstevel@tonic-gate 	 * Copyin arguments
694*7c478bd9Sstevel@tonic-gate 	 */
695*7c478bd9Sstevel@tonic-gate 	if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
696*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	idtype = args.idtype;
699*7c478bd9Sstevel@tonic-gate 	id = args.id;
700*7c478bd9Sstevel@tonic-gate 	lgrp = args.lgrp;
701*7c478bd9Sstevel@tonic-gate 	aff = args.aff;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	/*
704*7c478bd9Sstevel@tonic-gate 	 * Check for invalid lgroup
705*7c478bd9Sstevel@tonic-gate 	 */
706*7c478bd9Sstevel@tonic-gate 	if (lgrp < 0 || lgrp == LGRP_NONE)
707*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	/*
710*7c478bd9Sstevel@tonic-gate 	 * Check for existing lgroup
711*7c478bd9Sstevel@tonic-gate 	 */
712*7c478bd9Sstevel@tonic-gate 	if (lgrp > lgrp_alloc_max)
713*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	/*
716*7c478bd9Sstevel@tonic-gate 	 * Check for legal affinity
717*7c478bd9Sstevel@tonic-gate 	 */
718*7c478bd9Sstevel@tonic-gate 	if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK &&
719*7c478bd9Sstevel@tonic-gate 	    aff != LGRP_AFF_STRONG)
720*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	/*
723*7c478bd9Sstevel@tonic-gate 	 * Must be process or LWP ID
724*7c478bd9Sstevel@tonic-gate 	 */
725*7c478bd9Sstevel@tonic-gate 	if (idtype != P_LWPID && idtype != P_PID)
726*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	/*
729*7c478bd9Sstevel@tonic-gate 	 * Set given LWP's or process' affinity for specified lgroup
730*7c478bd9Sstevel@tonic-gate 	 */
731*7c478bd9Sstevel@tonic-gate 	switch (idtype) {
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	case P_LWPID:
734*7c478bd9Sstevel@tonic-gate 		/*
735*7c478bd9Sstevel@tonic-gate 		 * Allocate memory for thread's lgroup affinities
736*7c478bd9Sstevel@tonic-gate 		 * ahead of time w/o holding locks
737*7c478bd9Sstevel@tonic-gate 		 */
738*7c478bd9Sstevel@tonic-gate 		aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t),
739*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		p = curproc;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 		/*
744*7c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
745*7c478bd9Sstevel@tonic-gate 		 */
746*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
747*7c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
748*7c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(curthread, lgrp, aff,
749*7c478bd9Sstevel@tonic-gate 			    &aff_buf);
750*7c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
751*7c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
752*7c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
753*7c478bd9Sstevel@tonic-gate 			int		found = 0;
754*7c478bd9Sstevel@tonic-gate 			kthread_t	*t;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
757*7c478bd9Sstevel@tonic-gate 			do {
758*7c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
759*7c478bd9Sstevel@tonic-gate 					retval = lgrp_affinity_set_thread(t,
760*7c478bd9Sstevel@tonic-gate 					    lgrp, aff, &aff_buf);
761*7c478bd9Sstevel@tonic-gate 					found = 1;
762*7c478bd9Sstevel@tonic-gate 					break;
763*7c478bd9Sstevel@tonic-gate 				}
764*7c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
765*7c478bd9Sstevel@tonic-gate 			if (!found)
766*7c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
767*7c478bd9Sstevel@tonic-gate 		}
768*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 		/*
771*7c478bd9Sstevel@tonic-gate 		 * Free memory for lgroup affinities,
772*7c478bd9Sstevel@tonic-gate 		 * since thread didn't need it
773*7c478bd9Sstevel@tonic-gate 		 */
774*7c478bd9Sstevel@tonic-gate 		if (aff_buf)
775*7c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf,
776*7c478bd9Sstevel@tonic-gate 			    nlgrpsmax * sizeof (lgrp_affinity_t));
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 		break;
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	case P_PID:
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 		do {
783*7c478bd9Sstevel@tonic-gate 			lgrp_affinity_t	**aff_buf_array;
784*7c478bd9Sstevel@tonic-gate 			int		i;
785*7c478bd9Sstevel@tonic-gate 			size_t		size;
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 			/*
788*7c478bd9Sstevel@tonic-gate 			 * Get process
789*7c478bd9Sstevel@tonic-gate 			 */
790*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 			if (id == P_MYID)
793*7c478bd9Sstevel@tonic-gate 				p = curproc;
794*7c478bd9Sstevel@tonic-gate 			else
795*7c478bd9Sstevel@tonic-gate 				p = prfind(id);
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 			if (p == NULL) {
798*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
799*7c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
800*7c478bd9Sstevel@tonic-gate 			}
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 			/*
803*7c478bd9Sstevel@tonic-gate 			 * Get number of threads in process
804*7c478bd9Sstevel@tonic-gate 			 *
805*7c478bd9Sstevel@tonic-gate 			 * NOTE: Only care about user processes,
806*7c478bd9Sstevel@tonic-gate 			 *	 so p_lwpcnt should be number of threads.
807*7c478bd9Sstevel@tonic-gate 			 */
808*7c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
809*7c478bd9Sstevel@tonic-gate 			nthreads = p->p_lwpcnt;
810*7c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 			if (nthreads < 1)
815*7c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 			/*
818*7c478bd9Sstevel@tonic-gate 			 * Preallocate memory for lgroup affinities for
819*7c478bd9Sstevel@tonic-gate 			 * each thread in process now to avoid holding
820*7c478bd9Sstevel@tonic-gate 			 * any locks.  Allocate an array to hold a buffer
821*7c478bd9Sstevel@tonic-gate 			 * for each thread.
822*7c478bd9Sstevel@tonic-gate 			 */
823*7c478bd9Sstevel@tonic-gate 			aff_buf_array = kmem_zalloc(nthreads *
824*7c478bd9Sstevel@tonic-gate 			    sizeof (lgrp_affinity_t *), KM_SLEEP);
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 			size = nlgrpsmax * sizeof (lgrp_affinity_t);
827*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
828*7c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP);
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 			/*
833*7c478bd9Sstevel@tonic-gate 			 * Get process again since dropped locks to allocate
834*7c478bd9Sstevel@tonic-gate 			 * memory (except current process)
835*7c478bd9Sstevel@tonic-gate 			 */
836*7c478bd9Sstevel@tonic-gate 			if (id != P_MYID)
837*7c478bd9Sstevel@tonic-gate 				p = prfind(id);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 			/*
840*7c478bd9Sstevel@tonic-gate 			 * Process went away after we dropped locks and before
841*7c478bd9Sstevel@tonic-gate 			 * reacquiring them, so drop locks, free memory, and
842*7c478bd9Sstevel@tonic-gate 			 * return.
843*7c478bd9Sstevel@tonic-gate 			 */
844*7c478bd9Sstevel@tonic-gate 			if (p == NULL) {
845*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
846*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
847*7c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
848*7c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
849*7c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
850*7c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
851*7c478bd9Sstevel@tonic-gate 			}
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 			/*
856*7c478bd9Sstevel@tonic-gate 			 * See whether number of threads is same
857*7c478bd9Sstevel@tonic-gate 			 * If not, drop locks, free memory, and try again
858*7c478bd9Sstevel@tonic-gate 			 */
859*7c478bd9Sstevel@tonic-gate 			if (nthreads != p->p_lwpcnt) {
860*7c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
861*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
862*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
863*7c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
864*7c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
865*7c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
866*7c478bd9Sstevel@tonic-gate 				continue;
867*7c478bd9Sstevel@tonic-gate 			}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 			/*
870*7c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for threads in process
871*7c478bd9Sstevel@tonic-gate 			 */
872*7c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_proc(p, lgrp, aff,
873*7c478bd9Sstevel@tonic-gate 			    aff_buf_array);
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
876*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 			/*
879*7c478bd9Sstevel@tonic-gate 			 * Free any leftover memory, since some threads may
880*7c478bd9Sstevel@tonic-gate 			 * have already allocated memory and set lgroup
881*7c478bd9Sstevel@tonic-gate 			 * affinities before
882*7c478bd9Sstevel@tonic-gate 			 */
883*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
884*7c478bd9Sstevel@tonic-gate 				if (aff_buf_array[i] != NULL)
885*7c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
886*7c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf_array,
887*7c478bd9Sstevel@tonic-gate 			    nthreads * sizeof (lgrp_affinity_t *));
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 			break;
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 		} while (nthreads != p->p_lwpcnt);
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 		break;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	default:
896*7c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
897*7c478bd9Sstevel@tonic-gate 		break;
898*7c478bd9Sstevel@tonic-gate 	}
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	return (retval);
901*7c478bd9Sstevel@tonic-gate }
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate /*
905*7c478bd9Sstevel@tonic-gate  * Return the latest generation number for the lgroup hierarchy
906*7c478bd9Sstevel@tonic-gate  * with the given view
907*7c478bd9Sstevel@tonic-gate  */
908*7c478bd9Sstevel@tonic-gate lgrp_gen_t
909*7c478bd9Sstevel@tonic-gate lgrp_generation(lgrp_view_t view)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate 	cpupart_t	*cpupart;
912*7c478bd9Sstevel@tonic-gate 	uint_t		gen;
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	/*
917*7c478bd9Sstevel@tonic-gate 	 * Determine generation number for given view
918*7c478bd9Sstevel@tonic-gate 	 */
919*7c478bd9Sstevel@tonic-gate 	if (view == LGRP_VIEW_OS)
920*7c478bd9Sstevel@tonic-gate 		/*
921*7c478bd9Sstevel@tonic-gate 		 * Return generation number of lgroup hierarchy for OS view
922*7c478bd9Sstevel@tonic-gate 		 */
923*7c478bd9Sstevel@tonic-gate 		gen = lgrp_gen;
924*7c478bd9Sstevel@tonic-gate 	else {
925*7c478bd9Sstevel@tonic-gate 		/*
926*7c478bd9Sstevel@tonic-gate 		 * For caller's view, use generation numbers for lgroup
927*7c478bd9Sstevel@tonic-gate 		 * hierarchy and caller's pset
928*7c478bd9Sstevel@tonic-gate 		 * NOTE: Caller needs to check for change in pset ID
929*7c478bd9Sstevel@tonic-gate 		 */
930*7c478bd9Sstevel@tonic-gate 		cpupart = curthread->t_cpupart;
931*7c478bd9Sstevel@tonic-gate 		ASSERT(cpupart);
932*7c478bd9Sstevel@tonic-gate 		gen = lgrp_gen + cpupart->cp_gen;
933*7c478bd9Sstevel@tonic-gate 	}
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	return (gen);
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate lgrp_id_t
942*7c478bd9Sstevel@tonic-gate lgrp_home_thread(kthread_t *t)
943*7c478bd9Sstevel@tonic-gate {
944*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
947*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	thread_lock(t);
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	/*
952*7c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
953*7c478bd9Sstevel@tonic-gate 	 * thread
954*7c478bd9Sstevel@tonic-gate 	 */
955*7c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
956*7c478bd9Sstevel@tonic-gate 		thread_unlock(t);
957*7c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
958*7c478bd9Sstevel@tonic-gate 	}
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	home = lgrp_home_id(t);
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	thread_unlock(t);
963*7c478bd9Sstevel@tonic-gate 	return (home);
964*7c478bd9Sstevel@tonic-gate }
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate /*
968*7c478bd9Sstevel@tonic-gate  * Get home lgroup of given process or thread
969*7c478bd9Sstevel@tonic-gate  */
970*7c478bd9Sstevel@tonic-gate lgrp_id_t
971*7c478bd9Sstevel@tonic-gate lgrp_home_get(idtype_t idtype, id_t id)
972*7c478bd9Sstevel@tonic-gate {
973*7c478bd9Sstevel@tonic-gate 	proc_t		*p;
974*7c478bd9Sstevel@tonic-gate 	lgrp_id_t	retval;
975*7c478bd9Sstevel@tonic-gate 	kthread_t	*t;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	/*
978*7c478bd9Sstevel@tonic-gate 	 * Get home lgroup of given LWP or process
979*7c478bd9Sstevel@tonic-gate 	 */
980*7c478bd9Sstevel@tonic-gate 	switch (idtype) {
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	case P_LWPID:
983*7c478bd9Sstevel@tonic-gate 		p = curproc;
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 		/*
986*7c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
987*7c478bd9Sstevel@tonic-gate 		 */
988*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
989*7c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
990*7c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(curthread);
991*7c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
992*7c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
993*7c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
994*7c478bd9Sstevel@tonic-gate 			int	found = 0;
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
997*7c478bd9Sstevel@tonic-gate 			do {
998*7c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
999*7c478bd9Sstevel@tonic-gate 					retval = lgrp_home_thread(t);
1000*7c478bd9Sstevel@tonic-gate 					found = 1;
1001*7c478bd9Sstevel@tonic-gate 					break;
1002*7c478bd9Sstevel@tonic-gate 				}
1003*7c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
1004*7c478bd9Sstevel@tonic-gate 			if (!found)
1005*7c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
1006*7c478bd9Sstevel@tonic-gate 		}
1007*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
1008*7c478bd9Sstevel@tonic-gate 		break;
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	case P_PID:
1011*7c478bd9Sstevel@tonic-gate 		/*
1012*7c478bd9Sstevel@tonic-gate 		 * Get process
1013*7c478bd9Sstevel@tonic-gate 		 */
1014*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 		if (id == P_MYID)
1017*7c478bd9Sstevel@tonic-gate 			p = curproc;
1018*7c478bd9Sstevel@tonic-gate 		else
1019*7c478bd9Sstevel@tonic-gate 			p = prfind(id);
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 		if (p == NULL) {
1022*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
1023*7c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
1024*7c478bd9Sstevel@tonic-gate 		}
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
1027*7c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
1028*7c478bd9Sstevel@tonic-gate 		if (t == NULL)
1029*7c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
1030*7c478bd9Sstevel@tonic-gate 		else
1031*7c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(t);
1032*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 		break;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	default:
1039*7c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
1040*7c478bd9Sstevel@tonic-gate 		break;
1041*7c478bd9Sstevel@tonic-gate 	}
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	return (retval);
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate /*
1048*7c478bd9Sstevel@tonic-gate  * Return latency between "from" and "to" lgroups
1049*7c478bd9Sstevel@tonic-gate  *
1050*7c478bd9Sstevel@tonic-gate  * This latency number can only be used for relative comparison
1051*7c478bd9Sstevel@tonic-gate  * between lgroups on the running system, cannot be used across platforms,
1052*7c478bd9Sstevel@tonic-gate  * and may not reflect the actual latency.  It is platform and implementation
1053*7c478bd9Sstevel@tonic-gate  * specific, so platform gets to decide its value.  It would be nice if the
1054*7c478bd9Sstevel@tonic-gate  * number was at least proportional to make comparisons more meaningful though.
1055*7c478bd9Sstevel@tonic-gate  */
1056*7c478bd9Sstevel@tonic-gate int
1057*7c478bd9Sstevel@tonic-gate lgrp_latency(lgrp_id_t from, lgrp_id_t to)
1058*7c478bd9Sstevel@tonic-gate {
1059*7c478bd9Sstevel@tonic-gate 	lgrp_t		*from_lgrp;
1060*7c478bd9Sstevel@tonic-gate 	int		i;
1061*7c478bd9Sstevel@tonic-gate 	int		latency;
1062*7c478bd9Sstevel@tonic-gate 	int		latency_max;
1063*7c478bd9Sstevel@tonic-gate 	lgrp_t		*to_lgrp;
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	if (from < 0 || to < 0)
1068*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 	if (from > lgrp_alloc_max || to > lgrp_alloc_max)
1071*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	from_lgrp = lgrp_table[from];
1074*7c478bd9Sstevel@tonic-gate 	to_lgrp = lgrp_table[to];
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) {
1077*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
1078*7c478bd9Sstevel@tonic-gate 	}
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	/*
1081*7c478bd9Sstevel@tonic-gate 	 * Get latency for same lgroup
1082*7c478bd9Sstevel@tonic-gate 	 */
1083*7c478bd9Sstevel@tonic-gate 	if (from == to) {
1084*7c478bd9Sstevel@tonic-gate 		latency = from_lgrp->lgrp_latency;
1085*7c478bd9Sstevel@tonic-gate 		return (latency);
1086*7c478bd9Sstevel@tonic-gate 	}
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 	/*
1089*7c478bd9Sstevel@tonic-gate 	 * Get latency between leaf lgroups
1090*7c478bd9Sstevel@tonic-gate 	 */
1091*7c478bd9Sstevel@tonic-gate 	if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0)
1092*7c478bd9Sstevel@tonic-gate 		return (lgrp_plat_latency(from_lgrp->lgrp_plathand,
1093*7c478bd9Sstevel@tonic-gate 		    to_lgrp->lgrp_plathand));
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	/*
1096*7c478bd9Sstevel@tonic-gate 	 * Determine max latency between resources in two lgroups
1097*7c478bd9Sstevel@tonic-gate 	 */
1098*7c478bd9Sstevel@tonic-gate 	latency_max = 0;
1099*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
1100*7c478bd9Sstevel@tonic-gate 		lgrp_t	*from_rsrc;
1101*7c478bd9Sstevel@tonic-gate 		int	j;
1102*7c478bd9Sstevel@tonic-gate 		lgrp_t	*to_rsrc;
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 		from_rsrc = lgrp_table[i];
1105*7c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(from_rsrc) ||
1106*7c478bd9Sstevel@tonic-gate 		    !klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i))
1107*7c478bd9Sstevel@tonic-gate 			continue;
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 		for (j = 0; j <= lgrp_alloc_max; j++) {
1110*7c478bd9Sstevel@tonic-gate 			to_rsrc = lgrp_table[j];
1111*7c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to_rsrc) ||
1112*7c478bd9Sstevel@tonic-gate 			    klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM],
1113*7c478bd9Sstevel@tonic-gate 			    j) == 0)
1114*7c478bd9Sstevel@tonic-gate 				continue;
1115*7c478bd9Sstevel@tonic-gate 			latency = lgrp_plat_latency(from_rsrc->lgrp_plathand,
1116*7c478bd9Sstevel@tonic-gate 			    to_rsrc->lgrp_plathand);
1117*7c478bd9Sstevel@tonic-gate 			if (latency > latency_max)
1118*7c478bd9Sstevel@tonic-gate 				latency_max = latency;
1119*7c478bd9Sstevel@tonic-gate 		}
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 	return (latency_max);
1122*7c478bd9Sstevel@tonic-gate }
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate /*
1126*7c478bd9Sstevel@tonic-gate  * Return lgroup interface version number
1127*7c478bd9Sstevel@tonic-gate  * 0 - none
1128*7c478bd9Sstevel@tonic-gate  * 1 - original
1129*7c478bd9Sstevel@tonic-gate  * 2 - lgrp_latency_cookie() and lgrp_resources() added
1130*7c478bd9Sstevel@tonic-gate  */
1131*7c478bd9Sstevel@tonic-gate int
1132*7c478bd9Sstevel@tonic-gate lgrp_version(int version)
1133*7c478bd9Sstevel@tonic-gate {
1134*7c478bd9Sstevel@tonic-gate 	/*
1135*7c478bd9Sstevel@tonic-gate 	 * Return LGRP_VER_NONE when requested version isn't supported
1136*7c478bd9Sstevel@tonic-gate 	 */
1137*7c478bd9Sstevel@tonic-gate 	if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT)
1138*7c478bd9Sstevel@tonic-gate 		return (LGRP_VER_NONE);
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	/*
1141*7c478bd9Sstevel@tonic-gate 	 * Return current version when LGRP_VER_NONE passed in
1142*7c478bd9Sstevel@tonic-gate 	 */
1143*7c478bd9Sstevel@tonic-gate 	if (version == LGRP_VER_NONE)
1144*7c478bd9Sstevel@tonic-gate 		return (LGRP_VER_CURRENT);
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 	/*
1147*7c478bd9Sstevel@tonic-gate 	 * Otherwise, return supported version.
1148*7c478bd9Sstevel@tonic-gate 	 */
1149*7c478bd9Sstevel@tonic-gate 	return (version);
1150*7c478bd9Sstevel@tonic-gate }
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate /*
1154*7c478bd9Sstevel@tonic-gate  * Snapshot of lgroup hieararchy
1155*7c478bd9Sstevel@tonic-gate  *
1156*7c478bd9Sstevel@tonic-gate  * One snapshot is kept and is based on the kernel's native data model, so
1157*7c478bd9Sstevel@tonic-gate  * a 32-bit snapshot is kept for the 32-bit kernel and a 64-bit one for the
1158*7c478bd9Sstevel@tonic-gate  * 64-bit kernel.  If a 32-bit user wants a snapshot from the 64-bit kernel,
1159*7c478bd9Sstevel@tonic-gate  * the kernel generates a 32-bit snapshot from the data in its 64-bit snapshot.
1160*7c478bd9Sstevel@tonic-gate  *
1161*7c478bd9Sstevel@tonic-gate  * The format is defined by lgroup snapshot header and the layout of
1162*7c478bd9Sstevel@tonic-gate  * the snapshot in memory is as follows:
1163*7c478bd9Sstevel@tonic-gate  * 1) lgroup snapshot header
1164*7c478bd9Sstevel@tonic-gate  *    - specifies format of snapshot
1165*7c478bd9Sstevel@tonic-gate  *    - defined by lgrp_snapshot_header_t
1166*7c478bd9Sstevel@tonic-gate  * 2) lgroup info array
1167*7c478bd9Sstevel@tonic-gate  *    - contains information about each lgroup
1168*7c478bd9Sstevel@tonic-gate  *    - one element for each lgroup
1169*7c478bd9Sstevel@tonic-gate  *    - each element is defined by lgrp_info_t
1170*7c478bd9Sstevel@tonic-gate  * 3) lgroup CPU ID array
1171*7c478bd9Sstevel@tonic-gate  *    - contains list (array) of CPU IDs for each lgroup
1172*7c478bd9Sstevel@tonic-gate  *    - lgrp_info_t points into array and specifies how many CPUs belong to
1173*7c478bd9Sstevel@tonic-gate  *      given lgroup
1174*7c478bd9Sstevel@tonic-gate  * 4) lgroup parents array
1175*7c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of parents for each lgroup
1176*7c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
1177*7c478bd9Sstevel@tonic-gate  * 5) lgroup children array
1178*7c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of children for each lgroup
1179*7c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
1180*7c478bd9Sstevel@tonic-gate  * 6) lgroup resources array
1181*7c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of resources for each lgroup
1182*7c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
1183*7c478bd9Sstevel@tonic-gate  * 7) lgroup latency table
1184*7c478bd9Sstevel@tonic-gate  *    - contains latency from each lgroup to each of other lgroups
1185*7c478bd9Sstevel@tonic-gate  *
1186*7c478bd9Sstevel@tonic-gate  * NOTE:  Must use nlgrpsmax for per lgroup data structures because lgroups
1187*7c478bd9Sstevel@tonic-gate  *	  may be sparsely allocated.
1188*7c478bd9Sstevel@tonic-gate  */
1189*7c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t	*lgrp_snap = NULL;	/* lgroup snapshot */
1190*7c478bd9Sstevel@tonic-gate static kmutex_t		lgrp_snap_lock;		/* snapshot lock */
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate /*
1194*7c478bd9Sstevel@tonic-gate  * Take a snapshot of lgroup hierarchy and return size of buffer
1195*7c478bd9Sstevel@tonic-gate  * needed to hold snapshot
1196*7c478bd9Sstevel@tonic-gate  */
1197*7c478bd9Sstevel@tonic-gate static int
1198*7c478bd9Sstevel@tonic-gate lgrp_snapshot(void)
1199*7c478bd9Sstevel@tonic-gate {
1200*7c478bd9Sstevel@tonic-gate 	size_t		bitmask_size;
1201*7c478bd9Sstevel@tonic-gate 	size_t		bitmasks_size;
1202*7c478bd9Sstevel@tonic-gate 	size_t		bufsize;
1203*7c478bd9Sstevel@tonic-gate 	int		cpu_index;
1204*7c478bd9Sstevel@tonic-gate 	size_t		cpuids_size;
1205*7c478bd9Sstevel@tonic-gate 	int		i;
1206*7c478bd9Sstevel@tonic-gate 	int		j;
1207*7c478bd9Sstevel@tonic-gate 	size_t		info_size;
1208*7c478bd9Sstevel@tonic-gate 	size_t		lats_size;
1209*7c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_children;
1210*7c478bd9Sstevel@tonic-gate 	processorid_t	*lgrp_cpuids;
1211*7c478bd9Sstevel@tonic-gate 	lgrp_info_t	*lgrp_info;
1212*7c478bd9Sstevel@tonic-gate 	int		**lgrp_lats;
1213*7c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_parents;
1214*7c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_rsets;
1215*7c478bd9Sstevel@tonic-gate 	ulong_t		*lgrpset;
1216*7c478bd9Sstevel@tonic-gate 	int		snap_ncpus;
1217*7c478bd9Sstevel@tonic-gate 	int		snap_nlgrps;
1218*7c478bd9Sstevel@tonic-gate 	int		snap_nlgrpsmax;
1219*7c478bd9Sstevel@tonic-gate 	size_t		snap_hdr_size;
1220*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
1221*7c478bd9Sstevel@tonic-gate 	model_t		model = DATAMODEL_NATIVE;
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate 	/*
1224*7c478bd9Sstevel@tonic-gate 	 * Have up-to-date snapshot, so check to see whether caller is 32-bit
1225*7c478bd9Sstevel@tonic-gate 	 * program and need to return size of 32-bit snapshot now.
1226*7c478bd9Sstevel@tonic-gate 	 */
1227*7c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
1228*7c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32 && lgrp_snap &&
1229*7c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_gen == lgrp_gen) {
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
1232*7c478bd9Sstevel@tonic-gate 
1233*7c478bd9Sstevel@tonic-gate 		/*
1234*7c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
1235*7c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
1236*7c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
1237*7c478bd9Sstevel@tonic-gate 		 */
1238*7c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
1239*7c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
1240*7c478bd9Sstevel@tonic-gate 		info_size =
1241*7c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
1242*7c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
1243*7c478bd9Sstevel@tonic-gate 		cpuids_size =
1244*7c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
1245*7c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 		/*
1248*7c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for parents, children, and resources
1249*7c478bd9Sstevel@tonic-gate 		 * for each lgroup and pset lgroup set
1250*7c478bd9Sstevel@tonic-gate 		 */
1251*7c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
1252*7c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
1253*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 		/*
1256*7c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
1257*7c478bd9Sstevel@tonic-gate 		 */
1258*7c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (caddr32_t) +
1259*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
1262*7c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
1263*7c478bd9Sstevel@tonic-gate 		return (bufsize);
1264*7c478bd9Sstevel@tonic-gate 	}
1265*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	/*
1268*7c478bd9Sstevel@tonic-gate 	 * Check whether snapshot is up-to-date
1269*7c478bd9Sstevel@tonic-gate 	 * Free it and take another one if not
1270*7c478bd9Sstevel@tonic-gate 	 */
1271*7c478bd9Sstevel@tonic-gate 	if (lgrp_snap) {
1272*7c478bd9Sstevel@tonic-gate 		if (lgrp_snap->ss_gen == lgrp_gen)
1273*7c478bd9Sstevel@tonic-gate 			return (lgrp_snap->ss_size);
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, lgrp_snap->ss_size);
1276*7c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
1277*7c478bd9Sstevel@tonic-gate 	}
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	/*
1280*7c478bd9Sstevel@tonic-gate 	 * Allocate memory for snapshot
1281*7c478bd9Sstevel@tonic-gate 	 * w/o holding cpu_lock while waiting for memory
1282*7c478bd9Sstevel@tonic-gate 	 */
1283*7c478bd9Sstevel@tonic-gate 	while (lgrp_snap == NULL) {
1284*7c478bd9Sstevel@tonic-gate 		int	old_generation;
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 		/*
1287*7c478bd9Sstevel@tonic-gate 		 * Take snapshot of lgroup generation number
1288*7c478bd9Sstevel@tonic-gate 		 * and configuration size dependent information
1289*7c478bd9Sstevel@tonic-gate 		 * NOTE: Only count number of online CPUs,
1290*7c478bd9Sstevel@tonic-gate 		 * since only online CPUs appear in lgroups.
1291*7c478bd9Sstevel@tonic-gate 		 */
1292*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
1293*7c478bd9Sstevel@tonic-gate 		old_generation = lgrp_gen;
1294*7c478bd9Sstevel@tonic-gate 		snap_ncpus = ncpus_online;
1295*7c478bd9Sstevel@tonic-gate 		snap_nlgrps = nlgrps;
1296*7c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = nlgrpsmax;
1297*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 		/*
1300*7c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for snapshot,
1301*7c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
1302*7c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
1303*7c478bd9Sstevel@tonic-gate 		 */
1304*7c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
1305*7c478bd9Sstevel@tonic-gate 		    sizeof (void *));
1306*7c478bd9Sstevel@tonic-gate 		info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
1307*7c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
1308*7c478bd9Sstevel@tonic-gate 		cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
1309*7c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
1310*7c478bd9Sstevel@tonic-gate 		/*
1311*7c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for pset lgroup set and  parents,
1312*7c478bd9Sstevel@tonic-gate 		 * children, and resource sets for each lgroup
1313*7c478bd9Sstevel@tonic-gate 		 */
1314*7c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
1315*7c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
1316*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 		/*
1319*7c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
1320*7c478bd9Sstevel@tonic-gate 		 */
1321*7c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (int *) +
1322*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
1325*7c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate 		/*
1328*7c478bd9Sstevel@tonic-gate 		 * Allocate memory for buffer
1329*7c478bd9Sstevel@tonic-gate 		 */
1330*7c478bd9Sstevel@tonic-gate 		lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP);
1331*7c478bd9Sstevel@tonic-gate 		if (lgrp_snap == NULL)
1332*7c478bd9Sstevel@tonic-gate 			return (set_errno(ENOMEM));
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		/*
1335*7c478bd9Sstevel@tonic-gate 		 * Check whether generation number has changed
1336*7c478bd9Sstevel@tonic-gate 		 */
1337*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
1338*7c478bd9Sstevel@tonic-gate 		if (lgrp_gen == old_generation)
1339*7c478bd9Sstevel@tonic-gate 			break;		/* hasn't change, so done. */
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 		/*
1342*7c478bd9Sstevel@tonic-gate 		 * Generation number changed, so free memory and try again.
1343*7c478bd9Sstevel@tonic-gate 		 */
1344*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
1345*7c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, bufsize);
1346*7c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
1347*7c478bd9Sstevel@tonic-gate 	}
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	/*
1350*7c478bd9Sstevel@tonic-gate 	 * Fill in lgroup snapshot header
1351*7c478bd9Sstevel@tonic-gate 	 * (including pointers to tables of lgroup info, CPU IDs, and parents
1352*7c478bd9Sstevel@tonic-gate 	 * and children)
1353*7c478bd9Sstevel@tonic-gate 	 */
1354*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_version = LGRP_VER_CURRENT;
1355*7c478bd9Sstevel@tonic-gate 
1356*7c478bd9Sstevel@tonic-gate 	/*
1357*7c478bd9Sstevel@tonic-gate 	 * XXX For now, liblgrp only needs to know whether the hierarchy
1358*7c478bd9Sstevel@tonic-gate 	 * XXX only has one level or not
1359*7c478bd9Sstevel@tonic-gate 	 */
1360*7c478bd9Sstevel@tonic-gate 	if (snap_nlgrps == 1)
1361*7c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 1;
1362*7c478bd9Sstevel@tonic-gate 	else
1363*7c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 2;
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_root = LGRP_ROOTID;
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps;
1368*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax;
1369*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_ncpus = snap_ncpus;
1370*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_gen = lgrp_gen;
1371*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_view = LGRP_VIEW_OS;
1372*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_pset = 0;		/* NOTE: caller should set if needed */
1373*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_size = bufsize;
1374*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_magic = (uintptr_t)lgrp_snap;
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_info = lgrp_info =
1377*7c478bd9Sstevel@tonic-gate 	    (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_cpuids = lgrp_cpuids =
1380*7c478bd9Sstevel@tonic-gate 	    (processorid_t *)((uintptr_t)lgrp_info + info_size);
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_lgrpset = lgrpset =
1383*7c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size);
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_parents = lgrp_parents =
1386*7c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrpset + bitmask_size);
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_children = lgrp_children =
1389*7c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax *
1390*7c478bd9Sstevel@tonic-gate 	    bitmask_size));
1391*7c478bd9Sstevel@tonic-gate 
1392*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_rsets = lgrp_rsets =
1393*7c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax *
1394*7c478bd9Sstevel@tonic-gate 	    bitmask_size));
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_latencies = lgrp_lats =
1397*7c478bd9Sstevel@tonic-gate 	    (int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT *
1398*7c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax * bitmask_size));
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 	/*
1401*7c478bd9Sstevel@tonic-gate 	 * Fill in lgroup information
1402*7c478bd9Sstevel@tonic-gate 	 */
1403*7c478bd9Sstevel@tonic-gate 	cpu_index = 0;
1404*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
1405*7c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
1406*7c478bd9Sstevel@tonic-gate 		int		cpu_count;
1407*7c478bd9Sstevel@tonic-gate 		struct cpu	*head;
1408*7c478bd9Sstevel@tonic-gate 		int		k;
1409*7c478bd9Sstevel@tonic-gate 		lgrp_t		*lgrp;
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 		lgrp = lgrp_table[i];
1412*7c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(lgrp)) {
1413*7c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info[i], sizeof (lgrp_info[i]));
1414*7c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_lgrpid = LGRP_NONE;
1415*7c478bd9Sstevel@tonic-gate 			continue;
1416*7c478bd9Sstevel@tonic-gate 		}
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_lgrpid = i;
1419*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_latency = lgrp->lgrp_latency;
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 		/*
1422*7c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, and lgroup resources
1423*7c478bd9Sstevel@tonic-gate 		 */
1424*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_parents =
1425*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size));
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 		if (lgrp->lgrp_parent)
1428*7c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_info[i].info_parents,
1429*7c478bd9Sstevel@tonic-gate 			    lgrp->lgrp_parent->lgrp_id);
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_children =
1432*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size));
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++)
1435*7c478bd9Sstevel@tonic-gate 			if (klgrpset_ismember(lgrp->lgrp_children, j))
1436*7c478bd9Sstevel@tonic-gate 				BT_SET(lgrp_info[i].info_children, j);
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_rset =
1439*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_rsets +
1440*7c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < LGRP_RSRC_COUNT; j++) {
1443*7c478bd9Sstevel@tonic-gate 			ulong_t	*rset;
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 			rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset +
1446*7c478bd9Sstevel@tonic-gate 			    (j * bitmask_size));
1447*7c478bd9Sstevel@tonic-gate 			for (k = 0; k < snap_nlgrpsmax; k++)
1448*7c478bd9Sstevel@tonic-gate 				if (klgrpset_ismember(lgrp->lgrp_set[j], k))
1449*7c478bd9Sstevel@tonic-gate 					BT_SET(rset, k);
1450*7c478bd9Sstevel@tonic-gate 		}
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 		/*
1453*7c478bd9Sstevel@tonic-gate 		 * Fill in CPU IDs
1454*7c478bd9Sstevel@tonic-gate 		 */
1455*7c478bd9Sstevel@tonic-gate 		cpu_count = 0;
1456*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_cpuids = NULL;
1457*7c478bd9Sstevel@tonic-gate 		cp = head = lgrp->lgrp_cpu;
1458*7c478bd9Sstevel@tonic-gate 		if (head != NULL) {
1459*7c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index];
1460*7c478bd9Sstevel@tonic-gate 			do {
1461*7c478bd9Sstevel@tonic-gate 				lgrp_cpuids[cpu_index] = cp->cpu_id;
1462*7c478bd9Sstevel@tonic-gate 				cpu_index++;
1463*7c478bd9Sstevel@tonic-gate 				cpu_count++;
1464*7c478bd9Sstevel@tonic-gate 				cp = cp->cpu_next_lgrp;
1465*7c478bd9Sstevel@tonic-gate 			} while (cp != head);
1466*7c478bd9Sstevel@tonic-gate 		}
1467*7c478bd9Sstevel@tonic-gate 		ASSERT(cpu_count == lgrp->lgrp_cpucnt);
1468*7c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_ncpus = cpu_count;
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 		/*
1471*7c478bd9Sstevel@tonic-gate 		 * Fill in memory sizes for lgroups that directly contain
1472*7c478bd9Sstevel@tonic-gate 		 * memory
1473*7c478bd9Sstevel@tonic-gate 		 */
1474*7c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) {
1475*7c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_free =
1476*7c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
1477*7c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_install =
1478*7c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL);
1479*7c478bd9Sstevel@tonic-gate 		}
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 		/*
1482*7c478bd9Sstevel@tonic-gate 		 * Fill in latency table and buffer
1483*7c478bd9Sstevel@tonic-gate 		 */
1484*7c478bd9Sstevel@tonic-gate 		lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax *
1485*7c478bd9Sstevel@tonic-gate 		    sizeof (int *) + i * snap_nlgrpsmax * sizeof (int));
1486*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
1487*7c478bd9Sstevel@tonic-gate 			lgrp_t	*to;
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 			to = lgrp_table[j];
1490*7c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to))
1491*7c478bd9Sstevel@tonic-gate 				continue;
1492*7c478bd9Sstevel@tonic-gate 			lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id,
1493*7c478bd9Sstevel@tonic-gate 			    to->lgrp_id);
1494*7c478bd9Sstevel@tonic-gate 		}
1495*7c478bd9Sstevel@tonic-gate 	}
1496*7c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
1502*7c478bd9Sstevel@tonic-gate 	/*
1503*7c478bd9Sstevel@tonic-gate 	 * Check to see whether caller is 32-bit program and need to return
1504*7c478bd9Sstevel@tonic-gate 	 * size of 32-bit snapshot now that snapshot has been taken/updated.
1505*7c478bd9Sstevel@tonic-gate 	 * May not have been able to do this earlier if snapshot was out of
1506*7c478bd9Sstevel@tonic-gate 	 * date or didn't exist yet.
1507*7c478bd9Sstevel@tonic-gate 	 */
1508*7c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate 		/*
1513*7c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
1514*7c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
1515*7c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
1516*7c478bd9Sstevel@tonic-gate 		 */
1517*7c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
1518*7c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
1519*7c478bd9Sstevel@tonic-gate 		info_size =
1520*7c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
1521*7c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
1522*7c478bd9Sstevel@tonic-gate 		cpuids_size =
1523*7c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
1524*7c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
1527*7c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) +
1528*7c478bd9Sstevel@tonic-gate 		    1) * bitmask_size;
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 		/*
1532*7c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
1533*7c478bd9Sstevel@tonic-gate 		 */
1534*7c478bd9Sstevel@tonic-gate 		lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
1535*7c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
1538*7c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
1539*7c478bd9Sstevel@tonic-gate 		return (bufsize);
1540*7c478bd9Sstevel@tonic-gate 	}
1541*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	return (lgrp_snap->ss_size);
1544*7c478bd9Sstevel@tonic-gate }
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate /*
1548*7c478bd9Sstevel@tonic-gate  * Copy snapshot into given user buffer, fix up any pointers in buffer to point
1549*7c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, and return size of buffer
1550*7c478bd9Sstevel@tonic-gate  * needed to hold snapshot
1551*7c478bd9Sstevel@tonic-gate  */
1552*7c478bd9Sstevel@tonic-gate static int
1553*7c478bd9Sstevel@tonic-gate lgrp_snapshot_copy(char *buf, size_t bufsize)
1554*7c478bd9Sstevel@tonic-gate {
1555*7c478bd9Sstevel@tonic-gate 	size_t			bitmask_size;
1556*7c478bd9Sstevel@tonic-gate 	int			cpu_index;
1557*7c478bd9Sstevel@tonic-gate 	size_t			cpuids_size;
1558*7c478bd9Sstevel@tonic-gate 	int			i;
1559*7c478bd9Sstevel@tonic-gate 	size_t			info_size;
1560*7c478bd9Sstevel@tonic-gate 	lgrp_info_t		*lgrp_info;
1561*7c478bd9Sstevel@tonic-gate 	int			retval;
1562*7c478bd9Sstevel@tonic-gate 	size_t			snap_hdr_size;
1563*7c478bd9Sstevel@tonic-gate 	int			snap_ncpus;
1564*7c478bd9Sstevel@tonic-gate 	int			snap_nlgrpsmax;
1565*7c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header_t	*user_snap;
1566*7c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info;
1567*7c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info_buffer;
1568*7c478bd9Sstevel@tonic-gate 	processorid_t		*user_cpuids;
1569*7c478bd9Sstevel@tonic-gate 	ulong_t			*user_lgrpset;
1570*7c478bd9Sstevel@tonic-gate 	ulong_t			*user_parents;
1571*7c478bd9Sstevel@tonic-gate 	ulong_t			*user_children;
1572*7c478bd9Sstevel@tonic-gate 	int			**user_lats;
1573*7c478bd9Sstevel@tonic-gate 	int			**user_lats_buffer;
1574*7c478bd9Sstevel@tonic-gate 	ulong_t			*user_rsets;
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
1577*7c478bd9Sstevel@tonic-gate 		return (0);
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0)
1580*7c478bd9Sstevel@tonic-gate 		return (lgrp_snap->ss_size);
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate 	/*
1583*7c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
1584*7c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
1585*7c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
1586*7c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
1587*7c478bd9Sstevel@tonic-gate 	 */
1588*7c478bd9Sstevel@tonic-gate 	if (bufsize < lgrp_snap->ss_size)
1589*7c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
1592*7c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	/*
1595*7c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
1596*7c478bd9Sstevel@tonic-gate 	 */
1597*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
1598*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
1599*7c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
1600*7c478bd9Sstevel@tonic-gate 		    i)) {
1601*7c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_snap->ss_lgrpset, i);
1602*7c478bd9Sstevel@tonic-gate 		}
1603*7c478bd9Sstevel@tonic-gate 	}
1604*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 	/*
1607*7c478bd9Sstevel@tonic-gate 	 * Copy lgroup snapshot (snapshot header, lgroup info, and CPU IDs)
1608*7c478bd9Sstevel@tonic-gate 	 * into user buffer all at once
1609*7c478bd9Sstevel@tonic-gate 	 */
1610*7c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0)
1611*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate 	/*
1614*7c478bd9Sstevel@tonic-gate 	 * Round up sizes of lgroup snapshot header and info for alignment
1615*7c478bd9Sstevel@tonic-gate 	 */
1616*7c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
1617*7c478bd9Sstevel@tonic-gate 	    sizeof (void *));
1618*7c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
1619*7c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
1620*7c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
1621*7c478bd9Sstevel@tonic-gate 	    sizeof (ulong_t));
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 	/*
1626*7c478bd9Sstevel@tonic-gate 	 * Calculate pointers into user buffer for lgroup snapshot header,
1627*7c478bd9Sstevel@tonic-gate 	 * info, and CPU IDs
1628*7c478bd9Sstevel@tonic-gate 	 */
1629*7c478bd9Sstevel@tonic-gate 	user_snap = (lgrp_snapshot_header_t *)buf;
1630*7c478bd9Sstevel@tonic-gate 	user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size);
1631*7c478bd9Sstevel@tonic-gate 	user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size);
1632*7c478bd9Sstevel@tonic-gate 	user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size);
1633*7c478bd9Sstevel@tonic-gate 	user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size);
1634*7c478bd9Sstevel@tonic-gate 	user_children = (ulong_t *)((uintptr_t)user_parents +
1635*7c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
1636*7c478bd9Sstevel@tonic-gate 	user_rsets = (ulong_t *)((uintptr_t)user_children +
1637*7c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
1638*7c478bd9Sstevel@tonic-gate 	user_lats = (int **)((uintptr_t)user_rsets +
1639*7c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size));
1640*7c478bd9Sstevel@tonic-gate 
1641*7c478bd9Sstevel@tonic-gate 	/*
1642*7c478bd9Sstevel@tonic-gate 	 * Copyout magic number (ie. pointer to beginning of buffer)
1643*7c478bd9Sstevel@tonic-gate 	 */
1644*7c478bd9Sstevel@tonic-gate 	if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0)
1645*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	/*
1648*7c478bd9Sstevel@tonic-gate 	 * Fix up pointers in user buffer to point into user buffer
1649*7c478bd9Sstevel@tonic-gate 	 * not kernel snapshot
1650*7c478bd9Sstevel@tonic-gate 	 */
1651*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0)
1652*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_cpuids, &user_snap->ss_cpuids,
1655*7c478bd9Sstevel@tonic-gate 	    sizeof (user_cpuids)) != 0)
1656*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_lgrpset, &user_snap->ss_lgrpset,
1659*7c478bd9Sstevel@tonic-gate 	    sizeof (user_lgrpset)) != 0)
1660*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_parents, &user_snap->ss_parents,
1663*7c478bd9Sstevel@tonic-gate 	    sizeof (user_parents)) != 0)
1664*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1665*7c478bd9Sstevel@tonic-gate 
1666*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_children, &user_snap->ss_children,
1667*7c478bd9Sstevel@tonic-gate 	    sizeof (user_children)) != 0)
1668*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_rsets, &user_snap->ss_rsets,
1671*7c478bd9Sstevel@tonic-gate 	    sizeof (user_rsets)) != 0)
1672*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	if (copyout(&user_lats, &user_snap->ss_latencies,
1675*7c478bd9Sstevel@tonic-gate 	    sizeof (user_lats)) != 0)
1676*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate 	/*
1679*7c478bd9Sstevel@tonic-gate 	 * Make copies of lgroup info and latency table, fix up pointers,
1680*7c478bd9Sstevel@tonic-gate 	 * and then copy them into user buffer
1681*7c478bd9Sstevel@tonic-gate 	 */
1682*7c478bd9Sstevel@tonic-gate 	user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP);
1683*7c478bd9Sstevel@tonic-gate 	if (user_info_buffer == NULL)
1684*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate 	user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
1687*7c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
1688*7c478bd9Sstevel@tonic-gate 	if (user_lats_buffer == NULL) {
1689*7c478bd9Sstevel@tonic-gate 		kmem_free(user_info_buffer, info_size);
1690*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
1691*7c478bd9Sstevel@tonic-gate 	}
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 	lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
1694*7c478bd9Sstevel@tonic-gate 	bcopy(lgrp_info, user_info_buffer, info_size);
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate 	cpu_index = 0;
1697*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
1698*7c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 		/*
1701*7c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
1702*7c478bd9Sstevel@tonic-gate 		 */
1703*7c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_lgrpid == LGRP_NONE)
1704*7c478bd9Sstevel@tonic-gate 			continue;
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 		/*
1707*7c478bd9Sstevel@tonic-gate 		 * Update free memory size since it changes frequently
1708*7c478bd9Sstevel@tonic-gate 		 * Only do so for lgroups directly containing memory
1709*7c478bd9Sstevel@tonic-gate 		 *
1710*7c478bd9Sstevel@tonic-gate 		 * NOTE: This must be done before changing the pointers to
1711*7c478bd9Sstevel@tonic-gate 		 *	 point into user space since we need to dereference
1712*7c478bd9Sstevel@tonic-gate 		 *	 lgroup resource set
1713*7c478bd9Sstevel@tonic-gate 		 */
1714*7c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
1715*7c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
1716*7c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i))
1717*7c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_mem_free =
1718*7c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 		/*
1721*7c478bd9Sstevel@tonic-gate 		 * Fix up pointers to parents, children, resources, and
1722*7c478bd9Sstevel@tonic-gate 		 * latencies
1723*7c478bd9Sstevel@tonic-gate 		 */
1724*7c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_parents =
1725*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_parents + (i * bitmask_size));
1726*7c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_children =
1727*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_children + (i * bitmask_size));
1728*7c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_rset =
1729*7c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_rsets +
1730*7c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
1731*7c478bd9Sstevel@tonic-gate 		user_lats_buffer[i] = (int *)((uintptr_t)user_lats +
1732*7c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax *
1733*7c478bd9Sstevel@tonic-gate 		    sizeof (int)));
1734*7c478bd9Sstevel@tonic-gate 
1735*7c478bd9Sstevel@tonic-gate 		/*
1736*7c478bd9Sstevel@tonic-gate 		 * Fix up pointer to CPU IDs
1737*7c478bd9Sstevel@tonic-gate 		 */
1738*7c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_ncpus == 0) {
1739*7c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_cpuids = NULL;
1740*7c478bd9Sstevel@tonic-gate 			continue;
1741*7c478bd9Sstevel@tonic-gate 		}
1742*7c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index];
1743*7c478bd9Sstevel@tonic-gate 		cpu_index += user_info_buffer[i].info_ncpus;
1744*7c478bd9Sstevel@tonic-gate 	}
1745*7c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 	/*
1748*7c478bd9Sstevel@tonic-gate 	 * Copy lgroup info and latency table with pointers fixed up to point
1749*7c478bd9Sstevel@tonic-gate 	 * into user buffer out to user buffer now
1750*7c478bd9Sstevel@tonic-gate 	 */
1751*7c478bd9Sstevel@tonic-gate 	retval = lgrp_snap->ss_size;
1752*7c478bd9Sstevel@tonic-gate 	if (copyout(user_info_buffer, user_info, info_size) != 0)
1753*7c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
1754*7c478bd9Sstevel@tonic-gate 	kmem_free(user_info_buffer, info_size);
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 	if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax *
1757*7c478bd9Sstevel@tonic-gate 	    sizeof (int *)) != 0)
1758*7c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
1759*7c478bd9Sstevel@tonic-gate 	kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *));
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 	return (retval);
1762*7c478bd9Sstevel@tonic-gate }
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
1766*7c478bd9Sstevel@tonic-gate /*
1767*7c478bd9Sstevel@tonic-gate  * Make 32-bit copy of snapshot, fix up any pointers in buffer to point
1768*7c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, copy 32-bit snapshot into
1769*7c478bd9Sstevel@tonic-gate  * given user buffer, and return size of buffer needed to hold snapshot
1770*7c478bd9Sstevel@tonic-gate  */
1771*7c478bd9Sstevel@tonic-gate static int
1772*7c478bd9Sstevel@tonic-gate lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize)
1773*7c478bd9Sstevel@tonic-gate {
1774*7c478bd9Sstevel@tonic-gate 	size32_t			bitmask_size;
1775*7c478bd9Sstevel@tonic-gate 	size32_t			bitmasks_size;
1776*7c478bd9Sstevel@tonic-gate 	size32_t			children_size;
1777*7c478bd9Sstevel@tonic-gate 	int				cpu_index;
1778*7c478bd9Sstevel@tonic-gate 	size32_t			cpuids_size;
1779*7c478bd9Sstevel@tonic-gate 	int				i;
1780*7c478bd9Sstevel@tonic-gate 	int				j;
1781*7c478bd9Sstevel@tonic-gate 	size32_t			info_size;
1782*7c478bd9Sstevel@tonic-gate 	size32_t			lats_size;
1783*7c478bd9Sstevel@tonic-gate 	lgrp_info_t			*lgrp_info;
1784*7c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header32_t	*lgrp_snap32;
1785*7c478bd9Sstevel@tonic-gate 	lgrp_info32_t			*lgrp_info32;
1786*7c478bd9Sstevel@tonic-gate 	processorid_t			*lgrp_cpuids32;
1787*7c478bd9Sstevel@tonic-gate 	caddr32_t			*lgrp_lats32;
1788*7c478bd9Sstevel@tonic-gate 	int				**lgrp_lats32_kernel;
1789*7c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_set32;
1790*7c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_parents32;
1791*7c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_children32;
1792*7c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_rsets32;
1793*7c478bd9Sstevel@tonic-gate 	size32_t			parents_size;
1794*7c478bd9Sstevel@tonic-gate 	size32_t			rsets_size;
1795*7c478bd9Sstevel@tonic-gate 	size32_t			set_size;
1796*7c478bd9Sstevel@tonic-gate 	size32_t			snap_hdr_size;
1797*7c478bd9Sstevel@tonic-gate 	int				snap_ncpus;
1798*7c478bd9Sstevel@tonic-gate 	int				snap_nlgrpsmax;
1799*7c478bd9Sstevel@tonic-gate 	size32_t			snap_size;
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
1802*7c478bd9Sstevel@tonic-gate 		return (0);
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
1805*7c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	/*
1808*7c478bd9Sstevel@tonic-gate 	 * Calculate size of buffer needed for 32-bit snapshot,
1809*7c478bd9Sstevel@tonic-gate 	 * rounding up size of each object to allow for alignment
1810*7c478bd9Sstevel@tonic-gate 	 * of next object in buffer.
1811*7c478bd9Sstevel@tonic-gate 	 */
1812*7c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
1813*7c478bd9Sstevel@tonic-gate 	    sizeof (caddr32_t));
1814*7c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
1815*7c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
1816*7c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
1817*7c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax);
1820*7c478bd9Sstevel@tonic-gate 
1821*7c478bd9Sstevel@tonic-gate 	set_size = bitmask_size;
1822*7c478bd9Sstevel@tonic-gate 	parents_size = snap_nlgrpsmax * bitmask_size;
1823*7c478bd9Sstevel@tonic-gate 	children_size = snap_nlgrpsmax * bitmask_size;
1824*7c478bd9Sstevel@tonic-gate 	rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax *
1825*7c478bd9Sstevel@tonic-gate 	    (int)bitmask_size, sizeof (caddr32_t));
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate 	bitmasks_size = set_size + parents_size + children_size + rsets_size;
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	/*
1830*7c478bd9Sstevel@tonic-gate 	 * Size of latency table and buffer
1831*7c478bd9Sstevel@tonic-gate 	 */
1832*7c478bd9Sstevel@tonic-gate 	lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
1833*7c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 	snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size +
1836*7c478bd9Sstevel@tonic-gate 		lats_size;
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0) {
1839*7c478bd9Sstevel@tonic-gate 		return (snap_size);
1840*7c478bd9Sstevel@tonic-gate 	}
1841*7c478bd9Sstevel@tonic-gate 
1842*7c478bd9Sstevel@tonic-gate 	/*
1843*7c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
1844*7c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
1845*7c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
1846*7c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
1847*7c478bd9Sstevel@tonic-gate 	 */
1848*7c478bd9Sstevel@tonic-gate 	if (bufsize < snap_size)
1849*7c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 	/*
1852*7c478bd9Sstevel@tonic-gate 	 * Make 32-bit copy of snapshot, fix up pointers to point into user
1853*7c478bd9Sstevel@tonic-gate 	 * buffer not kernel, and then copy whole thing into user buffer
1854*7c478bd9Sstevel@tonic-gate 	 */
1855*7c478bd9Sstevel@tonic-gate 	lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP);
1856*7c478bd9Sstevel@tonic-gate 	if (lgrp_snap32 == NULL)
1857*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	/*
1860*7c478bd9Sstevel@tonic-gate 	 * Calculate pointers into 32-bit copy of snapshot
1861*7c478bd9Sstevel@tonic-gate 	 * for lgroup info, CPU IDs, pset lgroup bitmask, parents, children,
1862*7c478bd9Sstevel@tonic-gate 	 * resources, and latency table and buffer
1863*7c478bd9Sstevel@tonic-gate 	 */
1864*7c478bd9Sstevel@tonic-gate 	lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 +
1865*7c478bd9Sstevel@tonic-gate 	    snap_hdr_size);
1866*7c478bd9Sstevel@tonic-gate 	lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size);
1867*7c478bd9Sstevel@tonic-gate 	lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size);
1868*7c478bd9Sstevel@tonic-gate 	lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size);
1869*7c478bd9Sstevel@tonic-gate 	lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size);
1870*7c478bd9Sstevel@tonic-gate 	lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size);
1871*7c478bd9Sstevel@tonic-gate 	lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size);
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 	/*
1874*7c478bd9Sstevel@tonic-gate 	 * Make temporary lgroup latency table of pointers for kernel to use
1875*7c478bd9Sstevel@tonic-gate 	 * to fill in rows of table with latencies from each lgroup
1876*7c478bd9Sstevel@tonic-gate 	 */
1877*7c478bd9Sstevel@tonic-gate 	lgrp_lats32_kernel =  kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
1878*7c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
1879*7c478bd9Sstevel@tonic-gate 	if (lgrp_lats32_kernel == NULL) {
1880*7c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
1881*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
1882*7c478bd9Sstevel@tonic-gate 	}
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate 	/*
1885*7c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit lgroup snapshot header
1886*7c478bd9Sstevel@tonic-gate 	 * (with pointers into user's buffer for lgroup info, CPU IDs,
1887*7c478bd9Sstevel@tonic-gate 	 * bit masks, and latencies)
1888*7c478bd9Sstevel@tonic-gate 	 */
1889*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_version = lgrp_snap->ss_version;
1890*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_levels = lgrp_snap->ss_levels;
1891*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os =
1892*7c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_nlgrps;
1893*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax;
1894*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_root = lgrp_snap->ss_root;
1895*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus;
1896*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_gen = lgrp_snap->ss_gen;
1897*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_view = LGRP_VIEW_OS;
1898*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_size = snap_size;
1899*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_magic = buf;
1900*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_info = buf + snap_hdr_size;
1901*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size;
1902*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size;
1903*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size;
1904*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_children = lgrp_snap32->ss_parents +
1905*7c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
1906*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_rsets = lgrp_snap32->ss_children +
1907*7c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
1908*7c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets +
1909*7c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size);
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 	/*
1912*7c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
1913*7c478bd9Sstevel@tonic-gate 	 */
1914*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
1915*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
1916*7c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
1917*7c478bd9Sstevel@tonic-gate 		    i)) {
1918*7c478bd9Sstevel@tonic-gate 			BT_SET32(lgrp_set32, i);
1919*7c478bd9Sstevel@tonic-gate 		}
1920*7c478bd9Sstevel@tonic-gate 	}
1921*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	/*
1924*7c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit copy of lgroup info and fix up pointers
1925*7c478bd9Sstevel@tonic-gate 	 * to point into user's buffer instead of kernel's
1926*7c478bd9Sstevel@tonic-gate 	 */
1927*7c478bd9Sstevel@tonic-gate 	cpu_index = 0;
1928*7c478bd9Sstevel@tonic-gate 	lgrp_info = lgrp_snap->ss_info;
1929*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
1930*7c478bd9Sstevel@tonic-gate 		uint_t	*children;
1931*7c478bd9Sstevel@tonic-gate 		uint_t	*lgrp_rset;
1932*7c478bd9Sstevel@tonic-gate 		uint_t	*parents;
1933*7c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
1934*7c478bd9Sstevel@tonic-gate 
1935*7c478bd9Sstevel@tonic-gate 		/*
1936*7c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
1937*7c478bd9Sstevel@tonic-gate 		 */
1938*7c478bd9Sstevel@tonic-gate 		if (lgrp_info[i].info_lgrpid == LGRP_NONE) {
1939*7c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info32[i], sizeof (lgrp_info32[i]));
1940*7c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_lgrpid = LGRP_NONE;
1941*7c478bd9Sstevel@tonic-gate 			continue;
1942*7c478bd9Sstevel@tonic-gate 		}
1943*7c478bd9Sstevel@tonic-gate 
1944*7c478bd9Sstevel@tonic-gate 		/*
1945*7c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, lgroup resource set, and
1946*7c478bd9Sstevel@tonic-gate 		 * latencies from snapshot
1947*7c478bd9Sstevel@tonic-gate 		 */
1948*7c478bd9Sstevel@tonic-gate 		parents = (uint_t *)((uintptr_t)lgrp_parents32 +
1949*7c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
1950*7c478bd9Sstevel@tonic-gate 		children = (uint_t *)((uintptr_t)lgrp_children32 +
1951*7c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
1952*7c478bd9Sstevel@tonic-gate 		snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets +
1953*7c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax)));
1954*7c478bd9Sstevel@tonic-gate 		lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 +
1955*7c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
1956*7c478bd9Sstevel@tonic-gate 		lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 +
1957*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
1958*7c478bd9Sstevel@tonic-gate 		    sizeof (int));
1959*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
1960*7c478bd9Sstevel@tonic-gate 			int	k;
1961*7c478bd9Sstevel@tonic-gate 			uint_t	*rset;
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_parents[i], j))
1964*7c478bd9Sstevel@tonic-gate 				BT_SET32(parents, j);
1965*7c478bd9Sstevel@tonic-gate 
1966*7c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_children[i], j))
1967*7c478bd9Sstevel@tonic-gate 				BT_SET32(children, j);
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate 			for (k = 0; k < LGRP_RSRC_COUNT; k++) {
1970*7c478bd9Sstevel@tonic-gate 				rset = (uint_t *)((uintptr_t)lgrp_rset +
1971*7c478bd9Sstevel@tonic-gate 				    k * bitmask_size);
1972*7c478bd9Sstevel@tonic-gate 				if (BT_TEST(&snap_rset[k], j))
1973*7c478bd9Sstevel@tonic-gate 					BT_SET32(rset, j);
1974*7c478bd9Sstevel@tonic-gate 			}
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate 			lgrp_lats32_kernel[i][j] =
1977*7c478bd9Sstevel@tonic-gate 			    lgrp_snap->ss_latencies[i][j];
1978*7c478bd9Sstevel@tonic-gate 		}
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 		/*
1981*7c478bd9Sstevel@tonic-gate 		 * Fix up pointer to latency buffer
1982*7c478bd9Sstevel@tonic-gate 		 */
1983*7c478bd9Sstevel@tonic-gate 		lgrp_lats32[i] = lgrp_snap32->ss_latencies +
1984*7c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
1985*7c478bd9Sstevel@tonic-gate 		    sizeof (int);
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 		/*
1988*7c478bd9Sstevel@tonic-gate 		 * Fix up pointers for parents, children, and resources
1989*7c478bd9Sstevel@tonic-gate 		 */
1990*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_parents = lgrp_snap32->ss_parents +
1991*7c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
1992*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_children = lgrp_snap32->ss_children +
1993*7c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
1994*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets +
1995*7c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size);
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 		/*
1998*7c478bd9Sstevel@tonic-gate 		 * Fill in memory and CPU info
1999*7c478bd9Sstevel@tonic-gate 		 * Only fill in memory for lgroups directly containing memory
2000*7c478bd9Sstevel@tonic-gate 		 */
2001*7c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
2002*7c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
2003*7c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i)) {
2004*7c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_free = lgrp_mem_size(i,
2005*7c478bd9Sstevel@tonic-gate 			    LGRP_MEM_SIZE_FREE);
2006*7c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_install =
2007*7c478bd9Sstevel@tonic-gate 			    lgrp_info[i].info_mem_install;
2008*7c478bd9Sstevel@tonic-gate 		}
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus;
2011*7c478bd9Sstevel@tonic-gate 
2012*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid;
2013*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_latency = lgrp_info[i].info_latency;
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 		if (lgrp_info32[i].info_ncpus == 0) {
2016*7c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_cpuids = 0;
2017*7c478bd9Sstevel@tonic-gate 			continue;
2018*7c478bd9Sstevel@tonic-gate 		}
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate 		/*
2021*7c478bd9Sstevel@tonic-gate 		 * Fix up pointer for CPU IDs
2022*7c478bd9Sstevel@tonic-gate 		 */
2023*7c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids +
2024*7c478bd9Sstevel@tonic-gate 		    (cpu_index * sizeof (processorid_t));
2025*7c478bd9Sstevel@tonic-gate 		cpu_index += lgrp_info32[i].info_ncpus;
2026*7c478bd9Sstevel@tonic-gate 	}
2027*7c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 	/*
2030*7c478bd9Sstevel@tonic-gate 	 * Copy lgroup CPU IDs into 32-bit snapshot
2031*7c478bd9Sstevel@tonic-gate 	 * before copying it out into user's buffer
2032*7c478bd9Sstevel@tonic-gate 	 */
2033*7c478bd9Sstevel@tonic-gate 	bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size);
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 	/*
2036*7c478bd9Sstevel@tonic-gate 	 * Copy 32-bit lgroup snapshot into user's buffer all at once
2037*7c478bd9Sstevel@tonic-gate 	 */
2038*7c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) {
2039*7c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
2040*7c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
2041*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
2042*7c478bd9Sstevel@tonic-gate 	}
2043*7c478bd9Sstevel@tonic-gate 
2044*7c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_snap32, snap_size);
2045*7c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
2046*7c478bd9Sstevel@tonic-gate 
2047*7c478bd9Sstevel@tonic-gate 	return (snap_size);
2048*7c478bd9Sstevel@tonic-gate }
2049*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
2050*7c478bd9Sstevel@tonic-gate 
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate int
2053*7c478bd9Sstevel@tonic-gate lgrpsys(int subcode, long ia, void *ap)
2054*7c478bd9Sstevel@tonic-gate {
2055*7c478bd9Sstevel@tonic-gate 	size_t	bufsize;
2056*7c478bd9Sstevel@tonic-gate 	int	latency;
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	switch (subcode) {
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_GET:
2061*7c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_get((lgrp_affinity_args_t *)ap));
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_SET:
2064*7c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_set((lgrp_affinity_args_t *)ap));
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_GENERATION:
2067*7c478bd9Sstevel@tonic-gate 		return (lgrp_generation(ia));
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_HOME:
2070*7c478bd9Sstevel@tonic-gate 		return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap));
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_LATENCY:
2073*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
2074*7c478bd9Sstevel@tonic-gate 		latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap);
2075*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
2076*7c478bd9Sstevel@tonic-gate 		return (latency);
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_MEMINFO:
2079*7c478bd9Sstevel@tonic-gate 		return (meminfo(ia, (struct meminfo *)ap));
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_VERSION:
2082*7c478bd9Sstevel@tonic-gate 		return (lgrp_version(ia));
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate 	case LGRP_SYS_SNAPSHOT:
2085*7c478bd9Sstevel@tonic-gate 		mutex_enter(&lgrp_snap_lock);
2086*7c478bd9Sstevel@tonic-gate 		bufsize = lgrp_snapshot();
2087*7c478bd9Sstevel@tonic-gate 		if (ap && ia > 0) {
2088*7c478bd9Sstevel@tonic-gate 			if (get_udatamodel() == DATAMODEL_NATIVE)
2089*7c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy(ap, ia);
2090*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
2091*7c478bd9Sstevel@tonic-gate 			else
2092*7c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy32(
2093*7c478bd9Sstevel@tonic-gate 				    (caddr32_t)(uintptr_t)ap, ia);
2094*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
2095*7c478bd9Sstevel@tonic-gate 		}
2096*7c478bd9Sstevel@tonic-gate 		mutex_exit(&lgrp_snap_lock);
2097*7c478bd9Sstevel@tonic-gate 		return (bufsize);
2098*7c478bd9Sstevel@tonic-gate 
2099*7c478bd9Sstevel@tonic-gate 	default:
2100*7c478bd9Sstevel@tonic-gate 		break;
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	}
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 	return (set_errno(EINVAL));
2105*7c478bd9Sstevel@tonic-gate }
2106