xref: /titanic_51/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c (revision e2e5537f18c3760ce88f9038f7fe8b59cdf3b1d5)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file contains preset event names from the Performance Application
28  * Programming Interface v3.5 which included the following notice:
29  *
30  *                             Copyright (c) 2005,6
31  *                           Innovative Computing Labs
32  *                         Computer Science Department,
33  *                            University of Tennessee,
34  *                                 Knoxville, TN.
35  *                              All Rights Reserved.
36  *
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions are met:
40  *
41  *    * Redistributions of source code must retain the above copyright notice,
42  *      this list of conditions and the following disclaimer.
43  *    * Redistributions in binary form must reproduce the above copyright
44  *      notice, this list of conditions and the following disclaimer in the
45  *      documentation and/or other materials provided with the distribution.
46  *    * Neither the name of the University of Tennessee nor the names of its
47  *      contributors may be used to endorse or promote products derived from
48  *      this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  *
62  *
63  * This open source software license conforms to the BSD License template.
64  */
65 
66 /*
67  * Niagara2 Performance Counter Backend
68  */
69 
70 #include <sys/cpuvar.h>
71 #include <sys/systm.h>
72 #include <sys/archsystm.h>
73 #include <sys/cmn_err.h>
74 #include <sys/cpc_impl.h>
75 #include <sys/cpc_pcbe.h>
76 #include <sys/modctl.h>
77 #include <sys/machsystm.h>
78 #include <sys/sdt.h>
79 #include <sys/niagara2regs.h>
80 #include <sys/hsvc.h>
81 #include <sys/hypervisor_api.h>
82 #include <sys/disp.h>
83 
84 /*LINTLIBRARY*/
85 static int ni2_pcbe_init(void);
86 static uint_t ni2_pcbe_ncounters(void);
87 static const char *ni2_pcbe_impl_name(void);
88 static const char *ni2_pcbe_cpuref(void);
89 static char *ni2_pcbe_list_events(uint_t picnum);
90 static char *ni2_pcbe_list_attrs(void);
91 static uint64_t ni2_pcbe_event_coverage(char *event);
92 static uint64_t ni2_pcbe_overflow_bitmap(void);
93 static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
94     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
95     void *token);
96 static void ni2_pcbe_program(void *token);
97 static void ni2_pcbe_allstop(void);
98 static void ni2_pcbe_sample(void *token);
99 static void ni2_pcbe_free(void *config);
100 
101 extern void ultra_setpcr(uint64_t);
102 extern uint64_t ultra_getpcr(void);
103 extern void ultra_setpic(uint64_t);
104 extern uint64_t ultra_getpic(void);
105 extern uint64_t ultra_gettick(void);
106 extern char cpu_module_name[];
107 
108 pcbe_ops_t ni2_pcbe_ops = {
109 	PCBE_VER_1,
110 	CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE,
111 	ni2_pcbe_ncounters,
112 	ni2_pcbe_impl_name,
113 	ni2_pcbe_cpuref,
114 	ni2_pcbe_list_events,
115 	ni2_pcbe_list_attrs,
116 	ni2_pcbe_event_coverage,
117 	ni2_pcbe_overflow_bitmap,
118 	ni2_pcbe_configure,
119 	ni2_pcbe_program,
120 	ni2_pcbe_allstop,
121 	ni2_pcbe_sample,
122 	ni2_pcbe_free
123 };
124 
125 typedef struct _ni2_pcbe_config {
126 	uint_t		pcbe_picno;	/* 0 for pic0 or 1 for pic1 */
127 	uint32_t	pcbe_evsel;	/* %pcr event code unshifted */
128 	uint32_t	pcbe_flags;	/* hpriv/user/system/priv */
129 	uint32_t	pcbe_pic;	/* unshifted raw %pic value */
130 } ni2_pcbe_config_t;
131 
132 typedef struct _ni2_event {
133 	const char	*name;
134 	const uint32_t	emask;
135 	const uint32_t	emask_valid;	/* Mask of unreserved MASK bits */
136 } ni2_event_t;
137 
138 typedef struct _ni2_generic_event {
139 	char *name;
140 	char *event;
141 } ni2_generic_event_t;
142 
143 #define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_PCR_PRIV_SHIFT)
144 #define	EV_END {NULL, 0, 0}
145 #define	GEN_EV_END {NULL, NULL}
146 
147 static const uint64_t	allstopped = (ULTRA_PCR_PRIVPIC |
148 	CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1);
149 
150 /*
151  * We update this array in the program and allstop routine. The array
152  * is checked in the sample routine to allow us to only perform the
153  * PCR.ht bit check when counting is in progress.
154  */
155 static boolean_t ni2_cpc_counting[NCPU];
156 
157 static ni2_event_t ni2_events[] = {
158 	{ "Idle_strands",			0x000, 0x00 },
159 	{ "Br_completed",			0x201, 0xff },
160 	{ "Br_taken",				0x202, 0xff },
161 	{ "Instr_FGU_arithmetic",		0x204, 0xff },
162 	{ "Instr_ld",				0x208, 0xff },
163 	{ "Instr_st",				0x210, 0xff },
164 	{ "Instr_sw",				0x220, 0xff },
165 	{ "Instr_other",			0x240, 0xff },
166 	{ "Atomics",				0x280, 0xff },
167 	{ "Instr_cnt",				0x2fd, 0xff },
168 	{ "IC_miss",				0x301, 0x33 },
169 	{ "DC_miss",				0x302, 0x33 },
170 	{ "L2_imiss",				0x310, 0x33 },
171 	{ "L2_dmiss_ld",			0x320, 0x33 },
172 	{ "ITLB_HWTW_ref_L2",			0x404, 0x3c },
173 	{ "DTLB_HWTW_ref_L2",			0x408, 0x3c },
174 	{ "ITLB_HWTW_miss_L2",			0x410, 0x3c },
175 	{ "DTLB_HWTW_miss_L2",			0x420, 0x3c },
176 	{ "Stream_ld_to_PCX",			0x501, 0x3f },
177 	{ "Stream_st_to_PCX",			0x502, 0x3f },
178 	{ "CPU_ld_to_PCX",			0x504, 0x3f },
179 	{ "CPU_ifetch_to_PCX",			0x508, 0x3f },
180 	{ "CPU_st_to_PCX",			0x510, 0x3f },
181 	{ "MMU_ld_to_PCX",			0x520, 0x3f },
182 #ifdef KT_IMPL
183 	{ "DES_3DES_op",			0x601, 0xff },
184 	{ "AES_op",				0x602, 0xff },
185 	{ "Kasumi_op",				0x604, 0xff },
186 	{ "MD5_SHA-1_SHA-256_op",		0x608, 0xff },
187 	{ "MA_op",				0x610, 0xff },
188 	{ "CRC_TCPIP_cksum",			0x620, 0xff },
189 	{ "DES_3DES_busy_cycle",		0x701, 0xff },
190 	{ "AES_busy_cycle",			0x702, 0xff },
191 	{ "Kasumi_busy_cycle",			0x704, 0xff },
192 	{ "MD5_SHA-1_SHA-256_busy_cycle",	0x708, 0xff },
193 	{ "MA_busy_cycle",			0x710, 0xff },
194 	{ "CRC_MPA_cksum",			0x720, 0xff },
195 #else
196 	{ "DES_3DES_op",			0x601, 0x3f },
197 	{ "AES_op",				0x602, 0x3f },
198 	{ "RC4_op",				0x604, 0x3f },
199 	{ "MD5_SHA-1_SHA-256_op",		0x608, 0x3f },
200 	{ "MA_op",				0x610, 0x3f },
201 	{ "CRC_TCPIP_cksum",			0x620, 0x3f },
202 	{ "DES_3DES_busy_cycle",		0x701, 0x3f },
203 	{ "AES_busy_cycle",			0x702, 0x3f },
204 	{ "RC4_busy_cycle",			0x704, 0x3f },
205 	{ "MD5_SHA-1_SHA-256_busy_cycle",	0x708, 0x3f },
206 	{ "MA_busy_cycle",			0x710, 0x3f },
207 	{ "CRC_MPA_cksum",			0x720, 0x3f },
208 #endif
209 	{ "ITLB_miss",				0xb04, 0x0c },
210 	{ "DTLB_miss",				0xb08, 0x0c },
211 	{ "TLB_miss",				0xb0c, 0x0c },
212 	EV_END
213 };
214 
215 static ni2_generic_event_t ni2_generic_events[] = {
216 	{ "PAPI_tot_ins",	"Instr_cnt" },
217 	{ "PAPI_l1_dcm",	"DC_miss" },
218 	{ "PAPI_l1_icm",	"IC_miss" },
219 	{ "PAPI_l2_icm",	"L2_imiss" },
220 	{ "PAPI_l2_ldm",	"L2_dmiss_ld" },
221 	{ "PAPI_tlb_dm",	"DTLB_miss" },
222 	{ "PAPI_tlb_im",	"ITLB_miss" },
223 	{ "PAPI_tlb_tm",	"TLB_miss" },
224 	{ "PAPI_br_tkn",	"Br_taken" },
225 	{ "PAPI_br_ins",	"Br_completed" },
226 	{ "PAPI_ld_ins",	"Instr_ld" },
227 	{ "PAPI_sr_ins",	"Instr_st" },
228 	{ "PAPI_fp_ops",	"Instr_FGU_arithmetic" },
229 	{ "PAPI_fp_ins",	"Instr_FGU_arithmetic" },
230 	GEN_EV_END
231 };
232 
233 static char		*evlist;
234 static size_t		evlist_sz;
235 static uint16_t 	pcr_pic0_mask;
236 static uint16_t 	pcr_pic1_mask;
237 
238 #define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
239 			"http://www.sun.com/processors/manuals"
240 
241 #if defined(NIAGARA2_IMPL)
242 static const char	*cpu_impl_name = "UltraSPARC T2";
243 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" "
244 			"for descriptions of these events." CPU_REF_URL;
245 #elif defined(VFALLS_IMPL)
246 static const char	*cpu_impl_name = "UltraSPARC T2+";
247 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" "
248 			"for descriptions of these events." CPU_REF_URL;
249 #elif defined(KT_IMPL)
250 static const char	*cpu_impl_name = "UltraSPARC KT";
251 static const char *cpu_pcbe_ref = "See the \"UltraSPARC KT User's Manual\" "
252 			"for descriptions of these events." CPU_REF_URL;
253 #endif
254 
255 static boolean_t cpu_hsvc_available = B_TRUE;
256 
257 static int
258 ni2_pcbe_init(void)
259 {
260 	ni2_event_t		*evp;
261 	ni2_generic_event_t	*gevp;
262 	int			status;
263 	uint64_t		cpu_hsvc_major;
264 	uint64_t		cpu_hsvc_minor;
265 #if defined(NIAGARA2_IMPL)
266 	uint64_t		hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU;
267 	uint64_t		hsvc_cpu_major = NIAGARA2_HSVC_MAJOR;
268 #elif defined(VFALLS_IMPL)
269 	uint64_t		hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU;
270 	uint64_t		hsvc_cpu_major = VFALLS_HSVC_MAJOR;
271 #elif defined(KT_IMPL)
272 	uint64_t	hsvc_cpu_group = HSVC_GROUP_KT_CPU;
273 	uint64_t	hsvc_cpu_major = KT_HSVC_MAJOR;
274 #endif
275 
276 	pcr_pic0_mask = CPC_PCR_PIC0_MASK;
277 	pcr_pic1_mask = CPC_PCR_PIC1_MASK;
278 
279 	/*
280 	 * Validate API version for Niagara2 specific hypervisor services
281 	 */
282 	status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major,
283 	    &cpu_hsvc_minor);
284 	if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) {
285 		cmn_err(CE_WARN, "hypervisor services not negotiated "
286 		    "or unsupported major number: group: 0x%lx major: 0x%lx "
287 		    "minor: 0x%lx errno: %d", hsvc_cpu_group,
288 		    cpu_hsvc_major, cpu_hsvc_minor, status);
289 		cpu_hsvc_available = B_FALSE;
290 	}
291 
292 	/*
293 	 * Construct event list.
294 	 *
295 	 * First pass:  Calculate size needed. We'll need an additional byte
296 	 *		for the NULL pointer during the last strcat.
297 	 *
298 	 * Second pass: Copy strings.
299 	 */
300 	for (evp = ni2_events; evp->name != NULL; evp++)
301 		evlist_sz += strlen(evp->name) + 1;
302 
303 	for (gevp = ni2_generic_events; gevp->name != NULL; gevp++)
304 		evlist_sz += strlen(gevp->name) + 1;
305 
306 	evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP);
307 	evlist[0] = '\0';
308 
309 	for (evp = ni2_events; evp->name != NULL; evp++) {
310 		(void) strcat(evlist, evp->name);
311 		(void) strcat(evlist, ",");
312 	}
313 
314 	for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) {
315 		(void) strcat(evlist, gevp->name);
316 		(void) strcat(evlist, ",");
317 	}
318 
319 	/*
320 	 * Remove trailing comma.
321 	 */
322 	evlist[evlist_sz - 1] = '\0';
323 
324 	return (0);
325 }
326 
327 static uint_t
328 ni2_pcbe_ncounters(void)
329 {
330 	return (2);
331 }
332 
333 static const char *
334 ni2_pcbe_impl_name(void)
335 {
336 	return (cpu_impl_name);
337 }
338 
339 static const char *
340 ni2_pcbe_cpuref(void)
341 {
342 	return (cpu_pcbe_ref);
343 }
344 
345 static char *
346 ni2_pcbe_list_events(uint_t picnum)
347 {
348 	ASSERT(picnum < cpc_ncounters);
349 
350 	return (evlist);
351 }
352 
353 static char *
354 ni2_pcbe_list_attrs(void)
355 {
356 	if (cpu_hsvc_available == B_TRUE)
357 #if defined(NIAGARA2_IMPL)
358 		return ("hpriv,emask");
359 #elif defined(VFALLS_IMPL)
360 		return ("hpriv,l2ctl,emask");
361 #elif defined(KT_IMPL)
362 		return ("hpriv,l2ctl,emask,sample");
363 #endif
364 	else
365 #if defined(KT_IMPL)
366 		return ("emask,sample");
367 #else
368 		return ("emask");
369 #endif
370 }
371 
372 static ni2_generic_event_t *
373 find_generic_event(char *name)
374 {
375 	ni2_generic_event_t	*gevp;
376 
377 	for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) {
378 		if (strcmp(name, gevp->name) == 0)
379 			return (gevp);
380 	}
381 
382 	return (NULL);
383 }
384 
385 static ni2_event_t *
386 find_event(char *name)
387 {
388 	ni2_event_t		*evp;
389 
390 	for (evp = ni2_events; evp->name != NULL; evp++)
391 		if (strcmp(name, evp->name) == 0)
392 			return (evp);
393 
394 	return (NULL);
395 }
396 
397 /*ARGSUSED*/
398 static uint64_t
399 ni2_pcbe_event_coverage(char *event)
400 {
401 	/*
402 	 * Fortunately, both pic0 and pic1 can count all events.
403 	 */
404 	return (0x3);
405 }
406 
407 static uint64_t
408 ni2_pcbe_overflow_bitmap(void)
409 {
410 	uint64_t	pcr, overflow;
411 	uint64_t	pic;
412 	uint32_t	pic0, pic1;
413 	boolean_t	update_pic = B_FALSE;
414 	boolean_t	pic_inrange = B_FALSE;
415 
416 	ASSERT(getpil() >= DISP_LEVEL);
417 	pcr = ultra_getpcr();
418 	DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
419 	overflow =  (pcr & CPC_PCR_OV0_MASK) >>
420 	    CPC_PCR_OV0_SHIFT;
421 	overflow |=  (pcr & CPC_PCR_OV1_MASK) >>
422 	    CPC_PCR_OV1_SHIFT;
423 
424 	pic = ultra_getpic();
425 	pic0 = (uint32_t)(pic & PIC0_MASK);
426 	pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK);
427 
428 	pcr |= (CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1);
429 
430 	if (overflow & 0x1) {
431 		pcr &= ~(CPC_PCR_OV0_MASK |
432 		    CPC_PCR_HOLDOV0);
433 		pic_inrange = PIC_IN_OV_RANGE(pic0);
434 #if defined(KT_IMPL)
435 		if (pcr & CPC_PCR_SAMPLE_MODE_MASK)
436 			pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic0);
437 #endif
438 		if (pic_inrange) {
439 			pic0 = 0;
440 			update_pic = B_TRUE;
441 		}
442 	}
443 
444 	if (overflow & 0x2) {
445 		pcr &= ~(CPC_PCR_OV1_MASK |
446 		    CPC_PCR_HOLDOV1);
447 		pic_inrange = PIC_IN_OV_RANGE(pic1);
448 #if defined(KT_IMPL)
449 		if (pcr & CPC_PCR_SAMPLE_MODE_MASK)
450 			pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic1);
451 #endif
452 		if (pic_inrange) {
453 			pic1 = 0;
454 			update_pic = B_TRUE;
455 		}
456 	}
457 
458 	if (update_pic)
459 		ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0);
460 
461 	/*
462 	 * The HV interface does not need to be used here because we are
463 	 * only resetting the OV bits and do not need to set the HT bit.
464 	 */
465 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
466 	ultra_setpcr(pcr);
467 
468 	return (overflow);
469 }
470 
471 /*ARGSUSED*/
472 static int
473 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
474     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
475 {
476 	ni2_pcbe_config_t	*cfg;
477 	ni2_pcbe_config_t	*other_config;
478 	ni2_event_t		*evp;
479 	ni2_generic_event_t	*gevp;
480 	int			i;
481 	uint32_t		evsel;
482 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
483 	uint64_t		l2ctl = 0;
484 #endif
485 
486 	/*
487 	 * If we've been handed an existing configuration, we need only preset
488 	 * the counter value.
489 	 */
490 	if (*data != NULL) {
491 		cfg = *data;
492 		cfg->pcbe_pic = (uint32_t)preset;
493 		return (0);
494 	}
495 
496 	if (picnum > 1)
497 		return (CPC_INVALID_PICNUM);
498 
499 
500 	if ((evp = find_event(event)) == NULL) {
501 		if ((gevp = find_generic_event(event)) != NULL) {
502 			evp = find_event(gevp->event);
503 			ASSERT(evp != NULL);
504 
505 			if (nattrs > 0)
506 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
507 		} else {
508 			return (CPC_INVALID_EVENT);
509 		}
510 	}
511 
512 	evsel = evp->emask;
513 
514 	for (i = 0; i < nattrs; i++) {
515 		if (strcmp(attrs[i].ka_name, "hpriv") == 0) {
516 			if (attrs[i].ka_val != 0)
517 				flags |= CPC_COUNT_HV;
518 		} else if (strcmp(attrs[i].ka_name, "emask") == 0) {
519 			if ((attrs[i].ka_val | evp->emask_valid) !=
520 			    evp->emask_valid)
521 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
522 			evsel |= attrs[i].ka_val;
523 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
524 		} else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) {
525 			if ((attrs[i].ka_val | L2_CTL_MASK) !=
526 			    L2_CTL_MASK)
527 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
528 			else
529 				l2ctl = attrs[i].ka_val;
530 #endif
531 #if defined(KT_IMPL)
532 		} else if (strcmp(attrs[i].ka_name, "sample") == 0) {
533 			if (attrs[i].ka_val != 0)
534 				flags |= CPC_COUNT_SAMPLE_MODE;
535 #endif
536 		} else
537 			return (CPC_INVALID_ATTRIBUTE);
538 	}
539 
540 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
541 	/*
542 	 * Set PERF_CONTROL bits in L2_CONTROL_REG only when events have
543 	 * SL bits equal to 3.
544 	 */
545 	if ((evsel & SL3_MASK) == SL3_MASK) {
546 		if ((hv_niagara_setperf(HV_L2_CTL, l2ctl)) != 0)
547 			return (CPC_HV_NO_ACCESS);
548 	}
549 #endif
550 
551 	/*
552 	 * Find other requests that will be programmed with this one, and ensure
553 	 * the flags don't conflict.
554 	 */
555 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
556 	    (other_config->pcbe_flags != flags))
557 		return (CPC_CONFLICTING_REQS);
558 
559 	/*
560 	 * If the hpriv attribute is present, make sure we have
561 	 * access to hyperprivileged events before continuing with
562 	 * this configuration. If we can set the ht bit in the PCR
563 	 * successfully, we must have access to hyperprivileged
564 	 * events.
565 	 *
566 	 * If this is a static per-CPU configuration, the CPC
567 	 * driver ensures there can not be more than one for this
568 	 * CPU. If this is a per-LWP configuration, the driver
569 	 * ensures no static per-CPU counting is ongoing and that
570 	 * the target LWP is not already being monitored.
571 	 */
572 	if (flags & CPC_COUNT_HV) {
573 		kpreempt_disable();
574 
575 		DTRACE_PROBE1(niagara2__setpcr, uint64_t,
576 		    allstopped | CPC_PCR_HT);
577 		if (hv_niagara_setperf(HV_SPARC_CTL,
578 		    allstopped | CPC_PCR_HT) != H_EOK) {
579 			kpreempt_enable();
580 			return (CPC_HV_NO_ACCESS);
581 		}
582 
583 		DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped);
584 		(void) hv_niagara_setperf(HV_SPARC_CTL, allstopped);
585 
586 		kpreempt_enable();
587 	}
588 
589 	cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP);
590 
591 	cfg->pcbe_picno = picnum;
592 	cfg->pcbe_evsel = evsel;
593 	cfg->pcbe_flags = flags;
594 	cfg->pcbe_pic = (uint32_t)preset;
595 
596 	*data = cfg;
597 	return (0);
598 }
599 
600 static void
601 ni2_pcbe_program(void *token)
602 {
603 	ni2_pcbe_config_t	*pic0;
604 	ni2_pcbe_config_t	*pic1;
605 	ni2_pcbe_config_t	*tmp;
606 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
607 	uint64_t		pcr;
608 	uint64_t		curpic;
609 	uint64_t		toe;
610 
611 	/* enable trap-on-event for pic0 and pic1 */
612 	toe = (CPC_PCR_TOE0 | CPC_PCR_TOE1);
613 
614 	if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
615 	    NULL)
616 		panic("ni2_pcbe: token %p has no configs", token);
617 
618 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
619 		pic1 = &nullcfg;
620 		nullcfg.pcbe_flags = pic0->pcbe_flags;
621 		toe = CPC_PCR_TOE0; /* enable trap-on-event for pic0 */
622 	}
623 
624 	if (pic0->pcbe_picno != 0) {
625 		/*
626 		 * pic0 is counter 1, so if we need the null config it should
627 		 * be counter 0.
628 		 */
629 		nullcfg.pcbe_picno = 0;
630 		tmp = pic0;
631 		pic0 = pic1;
632 		pic1 = tmp;
633 		toe = CPC_PCR_TOE1; /* enable trap-on-event for pic1 */
634 	}
635 
636 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
637 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
638 
639 	/*
640 	 * UltraSPARC does not allow pic0 to be configured differently
641 	 * from pic1. If the flags on these two configurations are
642 	 * different, they are incompatible. This condition should be
643 	 * caught at configure time.
644 	 */
645 	ASSERT(pic0->pcbe_flags == pic1->pcbe_flags);
646 
647 	ni2_pcbe_allstop();
648 
649 	ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) |
650 	    (uint64_t)pic0->pcbe_pic);
651 
652 	pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_PCR_PIC0_SHIFT;
653 	pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) <<
654 	    CPC_PCR_PIC1_SHIFT;
655 
656 	if (pic0->pcbe_flags & CPC_COUNT_USER)
657 		pcr |= (1ull << CPC_PCR_UT_SHIFT);
658 	if (pic0->pcbe_flags & CPC_COUNT_SYSTEM)
659 		pcr |= (1ull << CPC_PCR_ST_SHIFT);
660 	if (pic0->pcbe_flags & CPC_COUNT_HV)
661 		pcr |= (1ull << CPC_PCR_HT_SHIFT);
662 #if defined(KT_IMPL)
663 	if (pic0->pcbe_flags & CPC_COUNT_SAMPLE_MODE)
664 		pcr |= (1ull << CPC_PCR_SAMPLE_MODE_SHIFT);
665 #endif
666 	pcr |= toe;
667 
668 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
669 
670 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
671 		/*
672 		 * The ht bit in the PCR is only writable in
673 		 * hyperprivileged mode. So if we are counting
674 		 * hpriv events, we must use the HV interface
675 		 * hv_niagara_setperf to set the PCR. If this
676 		 * fails, assume we no longer have access to
677 		 * hpriv events.
678 		 */
679 		if (hv_niagara_setperf(HV_SPARC_CTL, pcr) != H_EOK) {
680 			kcpc_invalidate_config(token);
681 			return;
682 		}
683 	} else
684 		/* Set the PCR with no hpriv event counting enabled. */
685 		ultra_setpcr(pcr);
686 
687 	ni2_cpc_counting[CPU->cpu_id] = B_TRUE;
688 
689 	/*
690 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
691 	 * expect the value we wrote into the PIC, above, to be there after
692 	 * starting the counter. We must sample the counter value now and use
693 	 * that as the baseline for future samples.
694 	 */
695 	curpic = ultra_getpic();
696 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
697 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
698 
699 	DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic);
700 }
701 
702 static void
703 ni2_pcbe_allstop(void)
704 {
705 	/*
706 	 * We use the HV interface here because if we were counting
707 	 * hyperprivileged events, we must reset the PCR.ht bit to stop
708 	 * the counting. In the event that this HV call fails, we fall
709 	 * back on ultra_setpcr which does not have write access to the
710 	 * ht bit.
711 	 */
712 	if (hv_niagara_setperf(HV_SPARC_CTL, allstopped) != H_EOK)
713 		ultra_setpcr(allstopped);
714 
715 	ni2_cpc_counting[CPU->cpu_id] = B_FALSE;
716 }
717 
718 static void
719 ni2_pcbe_sample(void *token)
720 {
721 	uint64_t		curpic;
722 	int64_t			diff;
723 	uint64_t		*pic0_data;
724 	uint64_t		*pic1_data;
725 	uint64_t		*dtmp;
726 	uint64_t		tmp;
727 	uint64_t		pcr;
728 	ni2_pcbe_config_t	*pic0;
729 	ni2_pcbe_config_t	*pic1;
730 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
731 	ni2_pcbe_config_t	*ctmp;
732 
733 	curpic = ultra_getpic();
734 	DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic);
735 
736 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
737 		panic("%s: token %p has no configs", cpu_impl_name, token);
738 
739 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
740 		pic1 = &nullcfg;
741 		pic1_data = &tmp;
742 	}
743 
744 	if (pic0->pcbe_picno != 0) {
745 		nullcfg.pcbe_picno = 0;
746 		ctmp = pic0;
747 		pic0 = pic1;
748 		pic1 = ctmp;
749 		dtmp = pic0_data;
750 		pic0_data = pic1_data;
751 		pic1_data = dtmp;
752 	}
753 
754 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
755 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
756 
757 
758 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
759 		/*
760 		 * If the hpriv attribute is present, but the HT bit
761 		 * is not set in the PCR, access to hyperprivileged
762 		 * events must have been revoked. Only perform this
763 		 * check if counting is not stopped.
764 		 */
765 		pcr = ultra_getpcr();
766 		DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
767 		if (ni2_cpc_counting[CPU->cpu_id] &&
768 		    !(pcr & CPC_PCR_HT)) {
769 			kcpc_invalidate_config(token);
770 			return;
771 		}
772 	}
773 
774 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic;
775 	if (diff < 0)
776 		diff += (1ll << 32);
777 	*pic0_data += diff;
778 
779 	diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic;
780 	if (diff < 0)
781 		diff += (1ll << 32);
782 	*pic1_data += diff;
783 
784 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
785 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
786 }
787 
788 static void
789 ni2_pcbe_free(void *config)
790 {
791 	kmem_free(config, sizeof (ni2_pcbe_config_t));
792 }
793 
794 
795 static struct modlpcbe modlpcbe = {
796 	&mod_pcbeops,
797 #if defined(NIAGARA2_IMPL)
798 	"UltraSPARC T2 Performance Counters",
799 #elif defined(VFALLS_IMPL)
800 	"UltraSPARC T2+ Performance Counters",
801 #elif defined(KT_IMPL)
802 	"UltraSPARC KT Performance Counters",
803 #endif
804 	&ni2_pcbe_ops
805 };
806 
807 static struct modlinkage modl = {
808 	MODREV_1,
809 	&modlpcbe,
810 };
811 
812 int
813 _init(void)
814 {
815 	if (ni2_pcbe_init() != 0)
816 		return (ENOTSUP);
817 	return (mod_install(&modl));
818 }
819 
820 int
821 _fini(void)
822 {
823 	return (mod_remove(&modl));
824 }
825 
826 int
827 _info(struct modinfo *mi)
828 {
829 	return (mod_info(&modl, mi));
830 }
831