xref: /illumos-gate/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c (revision 8fc99e42676a23421c75e76660640f9765d693b1)
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 2010 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 T3";
251 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T3 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 	 * Check whether counter event is supported
403 	 */
404 	if (find_event(event) == NULL && find_generic_event(event) == NULL)
405 		return (0);
406 
407 	/*
408 	 * Fortunately, both pic0 and pic1 can count all events.
409 	 */
410 	return (0x3);
411 }
412 
413 static uint64_t
414 ni2_pcbe_overflow_bitmap(void)
415 {
416 	uint64_t	pcr, overflow;
417 	uint64_t	pic;
418 	uint32_t	pic0, pic1;
419 	boolean_t	update_pic = B_FALSE;
420 	boolean_t	pic_inrange = B_FALSE;
421 
422 	ASSERT(getpil() >= DISP_LEVEL);
423 	pcr = ultra_getpcr();
424 	DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
425 	overflow =  (pcr & CPC_PCR_OV0_MASK) >>
426 	    CPC_PCR_OV0_SHIFT;
427 	overflow |=  (pcr & CPC_PCR_OV1_MASK) >>
428 	    CPC_PCR_OV1_SHIFT;
429 
430 	pic = ultra_getpic();
431 	pic0 = (uint32_t)(pic & PIC0_MASK);
432 	pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK);
433 
434 	pcr |= (CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1);
435 
436 	if (overflow & 0x1) {
437 		pcr &= ~(CPC_PCR_OV0_MASK |
438 		    CPC_PCR_HOLDOV0);
439 		pic_inrange = PIC_IN_OV_RANGE(pic0);
440 #if defined(KT_IMPL)
441 		if (pcr & CPC_PCR_SAMPLE_MODE_MASK)
442 			pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic0);
443 #endif
444 		if (pic_inrange) {
445 			pic0 = 0;
446 			update_pic = B_TRUE;
447 		}
448 	}
449 
450 	if (overflow & 0x2) {
451 		pcr &= ~(CPC_PCR_OV1_MASK |
452 		    CPC_PCR_HOLDOV1);
453 		pic_inrange = PIC_IN_OV_RANGE(pic1);
454 #if defined(KT_IMPL)
455 		if (pcr & CPC_PCR_SAMPLE_MODE_MASK)
456 			pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic1);
457 #endif
458 		if (pic_inrange) {
459 			pic1 = 0;
460 			update_pic = B_TRUE;
461 		}
462 	}
463 
464 	if (update_pic)
465 		ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0);
466 
467 	/*
468 	 * The HV interface does not need to be used here because we are
469 	 * only resetting the OV bits and do not need to set the HT bit.
470 	 */
471 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
472 	ultra_setpcr(pcr);
473 
474 	return (overflow);
475 }
476 
477 /*ARGSUSED*/
478 static int
479 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
480     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
481 {
482 	ni2_pcbe_config_t	*cfg;
483 	ni2_pcbe_config_t	*other_config;
484 	ni2_event_t		*evp;
485 	ni2_generic_event_t	*gevp;
486 	int			i;
487 	uint32_t		evsel;
488 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
489 	uint64_t		l2ctl = 0;
490 #endif
491 
492 	/*
493 	 * If we've been handed an existing configuration, we need only preset
494 	 * the counter value.
495 	 */
496 	if (*data != NULL) {
497 		cfg = *data;
498 		cfg->pcbe_pic = (uint32_t)preset;
499 		return (0);
500 	}
501 
502 	if (picnum > 1)
503 		return (CPC_INVALID_PICNUM);
504 
505 
506 	if ((evp = find_event(event)) == NULL) {
507 		if ((gevp = find_generic_event(event)) != NULL) {
508 			evp = find_event(gevp->event);
509 			ASSERT(evp != NULL);
510 
511 			if (nattrs > 0)
512 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
513 		} else {
514 			return (CPC_INVALID_EVENT);
515 		}
516 	}
517 
518 	evsel = evp->emask;
519 
520 	for (i = 0; i < nattrs; i++) {
521 		if (strcmp(attrs[i].ka_name, "hpriv") == 0) {
522 			if (attrs[i].ka_val != 0)
523 				flags |= CPC_COUNT_HV;
524 		} else if (strcmp(attrs[i].ka_name, "emask") == 0) {
525 			if ((attrs[i].ka_val | evp->emask_valid) !=
526 			    evp->emask_valid)
527 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
528 			evsel |= attrs[i].ka_val;
529 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
530 		} else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) {
531 			if ((attrs[i].ka_val | L2_CTL_MASK) !=
532 			    L2_CTL_MASK)
533 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
534 			else
535 				l2ctl = attrs[i].ka_val;
536 #endif
537 #if defined(KT_IMPL)
538 		} else if (strcmp(attrs[i].ka_name, "sample") == 0) {
539 			if (attrs[i].ka_val != 0)
540 				flags |= CPC_COUNT_SAMPLE_MODE;
541 #endif
542 		} else
543 			return (CPC_INVALID_ATTRIBUTE);
544 	}
545 
546 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
547 	/*
548 	 * Set PERF_CONTROL bits in L2_CONTROL_REG only when events have
549 	 * SL bits equal to 3.
550 	 */
551 	if ((evsel & SL3_MASK) == SL3_MASK) {
552 		if ((hv_niagara_setperf(HV_L2_CTL, l2ctl)) != 0)
553 			return (CPC_HV_NO_ACCESS);
554 	}
555 #endif
556 
557 	/*
558 	 * Find other requests that will be programmed with this one, and ensure
559 	 * the flags don't conflict.
560 	 */
561 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
562 	    (other_config->pcbe_flags != flags))
563 		return (CPC_CONFLICTING_REQS);
564 
565 	/*
566 	 * If the hpriv attribute is present, make sure we have
567 	 * access to hyperprivileged events before continuing with
568 	 * this configuration. If we can set the ht bit in the PCR
569 	 * successfully, we must have access to hyperprivileged
570 	 * events.
571 	 *
572 	 * If this is a static per-CPU configuration, the CPC
573 	 * driver ensures there can not be more than one for this
574 	 * CPU. If this is a per-LWP configuration, the driver
575 	 * ensures no static per-CPU counting is ongoing and that
576 	 * the target LWP is not already being monitored.
577 	 */
578 	if (flags & CPC_COUNT_HV) {
579 		kpreempt_disable();
580 
581 		DTRACE_PROBE1(niagara2__setpcr, uint64_t,
582 		    allstopped | CPC_PCR_HT);
583 		if (hv_niagara_setperf(HV_SPARC_CTL,
584 		    allstopped | CPC_PCR_HT) != H_EOK) {
585 			kpreempt_enable();
586 			return (CPC_HV_NO_ACCESS);
587 		}
588 
589 		DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped);
590 		(void) hv_niagara_setperf(HV_SPARC_CTL, allstopped);
591 
592 		kpreempt_enable();
593 	}
594 
595 	cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP);
596 
597 	cfg->pcbe_picno = picnum;
598 	cfg->pcbe_evsel = evsel;
599 	cfg->pcbe_flags = flags;
600 	cfg->pcbe_pic = (uint32_t)preset;
601 
602 	*data = cfg;
603 	return (0);
604 }
605 
606 static void
607 ni2_pcbe_program(void *token)
608 {
609 	ni2_pcbe_config_t	*pic0;
610 	ni2_pcbe_config_t	*pic1;
611 	ni2_pcbe_config_t	*tmp;
612 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
613 	uint64_t		pcr;
614 	uint64_t		curpic;
615 	uint64_t		toe;
616 
617 	/* enable trap-on-event for pic0 and pic1 */
618 	toe = (CPC_PCR_TOE0 | CPC_PCR_TOE1);
619 
620 	if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
621 	    NULL)
622 		panic("ni2_pcbe: token %p has no configs", token);
623 
624 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
625 		pic1 = &nullcfg;
626 		nullcfg.pcbe_flags = pic0->pcbe_flags;
627 		toe = CPC_PCR_TOE0; /* enable trap-on-event for pic0 */
628 	}
629 
630 	if (pic0->pcbe_picno != 0) {
631 		/*
632 		 * pic0 is counter 1, so if we need the null config it should
633 		 * be counter 0.
634 		 */
635 		nullcfg.pcbe_picno = 0;
636 		tmp = pic0;
637 		pic0 = pic1;
638 		pic1 = tmp;
639 		toe = CPC_PCR_TOE1; /* enable trap-on-event for pic1 */
640 	}
641 
642 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
643 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
644 
645 	/*
646 	 * UltraSPARC does not allow pic0 to be configured differently
647 	 * from pic1. If the flags on these two configurations are
648 	 * different, they are incompatible. This condition should be
649 	 * caught at configure time.
650 	 */
651 	ASSERT(pic0->pcbe_flags == pic1->pcbe_flags);
652 
653 	ni2_pcbe_allstop();
654 
655 	ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) |
656 	    (uint64_t)pic0->pcbe_pic);
657 
658 	pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_PCR_PIC0_SHIFT;
659 	pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) <<
660 	    CPC_PCR_PIC1_SHIFT;
661 
662 	if (pic0->pcbe_flags & CPC_COUNT_USER)
663 		pcr |= (1ull << CPC_PCR_UT_SHIFT);
664 	if (pic0->pcbe_flags & CPC_COUNT_SYSTEM)
665 		pcr |= (1ull << CPC_PCR_ST_SHIFT);
666 	if (pic0->pcbe_flags & CPC_COUNT_HV)
667 		pcr |= (1ull << CPC_PCR_HT_SHIFT);
668 #if defined(KT_IMPL)
669 	if (pic0->pcbe_flags & CPC_COUNT_SAMPLE_MODE)
670 		pcr |= (1ull << CPC_PCR_SAMPLE_MODE_SHIFT);
671 #endif
672 	pcr |= toe;
673 
674 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
675 
676 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
677 		/*
678 		 * The ht bit in the PCR is only writable in
679 		 * hyperprivileged mode. So if we are counting
680 		 * hpriv events, we must use the HV interface
681 		 * hv_niagara_setperf to set the PCR. If this
682 		 * fails, assume we no longer have access to
683 		 * hpriv events.
684 		 */
685 		if (hv_niagara_setperf(HV_SPARC_CTL, pcr) != H_EOK) {
686 			kcpc_invalidate_config(token);
687 			return;
688 		}
689 	} else
690 		/* Set the PCR with no hpriv event counting enabled. */
691 		ultra_setpcr(pcr);
692 
693 	ni2_cpc_counting[CPU->cpu_id] = B_TRUE;
694 
695 	/*
696 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
697 	 * expect the value we wrote into the PIC, above, to be there after
698 	 * starting the counter. We must sample the counter value now and use
699 	 * that as the baseline for future samples.
700 	 */
701 	curpic = ultra_getpic();
702 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
703 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
704 
705 	DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic);
706 }
707 
708 static void
709 ni2_pcbe_allstop(void)
710 {
711 	/*
712 	 * We use the HV interface here because if we were counting
713 	 * hyperprivileged events, we must reset the PCR.ht bit to stop
714 	 * the counting. In the event that this HV call fails, we fall
715 	 * back on ultra_setpcr which does not have write access to the
716 	 * ht bit.
717 	 */
718 	if (hv_niagara_setperf(HV_SPARC_CTL, allstopped) != H_EOK)
719 		ultra_setpcr(allstopped);
720 
721 	ni2_cpc_counting[CPU->cpu_id] = B_FALSE;
722 }
723 
724 static void
725 ni2_pcbe_sample(void *token)
726 {
727 	uint64_t		curpic;
728 	int64_t			diff;
729 	uint64_t		*pic0_data;
730 	uint64_t		*pic1_data;
731 	uint64_t		*dtmp;
732 	uint64_t		tmp;
733 	uint64_t		pcr;
734 	ni2_pcbe_config_t	*pic0;
735 	ni2_pcbe_config_t	*pic1;
736 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
737 	ni2_pcbe_config_t	*ctmp;
738 
739 	curpic = ultra_getpic();
740 	DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic);
741 
742 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
743 		panic("%s: token %p has no configs", cpu_impl_name, token);
744 
745 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
746 		pic1 = &nullcfg;
747 		pic1_data = &tmp;
748 	}
749 
750 	if (pic0->pcbe_picno != 0) {
751 		nullcfg.pcbe_picno = 0;
752 		ctmp = pic0;
753 		pic0 = pic1;
754 		pic1 = ctmp;
755 		dtmp = pic0_data;
756 		pic0_data = pic1_data;
757 		pic1_data = dtmp;
758 	}
759 
760 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
761 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
762 
763 
764 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
765 		/*
766 		 * If the hpriv attribute is present, but the HT bit
767 		 * is not set in the PCR, access to hyperprivileged
768 		 * events must have been revoked. Only perform this
769 		 * check if counting is not stopped.
770 		 */
771 		pcr = ultra_getpcr();
772 		DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
773 		if (ni2_cpc_counting[CPU->cpu_id] &&
774 		    !(pcr & CPC_PCR_HT)) {
775 			kcpc_invalidate_config(token);
776 			return;
777 		}
778 	}
779 
780 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic;
781 	if (diff < 0)
782 		diff += (1ll << 32);
783 	*pic0_data += diff;
784 
785 	diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic;
786 	if (diff < 0)
787 		diff += (1ll << 32);
788 	*pic1_data += diff;
789 
790 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
791 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
792 }
793 
794 static void
795 ni2_pcbe_free(void *config)
796 {
797 	kmem_free(config, sizeof (ni2_pcbe_config_t));
798 }
799 
800 
801 static struct modlpcbe modlpcbe = {
802 	&mod_pcbeops,
803 #if defined(NIAGARA2_IMPL)
804 	"UltraSPARC T2 Performance Counters",
805 #elif defined(VFALLS_IMPL)
806 	"UltraSPARC T2+ Performance Counters",
807 #elif defined(KT_IMPL)
808 	"UltraSPARC T3 Performance Counters",
809 #endif
810 	&ni2_pcbe_ops
811 };
812 
813 static struct modlinkage modl = {
814 	MODREV_1,
815 	&modlpcbe,
816 };
817 
818 int
819 _init(void)
820 {
821 	if (ni2_pcbe_init() != 0)
822 		return (ENOTSUP);
823 	return (mod_install(&modl));
824 }
825 
826 int
827 _fini(void)
828 {
829 	return (mod_remove(&modl));
830 }
831 
832 int
833 _info(struct modinfo *mi)
834 {
835 	return (mod_info(&modl, mi));
836 }
837