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