xref: /titanic_52/usr/src/uts/sun4u/pcbe/opl_pcbe.c (revision 9512fe850e98fdd448c638ca63fdd92a8a510255)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * SPARC64 VI 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/cmn_err.h>
35 #include <sys/cpc_impl.h>
36 #include <sys/cpc_pcbe.h>
37 #include <sys/modctl.h>
38 #include <sys/machsystm.h>
39 #include <sys/sdt.h>
40 #include <sys/cpu_impl.h>
41 
42 static int opl_pcbe_init(void);
43 static uint_t opl_pcbe_ncounters(void);
44 static const char *opl_pcbe_impl_name(void);
45 static const char *opl_pcbe_cpuref(void);
46 static char *opl_pcbe_list_events(uint_t picnum);
47 static char *opl_pcbe_list_attrs(void);
48 static uint64_t opl_pcbe_event_coverage(char *event);
49 static uint64_t opl_pcbe_overflow_bitmap(void);
50 static int opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
51     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
52     void *token);
53 static void opl_pcbe_program(void *token);
54 static void opl_pcbe_allstop(void);
55 static void opl_pcbe_sample(void *token);
56 static void opl_pcbe_free(void *config);
57 
58 extern void ultra_setpcr(uint64_t);
59 extern uint64_t ultra_getpcr(void);
60 extern void ultra_setpic(uint64_t);
61 extern uint64_t ultra_getpic(void);
62 extern uint64_t ultra_gettick(void);
63 
64 pcbe_ops_t opl_pcbe_ops = {
65 	PCBE_VER_1,
66 	CPC_CAP_OVERFLOW_INTERRUPT,
67 	opl_pcbe_ncounters,
68 	opl_pcbe_impl_name,
69 	opl_pcbe_cpuref,
70 	opl_pcbe_list_events,
71 	opl_pcbe_list_attrs,
72 	opl_pcbe_event_coverage,
73 	opl_pcbe_overflow_bitmap,
74 	opl_pcbe_configure,
75 	opl_pcbe_program,
76 	opl_pcbe_allstop,
77 	opl_pcbe_sample,
78 	opl_pcbe_free
79 };
80 
81 typedef struct _opl_pcbe_config {
82 	uint8_t		opl_picno;	/* From 0 to 7 */
83 	uint32_t	opl_bits;	/* %pcr event code unshifted */
84 	uint32_t	opl_flags;	/* user/system/priv */
85 	uint32_t	opl_pic;	/* unshifted raw %pic value */
86 } opl_pcbe_config_t;
87 
88 struct nametable {
89 	const uint8_t	bits;
90 	const char	*name;
91 };
92 
93 /*
94  * Performance Control Register (PCR)
95  *
96  * +----------+-----+-----+------+----+
97  * |      0   | OVF |  0  | OVR0 | 0  |
98  * +----------+-----+-----+------+----+
99  * 63     48  47:32  31:27   26    25
100  *
101  * +----+----+--- -+----+-----+---+-----+-----+----+----+----+
102  * | NC |  0 | SC  | 0  | SU  | 0 | SL  |ULRO | UT | ST |PRIV|
103  * +----+----+-----+----+-----+---+-----+-----+----+----+----+
104  * 24:22  21  20:18  17  16:11 10  9:4     3    2    1    0
105  *
106  *
107  * Performance Instrumentation Counter (PIC)
108  * Four PICs are implemented in SPARC64 VI,
109  * each PIC is accessed using PCR.SC as a select field.
110  *
111  * +------------------------+--------------------------+
112  * |         PICU	    |		PICL	       |
113  * +------------------------+--------------------------+
114  *  63			 32  31			      0
115  */
116 
117 #define	PIC_MASK (((uint64_t)1 << 32) - 1)
118 
119 #define	SPARC64_VI_PCR_PRIVPIC  UINT64_C(0)
120 
121 #define	CPC_SPARC64_VI_PCR_SYS_SHIFT	1
122 #define	CPC_SPARC64_VI_PCR_USR_SHIFT	2
123 
124 #define	CPC_SPARC64_VI_PCR_PICL_SHIFT	4
125 #define	CPC_SPARC64_VI_PCR_PICU_SHIFT	11
126 #define	CPC_SPARC64_VI_PCR_PIC_MASK	UINT64_C(0x3F)
127 
128 #define	CPC_SPARC64_VI_NPIC		8
129 
130 #define	CPC_SPARC64_VI_PCR_ULRO_SHIFT	3
131 #define	CPC_SPARC64_VI_PCR_SC_SHIFT	18
132 #define	CPC_SPARC64_VI_PCR_SC_MASK	UINT64_C(0x7)
133 #define	CPC_SPARC64_VI_PCR_NC_SHIFT	22
134 #define	CPC_SPARC64_VI_PCR_NC_MASK	UINT64_C(0x7)
135 #define	CPC_SPARC64_VI_PCR_OVRO_SHIFT	26
136 #define	CPC_SPARC64_VI_PCR_OVF_SHIFT	32
137 #define	CPC_SPARC64_VI_PCR_OVF_MASK	UINT64_C(0xffff)
138 
139 #define	SPARC64_VI_PCR_SYS	(UINT64_C(1) << CPC_SPARC64_VI_PCR_SYS_SHIFT)
140 #define	SPARC64_VI_PCR_USR	(UINT64_C(1) << CPC_SPARC64_VI_PCR_USR_SHIFT)
141 #define	SPARC64_VI_PCR_ULRO	(UINT64_C(1) << CPC_SPARC64_VI_PCR_ULRO_SHIFT)
142 #define	SPARC64_VI_PCR_OVRO	(UINT64_C(1) << CPC_SPARC64_VI_PCR_OVRO_SHIFT)
143 #define	SPARC64_VI_PCR_OVF	(CPC_SPARC64_VI_PCR_OVF_MASK << \
144 					CPC_SPARC64_VI_PCR_OVF_SHIFT)
145 
146 #define	SPARC64_VI_NUM_PIC_PAIRS	4
147 
148 #define	SPARC64_VI_PCR_SEL_PIC(pcr, picno) {				\
149 	pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK				\
150 		<< CPC_SPARC64_VI_PCR_SC_SHIFT));			\
151 									\
152 	pcr |= (((picno) & CPC_SPARC64_VI_PCR_SC_MASK)			\
153 		<< CPC_SPARC64_VI_PCR_SC_SHIFT);			\
154 }
155 
156 #define	SPARC64_VI_PCR_SEL_EVENT(pcr, sl, su) {				\
157 	pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK				\
158 		<< CPC_SPARC64_VI_PCR_PICL_SHIFT)			\
159 	    | (CPC_SPARC64_VI_PCR_PIC_MASK				\
160 		<< CPC_SPARC64_VI_PCR_PICU_SHIFT));			\
161 									\
162 	pcr |= (((sl) & CPC_SPARC64_VI_PCR_PIC_MASK)			\
163 		<< CPC_SPARC64_VI_PCR_PICL_SHIFT);			\
164 	pcr |= (((su) & CPC_SPARC64_VI_PCR_PIC_MASK)			\
165 		<< CPC_SPARC64_VI_PCR_PICU_SHIFT);			\
166 }
167 
168 #define	NT_END 0xFF
169 
170 static const uint64_t   allstopped = SPARC64_VI_PCR_PRIVPIC |
171 	SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO;
172 
173 #define	SPARC64_VI_EVENTS_comm			\
174 	{0x0,	"cycle_counts"},		\
175 	{0x1,	"instruction_counts"},		\
176 	{0x8,	"load_store_instructions"},	\
177 	{0x9,	"branch_instructions"},		\
178 	{0xa,	"floating_instructions"},	\
179 	{0xb,	"impdep2_instructions"},	\
180 	{0xc,	"prefetch_instructions"}
181 
182 static const struct nametable SPARC64_VI_names_l0[] = {
183 	SPARC64_VI_EVENTS_comm,
184 	{0x16,	"trap_int_vector"},
185 	{0x20,	"write_op_uTLB"},
186 	{0x30,	"sx_miss_wait_pf"},
187 	{0x31,	"jbus_cpi_count"},
188 	{NT_END, ""}
189 };
190 
191 static const struct nametable SPARC64_VI_names_u0[] = {
192 	SPARC64_VI_EVENTS_comm,
193 	{0x16,	"trap_all"},
194 	{0x20,	"write_if_uTLB"},
195 	{0x30,	"sx_miss_wait_dm"},
196 	{0x31,	"jbus_bi_count"},
197 	{NT_END, ""}
198 };
199 
200 static const struct nametable SPARC64_VI_names_l1[] = {
201 	SPARC64_VI_EVENTS_comm,
202 	{0x16,	"trap_spill"},
203 	{0x20,	"write_op_uTLB"},
204 	{0x30,	"sx_miss_count_pf"},
205 	{0x31,	"jbus_cpd_count"},
206 	{NT_END, ""}
207 };
208 
209 static const struct nametable SPARC64_VI_names_u1[] = {
210 	SPARC64_VI_EVENTS_comm,
211 	{0x16,	"trap_int_level"},
212 	{0x20,	"write_if_uTLB"},
213 	{0x30,	"sx_miss_count_dm"},
214 	{0x31,	"jbus_cpb_count"},
215 	{NT_END, ""}
216 };
217 
218 static const struct nametable SPARC64_VI_names_l2[] = {
219 	SPARC64_VI_EVENTS_comm,
220 	{0x16,	"trap_trap_inst"},
221 	{0x20,	"op_r_iu_req_mi_go"},
222 	{0x30,	"sx_read_count_pf"},
223 	{NT_END, ""}
224 };
225 
226 static const struct nametable SPARC64_VI_names_u2[] = {
227 	SPARC64_VI_EVENTS_comm,
228 	{0x16,	"trap_fill"},
229 	{0x20,	"if_r_iu_req_mi_go"},
230 	{0x30,	"sx_read_count_dm"},
231 	{NT_END, ""}
232 };
233 
234 static const struct nametable SPARC64_VI_names_l3[] = {
235 	SPARC64_VI_EVENTS_comm,
236 	{0x16,	"trap_DMMU_miss"},
237 	{0x20,	"op_wait_all"},
238 	{0x30,	"dvp_count_pf"},
239 	{NT_END, ""}
240 };
241 
242 static const struct nametable SPARC64_VI_names_u3[] = {
243 	SPARC64_VI_EVENTS_comm,
244 	{0x16,	"trap_IMMU_miss"},
245 	{0x20,	"if_wait_all"},
246 	{0x30,	"dvp_count_dm"},
247 	{NT_END, ""}
248 };
249 
250 #undef	SPARC64_VI_EVENTS_comm
251 
252 static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = {
253 	SPARC64_VI_names_l0,
254 	SPARC64_VI_names_u0,
255 	SPARC64_VI_names_l1,
256 	SPARC64_VI_names_u1,
257 	SPARC64_VI_names_l2,
258 	SPARC64_VI_names_u2,
259 	SPARC64_VI_names_l3,
260 	SPARC64_VI_names_u3
261 };
262 
263 opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = {
264 	{0, 0x3f, 0, 0},
265 	{1, 0x3f, 0, 0},
266 	{2, 0x3f, 0, 0},
267 	{3, 0x3f, 0, 0},
268 	{4, 0x3f, 0, 0},
269 	{5, 0x3f, 0, 0},
270 	{6, 0x3f, 0, 0},
271 	{7, 0x3f, 0, 0}
272 };
273 
274 static const struct nametable **events;
275 static const char *opl_impl_name;
276 static const char *opl_cpuref;
277 static char *pic_events[CPC_SPARC64_VI_NPIC];
278 
279 static const char *sp_6_ref = "See the \"SPARC64 VI extensions\" "
280 			"for descriptions of these events.";
281 
282 static int
283 opl_pcbe_init(void)
284 {
285 	const struct nametable	*n;
286 	int			i;
287 	size_t			size;
288 
289 	/*
290 	 * Discover type of CPU
291 	 *
292 	 * Point nametable to that CPU's table
293 	 */
294 	switch (ULTRA_VER_IMPL(ultra_getver())) {
295 	case OLYMPUS_C_IMPL:
296 		events = SPARC64_VI_names;
297 		opl_impl_name = "SPARC64 VI";
298 		opl_cpuref = sp_6_ref;
299 		break;
300 	default:
301 		return (-1);
302 	}
303 
304 	/*
305 	 * Initialize the list of events for each PIC.
306 	 * Do two passes: one to compute the size necessary and another
307 	 * to copy the strings. Need room for event, comma, and NULL terminator.
308 	 */
309 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
310 		size = 0;
311 		for (n = events[i]; n->bits != NT_END; n++)
312 			size += strlen(n->name) + 1;
313 		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
314 		*pic_events[i] = '\0';
315 		for (n = events[i]; n->bits != NT_END; n++) {
316 			(void) strcat(pic_events[i], n->name);
317 			(void) strcat(pic_events[i], ",");
318 		}
319 		/*
320 		 * Remove trailing comma.
321 		 */
322 		pic_events[i][size - 1] = '\0';
323 	}
324 
325 	return (0);
326 }
327 
328 static uint_t
329 opl_pcbe_ncounters(void)
330 {
331 	return (CPC_SPARC64_VI_NPIC);
332 }
333 
334 static const char *
335 opl_pcbe_impl_name(void)
336 {
337 	return (opl_impl_name);
338 }
339 
340 static const char *
341 opl_pcbe_cpuref(void)
342 {
343 	return (opl_cpuref);
344 }
345 
346 static char *
347 opl_pcbe_list_events(uint_t picnum)
348 {
349 	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
350 
351 	return (pic_events[picnum]);
352 }
353 
354 static char *
355 opl_pcbe_list_attrs(void)
356 {
357 	return ("");
358 }
359 
360 static const struct nametable *
361 find_event(int regno, char *name)
362 {
363 	const struct nametable *n;
364 
365 	n = events[regno];
366 
367 	for (; n->bits != NT_END; n++)
368 		if (strcmp(name, n->name) == 0)
369 			return (n);
370 
371 	return (NULL);
372 }
373 
374 static uint64_t
375 opl_pcbe_event_coverage(char *event)
376 {
377 	uint64_t bitmap = 0;
378 
379 	int	i;
380 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
381 		if (find_event(i, event) != NULL)
382 			bitmap |= (1 << i);
383 	}
384 
385 	return (bitmap);
386 }
387 
388 /*
389  * Check if counter overflow and clear it.
390  */
391 static uint64_t
392 opl_pcbe_overflow_bitmap(void)
393 {
394 	uint64_t	pcr, overflow;
395 
396 	pcr = ultra_getpcr();
397 	DTRACE_PROBE1(sparc64__getpcr, uint64_t, pcr);
398 
399 	overflow = (pcr & SPARC64_VI_PCR_OVF) >>
400 		CPC_SPARC64_VI_PCR_OVF_SHIFT;
401 
402 	if (overflow)
403 		ultra_setpcr(pcr & ~SPARC64_VI_PCR_OVF);
404 
405 	return (overflow);
406 }
407 
408 /*ARGSUSED*/
409 static int
410 opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
411     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
412 {
413 	opl_pcbe_config_t *conf;
414 	const struct nametable *n;
415 	opl_pcbe_config_t *other_config;
416 
417 	/*
418 	 * If we've been handed an existing configuration, we need only preset
419 	 * the counter value.
420 	 */
421 	if (*data != NULL) {
422 		conf = *data;
423 		conf->opl_pic = (uint32_t)preset;
424 		return (0);
425 	}
426 
427 	if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC)
428 		return (CPC_INVALID_PICNUM);
429 
430 	if (nattrs != 0)
431 		return (CPC_INVALID_ATTRIBUTE);
432 
433 	/*
434 	 * Find other requests that will be programmed with this one, and ensure
435 	 * the flags don't conflict.
436 	 */
437 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
438 	    (other_config->opl_flags != flags))
439 		return (CPC_CONFLICTING_REQS);
440 
441 	if ((n = find_event(picnum, event)) == NULL)
442 		return (CPC_INVALID_EVENT);
443 
444 	conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP);
445 
446 	conf->opl_picno = picnum;
447 	conf->opl_bits = (uint32_t)n->bits;
448 	conf->opl_flags = flags;
449 	conf->opl_pic = (uint32_t)preset;
450 
451 	*data = conf;
452 	return (0);
453 }
454 
455 static void
456 opl_pcbe_program(void *token)
457 {
458 	opl_pcbe_config_t	*pic[CPC_SPARC64_VI_NPIC];
459 	opl_pcbe_config_t	*firstconfig;
460 	opl_pcbe_config_t	*tmp;
461 	uint64_t		pcr;
462 	uint64_t		curpic;
463 	uint8_t			bitmap = 0;	/* for used pic config */
464 	int			i;
465 	opl_pcbe_config_t	dummypic[CPC_SPARC64_VI_NPIC];
466 
467 	/* Get next pic config */
468 	firstconfig = tmp = kcpc_next_config(token, NULL, NULL);
469 
470 	while (tmp != NULL) {
471 		ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC);
472 		ASSERT(firstconfig->opl_flags == tmp->opl_flags);
473 		pic[tmp->opl_picno] = tmp;
474 		bitmap |= (uint8_t)(1 << tmp->opl_picno);
475 		tmp = kcpc_next_config(token, tmp, NULL);
476 	}
477 	if (bitmap == 0)
478 		panic("opl_pcbe: token %p has no configs", token);
479 
480 	/* Fill in unused pic config */
481 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
482 		if (bitmap & (1 << i))
483 			continue;
484 
485 		dummypic[i] = nullpic[i];
486 		dummypic[i].opl_flags = firstconfig->opl_flags;
487 		pic[i] = &dummypic[i];
488 	}
489 
490 	/*
491 	 * For each counter pair, initialize event settings and
492 	 * counter values.
493 	 */
494 	ultra_setpcr(allstopped);
495 	pcr = allstopped;
496 	pcr &= ~SPARC64_VI_PCR_ULRO;
497 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
498 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
499 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
500 		    pic[i*2 + 1]->opl_bits);
501 
502 		ultra_setpcr(pcr);
503 		curpic = (uint64_t)(pic[i*2]->opl_pic |
504 		    ((uint64_t)pic[i*2 + 1]->opl_pic << 32));
505 		ultra_setpic(curpic);
506 	}
507 
508 	/*
509 	 * For each counter pair, enable the trace flags to start
510 	 * counting. Re-read the counters to sample the counter value now
511 	 * and use that as the baseline for future samples.
512 	 */
513 
514 	/* Get PCR */
515 	pcr = ultra_getpcr();
516 	pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO);
517 
518 	if (pic[0]->opl_flags & CPC_COUNT_USER)
519 		pcr |= SPARC64_VI_PCR_USR;
520 	if (pic[0]->opl_flags & CPC_COUNT_SYSTEM)
521 		pcr |= SPARC64_VI_PCR_SYS;
522 
523 	/* Set counter values */
524 
525 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
526 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
527 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
528 		    pic[i*2 + 1]->opl_bits);
529 
530 		ultra_setpcr(pcr);
531 		DTRACE_PROBE1(sparc64__setpcr, uint64_t, pcr);
532 
533 		curpic = ultra_getpic();
534 		DTRACE_PROBE1(sparc64__newpic, uint64_t, curpic);
535 		pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
536 		pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
537 	}
538 
539 }
540 
541 static void
542 opl_pcbe_allstop(void)
543 {
544 	ultra_setpcr(allstopped);
545 }
546 
547 
548 static void
549 opl_pcbe_sample(void *token)
550 {
551 	uint64_t		curpic;
552 	uint64_t		pcr;
553 	int64_t			diff;
554 	uint64_t		*pic_data[CPC_SPARC64_VI_NPIC];
555 	uint64_t		*dtmp;
556 	opl_pcbe_config_t	*pic[CPC_SPARC64_VI_NPIC];
557 	opl_pcbe_config_t	*ctmp;
558 	opl_pcbe_config_t	*firstconfig;
559 	uint8_t			bitmap = 0;	/* for used pic config */
560 	int			i;
561 	opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC];
562 	uint64_t dummypic_data[CPC_SPARC64_VI_NPIC];
563 
564 	/* Get next pic config */
565 	firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp);
566 
567 	while (ctmp != NULL) {
568 		ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC);
569 		ASSERT(firstconfig->opl_flags == ctmp->opl_flags);
570 		pic[ctmp->opl_picno] = ctmp;
571 		pic_data[ctmp->opl_picno] = dtmp;
572 		bitmap |= (uint8_t)(1 << ctmp->opl_picno);
573 		ctmp = kcpc_next_config(token, ctmp, &dtmp);
574 	}
575 	if (bitmap == 0)
576 		panic("opl_pcbe: token %p has no configs", token);
577 
578 	/* Fill in unuse pic config */
579 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
580 		if (bitmap & (1 << i))
581 			continue;
582 
583 		dummypic[i] = nullpic[i];
584 		dummypic[i].opl_flags = firstconfig->opl_flags;
585 		pic[i] = &dummypic[i];
586 
587 		dummypic_data[i] = 0;
588 		pic_data[i] = &dummypic_data[i];
589 	}
590 
591 	pcr = ultra_getpcr();
592 	pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO);
593 
594 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
595 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
596 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
597 		    pic[i*2 + 1]->opl_bits);
598 
599 		ultra_setpcr(pcr);
600 
601 		curpic = ultra_getpic();
602 		DTRACE_PROBE1(sparc64__getpic, unit64_t, curpic);
603 
604 		diff = (int64_t)((uint32_t)(curpic & PIC_MASK) -
605 		    pic[i*2]->opl_pic);
606 		if (diff < 0)
607 			diff += (1ll << 32);
608 		*pic_data[i*2] += diff;
609 
610 		diff = (int64_t)((uint32_t)(curpic >> 32) -
611 		    pic[i*2 + 1]->opl_pic);
612 		if (diff < 0)
613 			diff += (1ll << 32);
614 		*pic_data[i*2 + 1] += diff;
615 
616 		pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
617 		pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
618 	}
619 
620 }
621 
622 static void
623 opl_pcbe_free(void *config)
624 {
625 	kmem_free(config, sizeof (opl_pcbe_config_t));
626 }
627 
628 
629 static struct modlpcbe modlpcbe = {
630 	&mod_pcbeops,
631 	"SPARC64 VI Performance Counters v1.2",
632 	&opl_pcbe_ops
633 };
634 
635 static struct modlinkage modl = {
636 	MODREV_1,
637 	&modlpcbe,
638 };
639 
640 int
641 _init(void)
642 {
643 	if (opl_pcbe_init() != 0)
644 		return (ENOTSUP);
645 	return (mod_install(&modl));
646 }
647 
648 int
649 _fini(void)
650 {
651 	return (mod_remove(&modl));
652 }
653 
654 int
655 _info(struct modinfo *mi)
656 {
657 	return (mod_info(&modl, mi));
658 }
659