xref: /titanic_41/usr/src/uts/common/io/cpc.c (revision 72e1c0551e3c92bca8ab60d3f38afd96f35cc88c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * CPU Performance Counter system calls and device driver.
30  *
31  * This module uses a combination of thread context operators, and
32  * thread-specific data to export CPU performance counters
33  * via both a system call and a driver interface.
34  *
35  * There are three access methods exported - the 'shared' device
36  * and the 'private' and 'agent' variants of the system call.
37  *
38  * The shared device treats the performance counter registers as
39  * a processor metric, regardless of the work scheduled on them.
40  * The private system call treats the performance counter registers
41  * as a property of a single lwp.  This is achieved by using the
42  * thread context operators to virtualize the contents of the
43  * performance counter registers between lwps.
44  *
45  * The agent method is like the private method, except that it must
46  * be accessed via /proc's agent lwp to allow the counter context of
47  * other threads to be examined safely.
48  *
49  * The shared usage fundamentally conflicts with the agent and private usage;
50  * almost all of the complexity of the module is needed to allow these two
51  * models to co-exist in a reasonable way.
52  */
53 
54 #include <sys/types.h>
55 #include <sys/file.h>
56 #include <sys/errno.h>
57 #include <sys/open.h>
58 #include <sys/cred.h>
59 #include <sys/conf.h>
60 #include <sys/stat.h>
61 #include <sys/processor.h>
62 #include <sys/cpuvar.h>
63 #include <sys/disp.h>
64 #include <sys/kmem.h>
65 #include <sys/modctl.h>
66 #include <sys/ddi.h>
67 #include <sys/sunddi.h>
68 #include <sys/nvpair.h>
69 #include <sys/policy.h>
70 #include <sys/machsystm.h>
71 #include <sys/cpc_impl.h>
72 #include <sys/cpc_pcbe.h>
73 #include <sys/kcpc.h>
74 
75 static int kcpc_copyin_set(kcpc_set_t **set, void *ubuf, size_t len);
76 static int kcpc_verify_set(kcpc_set_t *set);
77 static uint32_t kcpc_nvlist_npairs(nvlist_t *list);
78 
79 /*
80  * Generic attributes supported regardless of processor.
81  */
82 
83 #define	ATTRLIST "picnum"
84 #define	SEPARATOR ","
85 
86 /*
87  * System call to access CPU performance counters.
88  */
89 static int
90 cpc(int cmd, id_t lwpid, void *udata1, void *udata2, void *udata3)
91 {
92 	kthread_t	*t;
93 	int		error;
94 	int		size;
95 	const char	*str;
96 	int		code;
97 
98 	/*
99 	 * This CPC syscall should only be loaded if it found a PCBE to use.
100 	 */
101 	ASSERT(pcbe_ops != NULL);
102 
103 	if (curproc->p_agenttp == curthread) {
104 		/*
105 		 * Only if /proc is invoking this system call from
106 		 * the agent thread do we allow the caller to examine
107 		 * the contexts of other lwps in the process.  And
108 		 * because we know we're the agent, we know we don't
109 		 * have to grab p_lock because no-one else can change
110 		 * the state of the process.
111 		 */
112 		if ((t = idtot(curproc, lwpid)) == NULL || t == curthread)
113 			return (set_errno(ESRCH));
114 		ASSERT(t->t_tid == lwpid && ttolwp(t) != NULL);
115 	} else
116 		t = curthread;
117 
118 	if (t->t_cpc_set == NULL && (cmd == CPC_SAMPLE || cmd == CPC_RELE))
119 		return (set_errno(EINVAL));
120 
121 	switch (cmd) {
122 	case CPC_BIND:
123 		/*
124 		 * udata1 = pointer to packed nvlist buffer
125 		 * udata2 = size of packed nvlist buffer
126 		 * udata3 = User addr to return error subcode in.
127 		 */
128 
129 		rw_enter(&kcpc_cpuctx_lock, RW_READER);
130 		if (kcpc_cpuctx) {
131 			rw_exit(&kcpc_cpuctx_lock);
132 			return (set_errno(EAGAIN));
133 		}
134 
135 		if (kcpc_hw_lwp_hook() != 0) {
136 			rw_exit(&kcpc_cpuctx_lock);
137 			return (set_errno(EACCES));
138 		}
139 
140 		/*
141 		 * An LWP may only have one set bound to it at a time; if there
142 		 * is a set bound to this LWP already, we unbind it here.
143 		 */
144 		if (t->t_cpc_set != NULL)
145 			(void) kcpc_unbind(t->t_cpc_set);
146 		ASSERT(t->t_cpc_set == NULL);
147 
148 		if ((error = kcpc_copyin_set(&t->t_cpc_set, udata1,
149 		    (size_t)udata2)) != 0) {
150 			rw_exit(&kcpc_cpuctx_lock);
151 			return (set_errno(error));
152 		}
153 
154 		if ((error = kcpc_verify_set(t->t_cpc_set)) != 0) {
155 			rw_exit(&kcpc_cpuctx_lock);
156 			kcpc_free_set(t->t_cpc_set);
157 			t->t_cpc_set = NULL;
158 			if (copyout(&error, udata3, sizeof (error)) == -1)
159 				return (set_errno(EFAULT));
160 			return (set_errno(EINVAL));
161 		}
162 
163 		if ((error = kcpc_bind_thread(t->t_cpc_set, t, &code)) != 0) {
164 			rw_exit(&kcpc_cpuctx_lock);
165 			kcpc_free_set(t->t_cpc_set);
166 			t->t_cpc_set = NULL;
167 			/*
168 			 * EINVAL and EACCES are the only errors with more
169 			 * specific subcodes.
170 			 */
171 			if ((error == EINVAL || error == EACCES) &&
172 			    copyout(&code, udata3, sizeof (code)) == -1)
173 				return (set_errno(EFAULT));
174 			return (set_errno(error));
175 		}
176 
177 		rw_exit(&kcpc_cpuctx_lock);
178 		return (0);
179 	case CPC_SAMPLE:
180 		/*
181 		 * udata1 = pointer to user's buffer
182 		 * udata2 = pointer to user's hrtime
183 		 * udata3 = pointer to user's tick
184 		 */
185 		/*
186 		 * We only allow thread-bound sets to be sampled via the
187 		 * syscall, so if this set has a CPU-bound context, return an
188 		 * error.
189 		 */
190 		if (t->t_cpc_set->ks_ctx->kc_cpuid != -1)
191 			return (set_errno(EINVAL));
192 		if ((error = kcpc_sample(t->t_cpc_set, udata1, udata2,
193 		    udata3)) != 0)
194 			return (set_errno(error));
195 
196 		return (0);
197 	case CPC_PRESET:
198 	case CPC_RESTART:
199 		/*
200 		 * These are valid only if this lwp has a bound set.
201 		 */
202 		if (t->t_cpc_set == NULL)
203 			return (set_errno(EINVAL));
204 		if (cmd == CPC_PRESET) {
205 			/*
206 			 * The preset is shipped up to us from userland in two
207 			 * parts. This lets us handle 64-bit values from 32-bit
208 			 * and 64-bit applications in the same manner.
209 			 *
210 			 * udata1 = index of request to preset
211 			 * udata2 = new 64-bit preset (most sig. 32 bits)
212 			 * udata3 = new 64-bit preset (least sig. 32 bits)
213 			 */
214 			if ((error = kcpc_preset(t->t_cpc_set, (intptr_t)udata1,
215 			    ((uint64_t)(uintptr_t)udata2 << 32ULL) |
216 			    (uint64_t)(uintptr_t)udata3)) != 0)
217 				return (set_errno(error));
218 		} else {
219 			/*
220 			 * udata[1-3] = unused
221 			 */
222 			if ((error = kcpc_restart(t->t_cpc_set)) != 0)
223 				return (set_errno(error));
224 		}
225 		return (0);
226 	case CPC_ENABLE:
227 	case CPC_DISABLE:
228 		udata1 = 0;
229 		/*FALLTHROUGH*/
230 	case CPC_USR_EVENTS:
231 	case CPC_SYS_EVENTS:
232 		if (t != curthread || t->t_cpc_set == NULL)
233 			return (set_errno(EINVAL));
234 		/*
235 		 * Provided for backwards compatibility with CPCv1.
236 		 *
237 		 * Stop the counters and record the current counts. Use the
238 		 * counts as the preset to rebind a new set with the requests
239 		 * reconfigured as requested.
240 		 *
241 		 * udata1: 1 == enable; 0 == disable
242 		 * udata{2,3}: unused
243 		 */
244 		rw_enter(&kcpc_cpuctx_lock, RW_READER);
245 		if ((error = kcpc_enable(t,
246 		    cmd, (int)(uintptr_t)udata1)) != 0) {
247 			rw_exit(&kcpc_cpuctx_lock);
248 			return (set_errno(error));
249 		}
250 		rw_exit(&kcpc_cpuctx_lock);
251 		return (0);
252 	case CPC_NPIC:
253 		return (cpc_ncounters);
254 	case CPC_CAPS:
255 		return (pcbe_ops->pcbe_caps);
256 	case CPC_EVLIST_SIZE:
257 	case CPC_LIST_EVENTS:
258 		/*
259 		 * udata1 = pointer to user's int or buffer
260 		 * udata2 = picnum
261 		 * udata3 = unused
262 		 */
263 		if ((uintptr_t)udata2 >= cpc_ncounters)
264 			return (set_errno(EINVAL));
265 
266 		size = strlen(
267 		    pcbe_ops->pcbe_list_events((uintptr_t)udata2)) + 1;
268 
269 		if (cmd == CPC_EVLIST_SIZE) {
270 			if (suword32(udata1, size) == -1)
271 				return (set_errno(EFAULT));
272 		} else {
273 			if (copyout(
274 			    pcbe_ops->pcbe_list_events((uintptr_t)udata2),
275 			    udata1, size) == -1)
276 				return (set_errno(EFAULT));
277 		}
278 		return (0);
279 	case CPC_ATTRLIST_SIZE:
280 	case CPC_LIST_ATTRS:
281 		/*
282 		 * udata1 = pointer to user's int or buffer
283 		 * udata2 = unused
284 		 * udata3 = unused
285 		 *
286 		 * attrlist size is length of PCBE-supported attributes, plus
287 		 * room for "picnum\0" plus an optional ',' separator char.
288 		 */
289 		str = pcbe_ops->pcbe_list_attrs();
290 		size = strlen(str) + sizeof (SEPARATOR ATTRLIST) + 1;
291 		if (str[0] != '\0')
292 			/*
293 			 * A ',' separator character is necessary.
294 			 */
295 			size += 1;
296 
297 		if (cmd == CPC_ATTRLIST_SIZE) {
298 			if (suword32(udata1, size) == -1)
299 				return (set_errno(EFAULT));
300 		} else {
301 			/*
302 			 * Copyout the PCBE attributes, and then append the
303 			 * generic attribute list (with separator if necessary).
304 			 */
305 			if (copyout(str, udata1, strlen(str)) == -1)
306 				return (set_errno(EFAULT));
307 			if (str[0] != '\0') {
308 				if (copyout(SEPARATOR ATTRLIST,
309 				    ((char *)udata1) + strlen(str),
310 				    strlen(SEPARATOR ATTRLIST) + 1)
311 				    == -1)
312 					return (set_errno(EFAULT));
313 			} else
314 				if (copyout(ATTRLIST,
315 				    (char *)udata1 + strlen(str),
316 				    strlen(ATTRLIST) + 1) == -1)
317 					return (set_errno(EFAULT));
318 		}
319 		return (0);
320 	case CPC_IMPL_NAME:
321 	case CPC_CPUREF:
322 		/*
323 		 * udata1 = pointer to user's buffer
324 		 * udata2 = unused
325 		 * udata3 = unused
326 		 */
327 		if (cmd == CPC_IMPL_NAME) {
328 			str = pcbe_ops->pcbe_impl_name();
329 			ASSERT(strlen(str) < CPC_MAX_IMPL_NAME);
330 		} else {
331 			str = pcbe_ops->pcbe_cpuref();
332 			ASSERT(strlen(str) < CPC_MAX_CPUREF);
333 		}
334 
335 		if (copyout(str, udata1, strlen(str) + 1) != 0)
336 			return (set_errno(EFAULT));
337 		return (0);
338 	case CPC_INVALIDATE:
339 		kcpc_invalidate(t);
340 		return (0);
341 	case CPC_RELE:
342 		if ((error = kcpc_unbind(t->t_cpc_set)) != 0)
343 			return (set_errno(error));
344 		return (0);
345 	default:
346 		return (set_errno(EINVAL));
347 	}
348 }
349 
350 /*
351  * The 'shared' device allows direct access to the
352  * performance counter control register of the current CPU.
353  * The major difference between the contexts created here and those
354  * above is that the context handlers are -not- installed, thus
355  * no context switching behaviour occurs.
356  *
357  * Because they manipulate per-cpu state, these ioctls can
358  * only be invoked from a bound lwp, by a caller with the cpc_cpu privilege
359  * who can open the relevant entry in /devices (the act of holding it open
360  * causes other uses of the counters to be suspended).
361  *
362  * Note that for correct results, the caller -must- ensure that
363  * all existing per-lwp contexts are either inactive or marked invalid;
364  * that's what the open routine does.
365  */
366 /*ARGSUSED*/
367 static int
368 kcpc_ioctl(dev_t dev, int cmd, intptr_t data, int flags, cred_t *cr, int *rvp)
369 {
370 	kthread_t	*t = curthread;
371 	processorid_t	cpuid;
372 	void		*udata1 = NULL;
373 	void		*udata2 = NULL;
374 	void		*udata3 = NULL;
375 	int		error;
376 	int		code;
377 
378 	STRUCT_DECL(__cpc_args, args);
379 
380 	STRUCT_INIT(args, flags);
381 
382 	if (curthread->t_bind_cpu != getminor(dev))
383 		return (EAGAIN);  /* someone unbound it? */
384 
385 	cpuid = getminor(dev);
386 
387 	if (cmd == CPCIO_BIND || cmd == CPCIO_SAMPLE) {
388 		if (copyin((void *)data, STRUCT_BUF(args),
389 		    STRUCT_SIZE(args)) == -1)
390 			return (EFAULT);
391 
392 		udata1 = STRUCT_FGETP(args, udata1);
393 		udata2 = STRUCT_FGETP(args, udata2);
394 		udata3 = STRUCT_FGETP(args, udata3);
395 	}
396 
397 	switch (cmd) {
398 	case CPCIO_BIND:
399 		/*
400 		 * udata1 = pointer to packed nvlist buffer
401 		 * udata2 = size of packed nvlist buffer
402 		 * udata3 = User addr to return error subcode in.
403 		 */
404 		if (t->t_cpc_set != NULL) {
405 			(void) kcpc_unbind(t->t_cpc_set);
406 			ASSERT(t->t_cpc_set == NULL);
407 		}
408 
409 		if ((error = kcpc_copyin_set(&t->t_cpc_set, udata1,
410 		    (size_t)udata2)) != 0) {
411 			return (error);
412 		}
413 
414 		if ((error = kcpc_verify_set(t->t_cpc_set)) != 0) {
415 			kcpc_free_set(t->t_cpc_set);
416 			t->t_cpc_set = NULL;
417 			if (copyout(&error, udata3, sizeof (error)) == -1)
418 				return (EFAULT);
419 			return (EINVAL);
420 		}
421 
422 		if ((error = kcpc_bind_cpu(t->t_cpc_set, cpuid, &code)) != 0) {
423 			kcpc_free_set(t->t_cpc_set);
424 			t->t_cpc_set = NULL;
425 			/*
426 			 * Subcodes are only returned for EINVAL and EACCESS.
427 			 */
428 			if ((error == EINVAL || error == EACCES) &&
429 			    copyout(&code, udata3, sizeof (code)) == -1)
430 				return (EFAULT);
431 			return (error);
432 		}
433 
434 		return (0);
435 	case CPCIO_SAMPLE:
436 		/*
437 		 * udata1 = pointer to user's buffer
438 		 * udata2 = pointer to user's hrtime
439 		 * udata3 = pointer to user's tick
440 		 */
441 		/*
442 		 * Only CPU-bound sets may be sampled via the ioctl(). If this
443 		 * set has no CPU-bound context, return an error.
444 		 */
445 		if (t->t_cpc_set == NULL)
446 			return (EINVAL);
447 		if ((error = kcpc_sample(t->t_cpc_set, udata1, udata2,
448 		    udata3)) != 0)
449 			return (error);
450 		return (0);
451 	case CPCIO_RELE:
452 		if (t->t_cpc_set == NULL)
453 			return (EINVAL);
454 		return (kcpc_unbind(t->t_cpc_set));
455 	default:
456 		return (EINVAL);
457 	}
458 }
459 
460 /*
461  * The device supports multiple opens, but only one open
462  * is allowed per processor.  This is to enable multiple
463  * instances of tools looking at different processors.
464  */
465 #define	KCPC_MINOR_SHARED		((minor_t)0x3fffful)
466 
467 static ulong_t *kcpc_cpumap;		/* bitmap of cpus */
468 
469 /*ARGSUSED1*/
470 static int
471 kcpc_open(dev_t *dev, int flags, int otyp, cred_t *cr)
472 {
473 	processorid_t	cpuid;
474 	int		error;
475 
476 	ASSERT(pcbe_ops != NULL);
477 
478 	if ((error = secpolicy_cpc_cpu(cr)) != 0)
479 		return (error);
480 	if (getminor(*dev) != KCPC_MINOR_SHARED)
481 		return (ENXIO);
482 	if ((cpuid = curthread->t_bind_cpu) == PBIND_NONE)
483 		return (EINVAL);
484 	if (cpuid > max_cpuid)
485 		return (EINVAL);
486 
487 	rw_enter(&kcpc_cpuctx_lock, RW_WRITER);
488 	if (++kcpc_cpuctx == 1) {
489 		ASSERT(kcpc_cpumap == NULL);
490 		kcpc_cpumap = kmem_zalloc(BT_SIZEOFMAP(max_cpuid + 1),
491 		    KM_SLEEP);
492 		/*
493 		 * When this device is open for processor-based contexts,
494 		 * no further lwp-based contexts can be created.
495 		 *
496 		 * Since this is the first open, ensure that all existing
497 		 * contexts are invalidated.
498 		 */
499 		kcpc_invalidate_all();
500 	} else if (BT_TEST(kcpc_cpumap, cpuid)) {
501 		kcpc_cpuctx--;
502 		rw_exit(&kcpc_cpuctx_lock);
503 		return (EAGAIN);
504 	} else if (kcpc_hw_cpu_hook(cpuid, kcpc_cpumap) != 0) {
505 		kcpc_cpuctx--;
506 		rw_exit(&kcpc_cpuctx_lock);
507 		return (EACCES);
508 	}
509 	BT_SET(kcpc_cpumap, cpuid);
510 	rw_exit(&kcpc_cpuctx_lock);
511 
512 	*dev = makedevice(getmajor(*dev), (minor_t)cpuid);
513 
514 	return (0);
515 }
516 
517 /*ARGSUSED1*/
518 static int
519 kcpc_close(dev_t dev, int flags, int otyp, cred_t *cr)
520 {
521 	rw_enter(&kcpc_cpuctx_lock, RW_WRITER);
522 	BT_CLEAR(kcpc_cpumap, getminor(dev));
523 	if (--kcpc_cpuctx == 0) {
524 		kmem_free(kcpc_cpumap, BT_SIZEOFMAP(max_cpuid + 1));
525 		kcpc_cpumap = NULL;
526 	}
527 	ASSERT(kcpc_cpuctx >= 0);
528 	rw_exit(&kcpc_cpuctx_lock);
529 
530 	return (0);
531 }
532 
533 /*
534  * Sane boundaries on the size of packed lists. In bytes.
535  */
536 #define	CPC_MIN_PACKSIZE 4
537 #define	CPC_MAX_PACKSIZE 10000
538 
539 /*
540  * Sane boundary on the number of requests a set can contain.
541  */
542 #define	CPC_MAX_NREQS 100
543 
544 /*
545  * Sane boundary on the number of attributes a request can contain.
546  */
547 #define	CPC_MAX_ATTRS 50
548 
549 /*
550  * Copy in a packed nvlist from the user and create a request set out of it.
551  * If successful, return 0 and store a pointer to the set we've created. Returns
552  * error code on error.
553  */
554 int
555 kcpc_copyin_set(kcpc_set_t **inset, void *ubuf, size_t len)
556 {
557 	kcpc_set_t	*set;
558 	int		i;
559 	int		j;
560 	char		*packbuf;
561 
562 	nvlist_t	*nvl;
563 	nvpair_t	*nvp = NULL;
564 
565 	nvlist_t	*attrs;
566 	nvpair_t	*nvp_attr;
567 	kcpc_attr_t	*attrp;
568 
569 	nvlist_t	**reqlist;
570 	uint_t		nreqs;
571 	uint64_t	uint64;
572 	uint32_t	uint32;
573 	uint32_t	setflags = (uint32_t)-1;
574 	char		*string;
575 	char		*name;
576 
577 	if (len < CPC_MIN_PACKSIZE || len > CPC_MAX_PACKSIZE)
578 		return (EINVAL);
579 
580 	packbuf = kmem_alloc(len, KM_SLEEP);
581 
582 	if (copyin(ubuf, packbuf, len) == -1) {
583 		kmem_free(packbuf, len);
584 		return (EFAULT);
585 	}
586 
587 	if (nvlist_unpack(packbuf, len, &nvl, KM_SLEEP) != 0) {
588 		kmem_free(packbuf, len);
589 		return (EINVAL);
590 	}
591 
592 	/*
593 	 * The nvlist has been unpacked so there is no need for the packed
594 	 * representation from this point on.
595 	 */
596 	kmem_free(packbuf, len);
597 
598 	i = 0;
599 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
600 		switch (nvpair_type(nvp)) {
601 		case DATA_TYPE_UINT32:
602 			if (strcmp(nvpair_name(nvp), "flags") != 0 ||
603 			    nvpair_value_uint32(nvp, &setflags) != 0) {
604 				nvlist_free(nvl);
605 				return (EINVAL);
606 			}
607 			break;
608 		case DATA_TYPE_NVLIST_ARRAY:
609 			if (strcmp(nvpair_name(nvp), "reqs") != 0 ||
610 			    nvpair_value_nvlist_array(nvp, &reqlist,
611 				&nreqs) != 0) {
612 				nvlist_free(nvl);
613 				return (EINVAL);
614 			}
615 			break;
616 		default:
617 			nvlist_free(nvl);
618 			return (EINVAL);
619 		}
620 		i++;
621 	}
622 
623 	/*
624 	 * There should be two members in the top-level nvlist:
625 	 * an array of nvlists consisting of the requests, and flags.
626 	 * Anything else is an invalid set.
627 	 */
628 	if (i != 2) {
629 		nvlist_free(nvl);
630 		return (EINVAL);
631 	}
632 
633 	if (nreqs > CPC_MAX_NREQS) {
634 		nvlist_free(nvl);
635 		return (EINVAL);
636 	}
637 
638 	/*
639 	 * The requests are now stored in the nvlist array at reqlist.
640 	 * Note that the use of kmem_zalloc() to alloc the kcpc_set_t means
641 	 * we don't need to call the init routines for ks_lock and ks_condv.
642 	 */
643 	set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP);
644 	set->ks_req = (kcpc_request_t *)kmem_zalloc(sizeof (kcpc_request_t) *
645 	    nreqs, KM_SLEEP);
646 	set->ks_nreqs = nreqs;
647 	/*
648 	 * If the nvlist didn't contain a flags member, setflags was initialized
649 	 * with an illegal value and this set will fail sanity checks later on.
650 	 */
651 	set->ks_flags = setflags;
652 	/*
653 	 * Initialize bind/unbind set synchronization.
654 	 */
655 	set->ks_state &= ~KCPC_SET_BOUND;
656 
657 	/*
658 	 * Build the set up one request at a time, always keeping it self-
659 	 * consistent so we can give it to kcpc_free_set() if we need to back
660 	 * out and return and error.
661 	 */
662 	for (i = 0; i < nreqs; i++) {
663 		nvp = NULL;
664 		set->ks_req[i].kr_picnum = -1;
665 		while ((nvp = nvlist_next_nvpair(reqlist[i], nvp)) != NULL) {
666 			name = nvpair_name(nvp);
667 			switch (nvpair_type(nvp)) {
668 			case DATA_TYPE_UINT32:
669 				if (nvpair_value_uint32(nvp, &uint32) == EINVAL)
670 					goto inval;
671 				if (strcmp(name, "cr_flags") == 0)
672 					set->ks_req[i].kr_flags = uint32;
673 				if (strcmp(name, "cr_index") == 0)
674 					set->ks_req[i].kr_index = uint32;
675 				break;
676 			case DATA_TYPE_UINT64:
677 				if (nvpair_value_uint64(nvp, &uint64) == EINVAL)
678 					goto inval;
679 				if (strcmp(name, "cr_preset") == 0)
680 					set->ks_req[i].kr_preset = uint64;
681 				break;
682 			case DATA_TYPE_STRING:
683 				if (nvpair_value_string(nvp, &string) == EINVAL)
684 					goto inval;
685 				if (strcmp(name, "cr_event") == 0)
686 					(void) strncpy(set->ks_req[i].kr_event,
687 					    string, CPC_MAX_EVENT_LEN);
688 				break;
689 			case DATA_TYPE_NVLIST:
690 				if (strcmp(name, "cr_attr") != 0)
691 					goto inval;
692 				if (nvpair_value_nvlist(nvp, &attrs) == EINVAL)
693 					goto inval;
694 				nvp_attr = NULL;
695 				/*
696 				 * If the picnum has been specified as an
697 				 * attribute, consume that attribute here and
698 				 * remove it from the list of attributes.
699 				 */
700 				if (nvlist_lookup_uint64(attrs, "picnum",
701 				    &uint64) == 0) {
702 					if (nvlist_remove(attrs, "picnum",
703 					    DATA_TYPE_UINT64) != 0)
704 						panic("nvlist %p faulty",
705 						    attrs);
706 					set->ks_req[i].kr_picnum = uint64;
707 				}
708 
709 				if ((set->ks_req[i].kr_nattrs =
710 				    kcpc_nvlist_npairs(attrs)) == 0)
711 					break;
712 
713 				if (set->ks_req[i].kr_nattrs > CPC_MAX_ATTRS)
714 					goto inval;
715 
716 				set->ks_req[i].kr_attr =
717 				    kmem_alloc(set->ks_req[i].kr_nattrs *
718 				    sizeof (kcpc_attr_t), KM_SLEEP);
719 				j = 0;
720 
721 				while ((nvp_attr = nvlist_next_nvpair(attrs,
722 				    nvp_attr)) != NULL) {
723 					attrp = &set->ks_req[i].kr_attr[j];
724 
725 					if (nvpair_type(nvp_attr) !=
726 					    DATA_TYPE_UINT64)
727 						goto inval;
728 
729 					(void) strncpy(attrp->ka_name,
730 					    nvpair_name(nvp_attr),
731 					    CPC_MAX_ATTR_LEN);
732 
733 					if (nvpair_value_uint64(nvp_attr,
734 					    &(attrp->ka_val)) == EINVAL)
735 						goto inval;
736 					j++;
737 				}
738 				ASSERT(j == set->ks_req[i].kr_nattrs);
739 			default:
740 				break;
741 			}
742 		}
743 	}
744 
745 	nvlist_free(nvl);
746 	*inset = set;
747 	return (0);
748 
749 inval:
750 	nvlist_free(nvl);
751 	kcpc_free_set(set);
752 	return (EINVAL);
753 }
754 
755 /*
756  * Count the number of nvpairs in the supplied nvlist.
757  */
758 static uint32_t
759 kcpc_nvlist_npairs(nvlist_t *list)
760 {
761 	nvpair_t *nvp = NULL;
762 	uint32_t n = 0;
763 
764 	while ((nvp = nvlist_next_nvpair(list, nvp)) != NULL)
765 		n++;
766 
767 	return (n);
768 }
769 
770 /*
771  * Performs sanity checks on the given set.
772  * Returns 0 if the set checks out OK.
773  * Returns a detailed error subcode, or -1 if there is no applicable subcode.
774  */
775 static int
776 kcpc_verify_set(kcpc_set_t *set)
777 {
778 	kcpc_request_t	*rp;
779 	int		i;
780 	uint64_t	bitmap = 0;
781 	int		n;
782 
783 	if (set->ks_nreqs > cpc_ncounters)
784 		return (-1);
785 
786 	if (CPC_SET_VALID_FLAGS(set->ks_flags) == 0)
787 		return (-1);
788 
789 	for (i = 0; i < set->ks_nreqs; i++) {
790 		rp = &set->ks_req[i];
791 
792 		/*
793 		 * The following comparison must cast cpc_ncounters to an int,
794 		 * because kr_picnum will be -1 if the request didn't explicitly
795 		 * choose a PIC.
796 		 */
797 		if (rp->kr_picnum >= (int)cpc_ncounters)
798 			return (CPC_INVALID_PICNUM);
799 
800 		/*
801 		 * Of the pics whose physical picnum has been specified, make
802 		 * sure each PIC appears only once in set.
803 		 */
804 		if ((n = set->ks_req[i].kr_picnum) != -1) {
805 			if ((bitmap & (1 << n)) != 0)
806 				return (-1);
807 			bitmap |= (1 << n);
808 		}
809 
810 		/*
811 		 * Make sure the requested index falls within the range of all
812 		 * requests.
813 		 */
814 		if (rp->kr_index < 0 || rp->kr_index >= set->ks_nreqs)
815 			return (-1);
816 
817 		/*
818 		 * Make sure there are no unknown flags.
819 		 */
820 		if (KCPC_REQ_VALID_FLAGS(rp->kr_flags) == 0)
821 			return (CPC_REQ_INVALID_FLAGS);
822 	}
823 
824 	return (0);
825 }
826 
827 static struct cb_ops cb_ops = {
828 	kcpc_open,
829 	kcpc_close,
830 	nodev,		/* strategy */
831 	nodev,		/* print */
832 	nodev,		/* dump */
833 	nodev,		/* read */
834 	nodev,		/* write */
835 	kcpc_ioctl,
836 	nodev,		/* devmap */
837 	nodev,		/* mmap */
838 	nodev,		/* segmap */
839 	nochpoll,	/* poll */
840 	ddi_prop_op,
841 	NULL,
842 	D_NEW | D_MP
843 };
844 
845 /*ARGSUSED*/
846 static int
847 kcpc_probe(dev_info_t *devi)
848 {
849 	return (DDI_PROBE_SUCCESS);
850 }
851 
852 static dev_info_t *kcpc_devi;
853 
854 static int
855 kcpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
856 {
857 	if (cmd != DDI_ATTACH)
858 		return (DDI_FAILURE);
859 	kcpc_devi = devi;
860 	return (ddi_create_minor_node(devi, "shared", S_IFCHR,
861 	    KCPC_MINOR_SHARED, DDI_PSEUDO, 0));
862 }
863 
864 /*ARGSUSED*/
865 static int
866 kcpc_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result)
867 {
868 	switch (cmd) {
869 	case DDI_INFO_DEVT2DEVINFO:
870 		switch (getminor((dev_t)arg)) {
871 		case KCPC_MINOR_SHARED:
872 			*result = kcpc_devi;
873 			return (DDI_SUCCESS);
874 		default:
875 			break;
876 		}
877 		break;
878 	case DDI_INFO_DEVT2INSTANCE:
879 		*result = 0;
880 		return (DDI_SUCCESS);
881 	default:
882 		break;
883 	}
884 
885 	return (DDI_FAILURE);
886 }
887 
888 static struct dev_ops dev_ops = {
889 	DEVO_REV,
890 	0,
891 	kcpc_getinfo,
892 	nulldev,		/* identify */
893 	kcpc_probe,
894 	kcpc_attach,
895 	nodev,			/* detach */
896 	nodev,			/* reset */
897 	&cb_ops,
898 	(struct bus_ops *)0
899 };
900 
901 static struct modldrv modldrv = {
902 	&mod_driverops,
903 	"cpc sampling driver v%I%",
904 	&dev_ops
905 };
906 
907 static struct sysent cpc_sysent = {
908 	5,
909 	SE_NOUNLOAD | SE_ARGC | SE_32RVAL1,
910 	cpc
911 };
912 
913 static struct modlsys modlsys = {
914 	&mod_syscallops,
915 	"cpc sampling system call",
916 	&cpc_sysent
917 };
918 
919 #ifdef _SYSCALL32_IMPL
920 static struct modlsys modlsys32 = {
921 	&mod_syscallops32,
922 	"32-bit cpc sampling system call",
923 	&cpc_sysent
924 };
925 #endif
926 
927 static struct modlinkage modl = {
928 	MODREV_1,
929 	&modldrv,
930 	&modlsys,
931 #ifdef _SYSCALL32_IMPL
932 	&modlsys32,
933 #endif
934 };
935 
936 static void
937 kcpc_init(void)
938 {
939 	long hash;
940 
941 	rw_init(&kcpc_cpuctx_lock, NULL, RW_DEFAULT, NULL);
942 	for (hash = 0; hash < CPC_HASH_BUCKETS; hash++)
943 		mutex_init(&kcpc_ctx_llock[hash],
944 		    NULL, MUTEX_DRIVER, (void *)(uintptr_t)15);
945 }
946 
947 static void
948 kcpc_fini(void)
949 {
950 	long hash;
951 
952 	for (hash = 0; hash < CPC_HASH_BUCKETS; hash++)
953 		mutex_destroy(&kcpc_ctx_llock[hash]);
954 	rw_destroy(&kcpc_cpuctx_lock);
955 }
956 
957 int
958 _init(void)
959 {
960 	int ret;
961 
962 	if (kcpc_hw_load_pcbe() != 0)
963 		return (ENOTSUP);
964 
965 	kcpc_init();
966 	if ((ret = mod_install(&modl)) != 0)
967 		kcpc_fini();
968 	return (ret);
969 }
970 
971 int
972 _fini(void)
973 {
974 	int ret;
975 
976 	if ((ret = mod_remove(&modl)) == 0)
977 		kcpc_fini();
978 	return (ret);
979 }
980 
981 int
982 _info(struct modinfo *mi)
983 {
984 	return (mod_info(&modl, mi));
985 }
986