xref: /illumos-gate/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c (revision 7800901e60d340b6af88e94a2149805dcfcaaf56)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Niagara2 Performance Counter Backend
28  */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <sys/cpuvar.h>
33 #include <sys/systm.h>
34 #include <sys/archsystm.h>
35 #include <sys/cmn_err.h>
36 #include <sys/cpc_impl.h>
37 #include <sys/cpc_pcbe.h>
38 #include <sys/modctl.h>
39 #include <sys/machsystm.h>
40 #include <sys/sdt.h>
41 #include <sys/niagara2regs.h>
42 #include <sys/hsvc.h>
43 #include <sys/hypervisor_api.h>
44 #include <sys/disp.h>
45 
46 /*LINTLIBRARY*/
47 static int ni2_pcbe_init(void);
48 static uint_t ni2_pcbe_ncounters(void);
49 static const char *ni2_pcbe_impl_name(void);
50 static const char *ni2_pcbe_cpuref(void);
51 static char *ni2_pcbe_list_events(uint_t picnum);
52 static char *ni2_pcbe_list_attrs(void);
53 static uint64_t ni2_pcbe_event_coverage(char *event);
54 static uint64_t ni2_pcbe_overflow_bitmap(void);
55 static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
56     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
57     void *token);
58 static void ni2_pcbe_program(void *token);
59 static void ni2_pcbe_allstop(void);
60 static void ni2_pcbe_sample(void *token);
61 static void ni2_pcbe_free(void *config);
62 
63 extern void ultra_setpcr(uint64_t);
64 extern uint64_t ultra_getpcr(void);
65 extern void ultra_setpic(uint64_t);
66 extern uint64_t ultra_getpic(void);
67 extern uint64_t ultra_gettick(void);
68 extern char cpu_module_name[];
69 
70 pcbe_ops_t ni2_pcbe_ops = {
71 	PCBE_VER_1,
72 	CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE,
73 	ni2_pcbe_ncounters,
74 	ni2_pcbe_impl_name,
75 	ni2_pcbe_cpuref,
76 	ni2_pcbe_list_events,
77 	ni2_pcbe_list_attrs,
78 	ni2_pcbe_event_coverage,
79 	ni2_pcbe_overflow_bitmap,
80 	ni2_pcbe_configure,
81 	ni2_pcbe_program,
82 	ni2_pcbe_allstop,
83 	ni2_pcbe_sample,
84 	ni2_pcbe_free
85 };
86 
87 typedef struct _ni2_pcbe_config {
88 	uint_t		pcbe_picno;	/* 0 for pic0 or 1 for pic1 */
89 	uint32_t	pcbe_evsel;	/* %pcr event code unshifted */
90 	uint32_t	pcbe_flags;	/* hpriv/user/system/priv */
91 	uint32_t	pcbe_pic;	/* unshifted raw %pic value */
92 } ni2_pcbe_config_t;
93 
94 typedef struct _ni2_event {
95 	const char	*name;
96 	const uint32_t	emask;
97 	const uint32_t	emask_valid;	/* Mask of unreserved MASK bits */
98 } ni2_event_t;
99 
100 #define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_NIAGARA2_PCR_PRIV_SHIFT)
101 #define	EV_END {NULL, 0, 0}
102 
103 static const uint64_t	allstopped = (ULTRA_PCR_PRIVPIC |
104 	CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1);
105 
106 /*
107  * We update this array in the program and allstop routine. The array
108  * is checked in the sample routine to allow us to only perform the
109  * PCR.ht bit check when counting is in progress.
110  */
111 static boolean_t ni2_cpc_counting[NCPU];
112 
113 static ni2_event_t ni2_events[] = {
114 	{ "Idle_strands",			0x000, 0x00 },
115 	{ "Br_completed",			0x201, 0xff },
116 	{ "Br_taken",				0x202, 0xff },
117 	{ "Instr_FGU_arithmetic",		0x204, 0xff },
118 	{ "Instr_ld",				0x208, 0xff },
119 	{ "Instr_st",				0x210, 0xff },
120 	{ "Instr_sw",				0x220, 0xff },
121 	{ "Instr_other",			0x240, 0xff },
122 	{ "Atomics",				0x280, 0xff },
123 	{ "Instr_cnt",				0x2fd, 0xff },
124 	{ "IC_miss",				0x301, 0x33 },
125 	{ "DC_miss",				0x302, 0x33 },
126 	{ "L2_imiss",				0x310, 0x33 },
127 	{ "L2_dmiss_ld",			0x320, 0x33 },
128 	{ "ITLB_HWTW_ref_L2",			0x404, 0x3c },
129 	{ "DTLB_HWTW_ref_L2",			0x408, 0x3c },
130 	{ "ITLB_HWTW_miss_L2",			0x410, 0x3c },
131 	{ "DTLB_HWTW_miss_L2",			0x420, 0x3c },
132 	{ "Stream_ld_to_PCX",			0x501, 0x3f },
133 	{ "Stream_st_to_PCX",			0x502, 0x3f },
134 	{ "CPU_ld_to_PCX",			0x504, 0x3f },
135 	{ "CPU_ifetch_to_PCX",			0x508, 0x3f },
136 	{ "CPU_st_to_PCX",			0x510, 0x3f },
137 	{ "MMU_ld_to_PCX",			0x520, 0x3f },
138 	{ "DES_3DES_op",			0x601, 0x3f },
139 	{ "AES_op",				0x602, 0x3f },
140 	{ "RC4_op",				0x604, 0x3f },
141 	{ "MD5_SHA-1_SHA-256_op",		0x608, 0x3f },
142 	{ "MA_op",				0x610, 0x3f },
143 	{ "CRC_TCPIP_cksum",			0x620, 0x3f },
144 	{ "DES_3DES_busy_cycle",		0x701, 0x3f },
145 	{ "AES_busy_cycle",			0x702, 0x3f },
146 	{ "RC4_busy_cycle",			0x704, 0x3f },
147 	{ "MD5_SHA-1_SHA-256_busy_cycle",	0x708, 0x3f },
148 	{ "MA_busy_cycle",			0x710, 0x3f },
149 	{ "CRC_MPA_cksum",			0x720, 0x3f },
150 	{ "ITLB_miss",				0xb04, 0x0c },
151 	{ "DTLB_miss",				0xb08, 0x0c },
152 	{ "TLB_miss",				0xb0c, 0x0c },
153 	EV_END
154 };
155 
156 static char		*evlist;
157 static size_t		evlist_sz;
158 static uint16_t 	pcr_pic0_mask;
159 static uint16_t 	pcr_pic1_mask;
160 
161 #define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
162 			"http://www.sun.com/processors/manuals"
163 
164 #if defined(NIAGARA2_IMPL)
165 static const char	*cpu_impl_name = "UltraSPARC T2";
166 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" "
167 			"for descriptions of these events." CPU_REF_URL;
168 #elif defined(VFALLS_IMPL)
169 static const char	*cpu_impl_name = "UltraSPARC T2+";
170 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" "
171 			"for descriptions of these events." CPU_REF_URL;
172 #endif
173 
174 static boolean_t cpu_hsvc_available = B_TRUE;
175 
176 static int
177 ni2_pcbe_init(void)
178 {
179 	ni2_event_t	*evp;
180 	int		status;
181 	uint64_t	cpu_hsvc_major;
182 	uint64_t	cpu_hsvc_minor;
183 #if defined(NIAGARA2_IMPL)
184 	uint64_t	hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU;
185 	uint64_t	hsvc_cpu_major = NIAGARA2_HSVC_MAJOR;
186 #elif defined(VFALLS_IMPL)
187 	uint64_t	hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU;
188 	uint64_t	hsvc_cpu_major = VFALLS_HSVC_MAJOR;
189 #endif
190 
191 	pcr_pic0_mask = CPC_NIAGARA2_PCR_PIC0_MASK;
192 	pcr_pic1_mask = CPC_NIAGARA2_PCR_PIC1_MASK;
193 
194 	/*
195 	 * Validate API version for Niagara2 specific hypervisor services
196 	 */
197 	status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major,
198 	    &cpu_hsvc_minor);
199 	if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) {
200 		cmn_err(CE_WARN, "hypervisor services not negotiated "
201 		    "or unsupported major number: group: 0x%lx major: 0x%lx "
202 		    "minor: 0x%lx errno: %d", hsvc_cpu_group,
203 		    cpu_hsvc_major, cpu_hsvc_minor, status);
204 		cpu_hsvc_available = B_FALSE;
205 	}
206 
207 	/*
208 	 * Construct event list.
209 	 *
210 	 * First pass:  Calculate size needed. We'll need an additional byte
211 	 *		for the NULL pointer during the last strcat.
212 	 *
213 	 * Second pass: Copy strings.
214 	 */
215 	for (evp = ni2_events; evp->name != NULL; evp++)
216 		evlist_sz += strlen(evp->name) + 1;
217 
218 	evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP);
219 	evlist[0] = '\0';
220 
221 	for (evp = ni2_events; evp->name != NULL; evp++) {
222 		(void) strcat(evlist, evp->name);
223 		(void) strcat(evlist, ",");
224 	}
225 	/*
226 	 * Remove trailing comma.
227 	 */
228 	evlist[evlist_sz - 1] = '\0';
229 
230 	return (0);
231 }
232 
233 static uint_t
234 ni2_pcbe_ncounters(void)
235 {
236 	return (2);
237 }
238 
239 static const char *
240 ni2_pcbe_impl_name(void)
241 {
242 	return (cpu_impl_name);
243 }
244 
245 static const char *
246 ni2_pcbe_cpuref(void)
247 {
248 	return (cpu_pcbe_ref);
249 }
250 
251 static char *
252 ni2_pcbe_list_events(uint_t picnum)
253 {
254 	ASSERT(picnum < cpc_ncounters);
255 
256 	return (evlist);
257 }
258 
259 static char *
260 ni2_pcbe_list_attrs(void)
261 {
262 	if (cpu_hsvc_available == B_TRUE)
263 #if defined(NIAGARA2_IMPL)
264 		return ("hpriv,emask");
265 #elif defined(VFALLS_IMPL)
266 		return ("hpriv,l2ctl,emask");
267 #endif
268 	else
269 		return ("emask");
270 }
271 
272 static ni2_event_t *
273 find_event(char *name)
274 {
275 	ni2_event_t	*evp;
276 
277 	for (evp = ni2_events; evp->name != NULL; evp++)
278 		if (strcmp(name, evp->name) == 0)
279 			return (evp);
280 
281 	return (NULL);
282 }
283 
284 /*ARGSUSED*/
285 static uint64_t
286 ni2_pcbe_event_coverage(char *event)
287 {
288 	/*
289 	 * Fortunately, both pic0 and pic1 can count all events.
290 	 */
291 	return (0x3);
292 }
293 
294 static uint64_t
295 ni2_pcbe_overflow_bitmap(void)
296 {
297 	uint64_t	pcr, overflow;
298 	uint64_t	pic;
299 	uint32_t	pic0, pic1;
300 	boolean_t	update_pic = B_FALSE;
301 
302 	ASSERT(getpil() >= DISP_LEVEL);
303 	pcr = ultra_getpcr();
304 	DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
305 	overflow =  (pcr & CPC_NIAGARA2_PCR_OV0_MASK) >>
306 	    CPC_NIAGARA2_PCR_OV0_SHIFT;
307 	overflow |=  (pcr & CPC_NIAGARA2_PCR_OV1_MASK) >>
308 	    CPC_NIAGARA2_PCR_OV1_SHIFT;
309 
310 	pic = ultra_getpic();
311 	pic0 = (uint32_t)(pic & PIC0_MASK);
312 	pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK);
313 
314 	pcr |= (CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1);
315 
316 	if (overflow & 0x1) {
317 		pcr &= ~(CPC_NIAGARA2_PCR_OV0_MASK |
318 		    CPC_NIAGARA2_PCR_HOLDOV0);
319 		if (PIC_IN_OV_RANGE(pic0)) {
320 			pic0 = 0;
321 			update_pic = B_TRUE;
322 		}
323 	}
324 
325 	if (overflow & 0x2) {
326 		pcr &= ~(CPC_NIAGARA2_PCR_OV1_MASK |
327 		    CPC_NIAGARA2_PCR_HOLDOV1);
328 		if (PIC_IN_OV_RANGE(pic1)) {
329 			pic1 = 0;
330 			update_pic = B_TRUE;
331 		}
332 	}
333 
334 	if (update_pic)
335 		ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0);
336 
337 	/*
338 	 * The HV interface does not need to be used here because we are
339 	 * only resetting the OV bits and do not need to set the HT bit.
340 	 */
341 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
342 	ultra_setpcr(pcr);
343 
344 	return (overflow);
345 }
346 
347 /*ARGSUSED*/
348 static int
349 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
350     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
351 {
352 	ni2_pcbe_config_t	*cfg;
353 	ni2_pcbe_config_t	*other_config;
354 	ni2_event_t		*evp;
355 	int			i;
356 	uint32_t		evsel;
357 
358 	/*
359 	 * If we've been handed an existing configuration, we need only preset
360 	 * the counter value.
361 	 */
362 	if (*data != NULL) {
363 		cfg = *data;
364 		cfg->pcbe_pic = (uint32_t)preset;
365 		return (0);
366 	}
367 
368 	if (picnum > 1)
369 		return (CPC_INVALID_PICNUM);
370 
371 	if ((evp = find_event(event)) == NULL)
372 		return (CPC_INVALID_EVENT);
373 
374 	evsel = evp->emask;
375 
376 	for (i = 0; i < nattrs; i++) {
377 		if (strcmp(attrs[i].ka_name, "hpriv") == 0) {
378 			if (attrs[i].ka_val != 0)
379 				flags |= CPC_COUNT_HV;
380 		} else if (strcmp(attrs[i].ka_name, "emask") == 0) {
381 			if ((attrs[i].ka_val | evp->emask_valid) !=
382 			    evp->emask_valid)
383 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
384 			evsel |= attrs[i].ka_val;
385 #if defined(VFALLS_IMPL)
386 		} else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) {
387 			if ((attrs[i].ka_val | VFALLS_L2_CTL_MASK) !=
388 			    VFALLS_L2_CTL_MASK)
389 				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
390 			/*
391 			 * Set PERF_CONTROL bits in L2_CONTROL_REG
392 			 * only when events have SL bits equal to 3.
393 			 */
394 			if ((evsel & VFALLS_SL3_MASK) == VFALLS_SL3_MASK) {
395 				if ((hv_niagara_setperf(HV_NIAGARA_L2_CTL,
396 				    attrs[i].ka_val)) != 0)
397 					return (CPC_HV_NO_ACCESS);
398 			}
399 #endif
400 		} else
401 			return (CPC_INVALID_ATTRIBUTE);
402 	}
403 
404 	/*
405 	 * Find other requests that will be programmed with this one, and ensure
406 	 * the flags don't conflict.
407 	 */
408 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
409 	    (other_config->pcbe_flags != flags))
410 		return (CPC_CONFLICTING_REQS);
411 
412 	/*
413 	 * If the hpriv attribute is present, make sure we have
414 	 * access to hyperprivileged events before continuing with
415 	 * this configuration. If we can set the ht bit in the PCR
416 	 * successfully, we must have access to hyperprivileged
417 	 * events.
418 	 *
419 	 * If this is a static per-CPU configuration, the CPC
420 	 * driver ensures there can not be more than one for this
421 	 * CPU. If this is a per-LWP configuration, the driver
422 	 * ensures no static per-CPU counting is ongoing and that
423 	 * the target LWP is not already being monitored.
424 	 */
425 	if (flags & CPC_COUNT_HV) {
426 		kpreempt_disable();
427 
428 		DTRACE_PROBE1(niagara2__setpcr, uint64_t,
429 		    allstopped | CPC_NIAGARA2_PCR_HT);
430 		if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL,
431 		    allstopped | CPC_NIAGARA2_PCR_HT) != H_EOK) {
432 			kpreempt_enable();
433 			return (CPC_HV_NO_ACCESS);
434 		}
435 
436 		DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped);
437 		(void) hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped);
438 
439 		kpreempt_enable();
440 	}
441 
442 	cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP);
443 
444 	cfg->pcbe_picno = picnum;
445 	cfg->pcbe_evsel = evsel;
446 	cfg->pcbe_flags = flags;
447 	cfg->pcbe_pic = (uint32_t)preset;
448 
449 	*data = cfg;
450 	return (0);
451 }
452 
453 static void
454 ni2_pcbe_program(void *token)
455 {
456 	ni2_pcbe_config_t	*pic0;
457 	ni2_pcbe_config_t	*pic1;
458 	ni2_pcbe_config_t	*tmp;
459 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
460 	uint64_t		pcr;
461 	uint64_t		curpic;
462 	uint64_t		toe;
463 
464 	/* enable trap-on-event for pic0 and pic1 */
465 	toe = (CPC_NIAGARA2_PCR_TOE0 | CPC_NIAGARA2_PCR_TOE1);
466 
467 	if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
468 	    NULL)
469 		panic("ni2_pcbe: token %p has no configs", token);
470 
471 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
472 		pic1 = &nullcfg;
473 		nullcfg.pcbe_flags = pic0->pcbe_flags;
474 		toe = CPC_NIAGARA2_PCR_TOE0; /* enable trap-on-event for pic0 */
475 	}
476 
477 	if (pic0->pcbe_picno != 0) {
478 		/*
479 		 * pic0 is counter 1, so if we need the null config it should
480 		 * be counter 0.
481 		 */
482 		nullcfg.pcbe_picno = 0;
483 		tmp = pic0;
484 		pic0 = pic1;
485 		pic1 = tmp;
486 		toe = CPC_NIAGARA2_PCR_TOE1; /* enable trap-on-event for pic1 */
487 	}
488 
489 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
490 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
491 
492 	/*
493 	 * UltraSPARC does not allow pic0 to be configured differently
494 	 * from pic1. If the flags on these two configurations are
495 	 * different, they are incompatible. This condition should be
496 	 * caught at configure time.
497 	 */
498 	ASSERT(pic0->pcbe_flags == pic1->pcbe_flags);
499 
500 	ni2_pcbe_allstop();
501 
502 	ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) |
503 	    (uint64_t)pic0->pcbe_pic);
504 
505 	pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_NIAGARA2_PCR_PIC0_SHIFT;
506 	pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) <<
507 	    CPC_NIAGARA2_PCR_PIC1_SHIFT;
508 
509 	if (pic0->pcbe_flags & CPC_COUNT_USER)
510 		pcr |= (1ull << CPC_NIAGARA2_PCR_UT_SHIFT);
511 	if (pic0->pcbe_flags & CPC_COUNT_SYSTEM)
512 		pcr |= (1ull << CPC_NIAGARA2_PCR_ST_SHIFT);
513 	if (pic0->pcbe_flags & CPC_COUNT_HV)
514 		pcr |= (1ull << CPC_NIAGARA2_PCR_HT_SHIFT);
515 	pcr |= toe;
516 
517 	DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr);
518 
519 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
520 		/*
521 		 * The ht bit in the PCR is only writable in
522 		 * hyperprivileged mode. So if we are counting
523 		 * hpriv events, we must use the HV interface
524 		 * hv_niagara_setperf to set the PCR. If this
525 		 * fails, assume we no longer have access to
526 		 * hpriv events.
527 		 */
528 		if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != H_EOK) {
529 			kcpc_invalidate_config(token);
530 			return;
531 		}
532 	} else
533 		/* Set the PCR with no hpriv event counting enabled. */
534 		ultra_setpcr(pcr);
535 
536 	ni2_cpc_counting[CPU->cpu_id] = B_TRUE;
537 
538 	/*
539 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
540 	 * expect the value we wrote into the PIC, above, to be there after
541 	 * starting the counter. We must sample the counter value now and use
542 	 * that as the baseline for future samples.
543 	 */
544 	curpic = ultra_getpic();
545 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
546 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
547 
548 	DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic);
549 }
550 
551 static void
552 ni2_pcbe_allstop(void)
553 {
554 	/*
555 	 * We use the HV interface here because if we were counting
556 	 * hyperprivileged events, we must reset the PCR.ht bit to stop
557 	 * the counting. In the event that this HV call fails, we fall
558 	 * back on ultra_setpcr which does not have write access to the
559 	 * ht bit.
560 	 */
561 	if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped) != H_EOK)
562 		ultra_setpcr(allstopped);
563 
564 	ni2_cpc_counting[CPU->cpu_id] = B_FALSE;
565 }
566 
567 static void
568 ni2_pcbe_sample(void *token)
569 {
570 	uint64_t		curpic;
571 	int64_t			diff;
572 	uint64_t		*pic0_data;
573 	uint64_t		*pic1_data;
574 	uint64_t		*dtmp;
575 	uint64_t		tmp;
576 	uint64_t		pcr;
577 	ni2_pcbe_config_t	*pic0;
578 	ni2_pcbe_config_t	*pic1;
579 	ni2_pcbe_config_t	nullcfg = { 1, 0, 0, 0 };
580 	ni2_pcbe_config_t	*ctmp;
581 
582 	curpic = ultra_getpic();
583 	DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic);
584 
585 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
586 		panic("%s: token %p has no configs", cpu_impl_name, token);
587 
588 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
589 		pic1 = &nullcfg;
590 		pic1_data = &tmp;
591 	}
592 
593 	if (pic0->pcbe_picno != 0) {
594 		nullcfg.pcbe_picno = 0;
595 		ctmp = pic0;
596 		pic0 = pic1;
597 		pic1 = ctmp;
598 		dtmp = pic0_data;
599 		pic0_data = pic1_data;
600 		pic1_data = dtmp;
601 	}
602 
603 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
604 		panic("%s: bad config on token %p\n", cpu_impl_name, token);
605 
606 
607 	if (pic0->pcbe_flags & CPC_COUNT_HV) {
608 		/*
609 		 * If the hpriv attribute is present, but the HT bit
610 		 * is not set in the PCR, access to hyperprivileged
611 		 * events must have been revoked. Only perform this
612 		 * check if counting is not stopped.
613 		 */
614 		pcr = ultra_getpcr();
615 		DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr);
616 		if (ni2_cpc_counting[CPU->cpu_id] &&
617 		    !(pcr & CPC_NIAGARA2_PCR_HT)) {
618 			kcpc_invalidate_config(token);
619 			return;
620 		}
621 	}
622 
623 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic;
624 	if (diff < 0)
625 		diff += (1ll << 32);
626 	*pic0_data += diff;
627 
628 	diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic;
629 	if (diff < 0)
630 		diff += (1ll << 32);
631 	*pic1_data += diff;
632 
633 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
634 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
635 }
636 
637 static void
638 ni2_pcbe_free(void *config)
639 {
640 	kmem_free(config, sizeof (ni2_pcbe_config_t));
641 }
642 
643 
644 static struct modlpcbe modlpcbe = {
645 	&mod_pcbeops,
646 #if defined(NIAGARA2_IMPL)
647 	"UltraSPARC T2 Performance Counters v%I%",
648 #elif defined(VFALLS_IMPL)
649 	"UltraSPARC T2+ Performance Counters v%I%",
650 #endif
651 	&ni2_pcbe_ops
652 };
653 
654 static struct modlinkage modl = {
655 	MODREV_1,
656 	&modlpcbe,
657 };
658 
659 int
660 _init(void)
661 {
662 	if (ni2_pcbe_init() != 0)
663 		return (ENOTSUP);
664 	return (mod_install(&modl));
665 }
666 
667 int
668 _fini(void)
669 {
670 	return (mod_remove(&modl));
671 }
672 
673 int
674 _info(struct modinfo *mi)
675 {
676 	return (mod_info(&modl, mi));
677 }
678