xref: /titanic_52/usr/src/uts/sun4u/pcbe/opl_pcbe.c (revision 80b80bf0416a7eb4be4215b2e192cafd03ca80b7)
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  * SPARC64 VI & VII 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  * ULRO and OVRO bits should be on upon accessing pcr unless
107  * those fields need to be updated.
108  * Turn off these bits when updating SU/SL or OVF field
109  * (during initialization, etc.).
110  *
111  *
112  * Performance Instrumentation Counter (PIC)
113  * Four PICs are implemented in SPARC64 VI and VII,
114  * each PIC is accessed using PCR.SC as a select field.
115  *
116  * +------------------------+--------------------------+
117  * |         PICU	    |		PICL	       |
118  * +------------------------+--------------------------+
119  *  63			 32  31			      0
120  */
121 
122 #define	PIC_MASK (((uint64_t)1 << 32) - 1)
123 
124 #define	SPARC64_VI_PCR_PRIVPIC  UINT64_C(0)
125 
126 #define	CPC_SPARC64_VI_PCR_SYS_SHIFT	1
127 #define	CPC_SPARC64_VI_PCR_USR_SHIFT	2
128 
129 #define	CPC_SPARC64_VI_PCR_PICL_SHIFT	4
130 #define	CPC_SPARC64_VI_PCR_PICU_SHIFT	11
131 #define	CPC_SPARC64_VI_PCR_PIC_MASK	UINT64_C(0x3F)
132 
133 #define	CPC_SPARC64_VI_NPIC		8
134 
135 #define	CPC_SPARC64_VI_PCR_ULRO_SHIFT	3
136 #define	CPC_SPARC64_VI_PCR_SC_SHIFT	18
137 #define	CPC_SPARC64_VI_PCR_SC_MASK	UINT64_C(0x7)
138 #define	CPC_SPARC64_VI_PCR_NC_SHIFT	22
139 #define	CPC_SPARC64_VI_PCR_NC_MASK	UINT64_C(0x7)
140 #define	CPC_SPARC64_VI_PCR_OVRO_SHIFT	26
141 #define	CPC_SPARC64_VI_PCR_OVF_SHIFT	32
142 #define	CPC_SPARC64_VI_PCR_OVF_MASK	UINT64_C(0xffff)
143 
144 #define	SPARC64_VI_PCR_SYS	(UINT64_C(1) << CPC_SPARC64_VI_PCR_SYS_SHIFT)
145 #define	SPARC64_VI_PCR_USR	(UINT64_C(1) << CPC_SPARC64_VI_PCR_USR_SHIFT)
146 #define	SPARC64_VI_PCR_ULRO	(UINT64_C(1) << CPC_SPARC64_VI_PCR_ULRO_SHIFT)
147 #define	SPARC64_VI_PCR_OVRO	(UINT64_C(1) << CPC_SPARC64_VI_PCR_OVRO_SHIFT)
148 #define	SPARC64_VI_PCR_OVF	(CPC_SPARC64_VI_PCR_OVF_MASK << \
149 					CPC_SPARC64_VI_PCR_OVF_SHIFT)
150 
151 #define	SPARC64_VI_NUM_PIC_PAIRS	4
152 
153 #define	SPARC64_VI_PCR_SEL_PIC(pcr, picno) {				\
154 	pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK				\
155 		<< CPC_SPARC64_VI_PCR_SC_SHIFT));			\
156 									\
157 	pcr |= (((picno) & CPC_SPARC64_VI_PCR_SC_MASK)			\
158 		<< CPC_SPARC64_VI_PCR_SC_SHIFT);			\
159 }
160 
161 #define	SPARC64_VI_PCR_SEL_EVENT(pcr, sl, su) {				\
162 	pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK				\
163 		<< CPC_SPARC64_VI_PCR_PICL_SHIFT)			\
164 	    | (CPC_SPARC64_VI_PCR_PIC_MASK				\
165 		<< CPC_SPARC64_VI_PCR_PICU_SHIFT));			\
166 									\
167 	pcr |= (((sl) & CPC_SPARC64_VI_PCR_PIC_MASK)			\
168 		<< CPC_SPARC64_VI_PCR_PICL_SHIFT);			\
169 	pcr |= (((su) & CPC_SPARC64_VI_PCR_PIC_MASK)			\
170 		<< CPC_SPARC64_VI_PCR_PICU_SHIFT);			\
171 }
172 
173 #define	SPARC64_VI_CHK_OVF(pcr, picno)					\
174 	((pcr) & (UINT64_C(1) << (CPC_SPARC64_VI_PCR_OVF_SHIFT + picno)))
175 
176 #define	SPARC64_VI_CLR_OVF(pcr, picno) {				\
177 	pcr &= ~(UINT64_C(1) << (CPC_SPARC64_VI_PCR_OVF_SHIFT + picno)); \
178 }
179 
180 #define	NT_END 0xFF
181 
182 static const uint64_t   allstopped = SPARC64_VI_PCR_PRIVPIC |
183 	SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO;
184 
185 #define	SPARC64_VI_EVENTS_comm_0		\
186 	{0x0,	"cycle_counts"},		\
187 	{0x1,	"instruction_counts"}
188 
189 #define	SPARC64_VI_EVENTS_comm_1		\
190 	{0x5,	"op_stv_wait"},			\
191 	{0x8,	"load_store_instructions"},	\
192 	{0x9,	"branch_instructions"},		\
193 	{0xa,	"floating_instructions"},	\
194 	{0xb,	"impdep2_instructions"},	\
195 	{0xc,	"prefetch_instructions"}
196 
197 #define	SPARC64_VI_EVENTS_comm_2		\
198 	{0x1a,	"active_cycle_count"}
199 
200 static const struct nametable SPARC64_VI_names_l0[] = {
201 	SPARC64_VI_EVENTS_comm_0,
202 	{0x2,	"only_this_thread_active"},
203 	{0x3,	"w_cse_window_empty"},
204 	{0x4,	"w_op_stv_wait_nc_pend"},
205 	SPARC64_VI_EVENTS_comm_1,
206 	{0x12,	"flush_rs"},
207 	{0x13,	"2iid_use"},
208 	{0x15,	"toq_rsbr_phantom"},
209 	{0x16,	"trap_int_vector"},
210 	{0x18,	"ts_by_sxmiss"},
211 	{0x18,	"both_threads_active"},
212 	SPARC64_VI_EVENTS_comm_2,
213 	{0x1d,	"op_stv_wait_sxmiss"},
214 	{0x1e,	"eu_comp_wait"},
215 	{0x23,	"op_l1_thrashing"},
216 	{0x24,	"swpf_fail_all"},
217 	{0x30,	"sx_miss_wait_pf"},
218 	{0x31,	"jbus_cpi_count"},
219 	{0x36,	"jbus_reqbus1_busy"},
220 	{NT_END, ""}
221 };
222 
223 static const struct nametable SPARC64_VI_names_u0[] = {
224 	SPARC64_VI_EVENTS_comm_0,
225 	{0x2,	"instruction_flow_counts"},
226 	{0x3,	"iwr_empty"},
227 	SPARC64_VI_EVENTS_comm_1,
228 	{0x12,	"rs1"},
229 	{0x13,	"1iid_use"},
230 	{0x16,	"trap_all"},
231 	{0x18,	"thread_switch_all"},
232 	{0x18,	"only_this_thread_active"},
233 	SPARC64_VI_EVENTS_comm_2,
234 	{0x1d,	"act_thread_suspend"},
235 	{0x1e,	"cse_window_empty"},
236 	{0x1f,	"inh_cmit_gpr_2write"},
237 	{0x23,	"if_l1_thrashing"},
238 	{0x24,	"swpf_success_all"},
239 	{0x30,	"sx_miss_wait_dm"},
240 	{0x31,	"jbus_bi_count"},
241 	{0x34,	"lost_softpf_pfp_full"},
242 	{0x36,	"jbus_reqbus0_busy"},
243 	{NT_END, ""}
244 };
245 
246 static const struct nametable SPARC64_VI_names_l1[] = {
247 	SPARC64_VI_EVENTS_comm_0,
248 	{0x2,	"single_mode_instructions"},
249 	{0x3,	"w_branch_comp_wait"},
250 	{0x4,	"w_op_stv_wait_sxmiss_ex"},
251 	SPARC64_VI_EVENTS_comm_1,
252 	{0x13,	"4iid_use"},
253 	{0x15,	"flush_rs"},
254 	{0x16,	"trap_spill"},
255 	{0x18,	"ts_by_timer"},
256 	SPARC64_VI_EVENTS_comm_2,
257 	{0x1b,	"0iid_use"},
258 	{0x1d,	"op_stv_wait_nc_pend"},
259 	{0x1e,	"0endop"},
260 	{0x20,	"write_op_uTLB"},
261 	{0x30,	"sx_miss_count_pf"},
262 	{0x31,	"jbus_cpd_count"},
263 	{0x32,	"snres_64"},
264 	{0x36,	"jbus_reqbus3_busy"},
265 	{NT_END, ""}
266 };
267 
268 static const struct nametable SPARC64_VI_names_u1[] = {
269 	SPARC64_VI_EVENTS_comm_0,
270 	{0x2,	"single_mode_cycle_counts"},
271 	{0x3,	"w_eu_comp_wait"},
272 	{0x4,	"w_op_stv_wait_sxmiss"},
273 	SPARC64_VI_EVENTS_comm_1,
274 	{0x13,	"3iid_use"},
275 	{0x16,	"trap_int_level"},
276 	{0x18,	"ts_by_data_arrive"},
277 	{0x18,	"both_threads_empty"},
278 	SPARC64_VI_EVENTS_comm_2,
279 	{0x1b,	"op_stv_wait_nc_pend"},
280 	{0x1d,	"op_stv_wait_sxmiss_ex"},
281 	{0x1e,	"branch_comp_wait"},
282 	{0x20,	"write_if_uTLB"},
283 	{0x30,	"sx_miss_count_dm"},
284 	{0x31,	"jbus_cpb_count"},
285 	{0x32,	"snres_256"},
286 	{0x34,	"lost_softpf_by_abort"},
287 	{0x36,	"jbus_reqbus2_busy"},
288 	{NT_END, ""}
289 };
290 
291 static const struct nametable SPARC64_VI_names_l2[] = {
292 	SPARC64_VI_EVENTS_comm_0,
293 	{0x2,	"d_move_wait"},
294 	{0x3,	"w_op_stv_wait"},
295 	{0x4,	"w_fl_comp_wait"},
296 	SPARC64_VI_EVENTS_comm_1,
297 	{0x13,	"sync_intlk"},
298 	{0x16,	"trap_trap_inst"},
299 	{0x18,	"ts_by_if"},
300 	SPARC64_VI_EVENTS_comm_2,
301 	{0x1e,	"fl_comp_wait"},
302 	{0x20,	"op_r_iu_req_mi_go"},
303 	{0x30,	"sx_read_count_pf"},
304 	{0x31,	"jbus_odrbus_busy"},
305 	{0x33,	"sx_miss_count_dm_if"},
306 	{0x36,	"jbus_odrbus1_busy"},
307 	{NT_END, ""}
308 };
309 
310 static const struct nametable SPARC64_VI_names_u2[] = {
311 	SPARC64_VI_EVENTS_comm_0,
312 	{0x2,	"instruction_flow_counts"},
313 	{0x3,	"iwr_empty"},
314 	SPARC64_VI_EVENTS_comm_1,
315 	{0x16,	"trap_fill"},
316 	{0x18,	"ts_by_intr"},
317 	SPARC64_VI_EVENTS_comm_2,
318 	{0x1b,	"flush_rs"},
319 	{0x1d,	"cse_window_empty_sp_full"},
320 	{0x1e,	"op_stv_wait_ex"},
321 	{0x1f,	"3endop"},
322 	{0x20,	"if_r_iu_req_mi_go"},
323 	{0x24,	"swpf_lbs_hit"},
324 	{0x30,	"sx_read_count_dm"},
325 	{0x31,	"jbus_reqbus_busy"},
326 	{0x33,	"sx_btc_count"},
327 	{0x36,	"jbus_odrbus0_busy"},
328 	{NT_END, ""}
329 };
330 
331 static const struct nametable SPARC64_VI_names_l3[] = {
332 	SPARC64_VI_EVENTS_comm_0,
333 	{0x2,	"xma_inst"},
334 	{0x3,	"w_0endop"},
335 	{0x4,	"w_op_stv_wait_ex"},
336 	SPARC64_VI_EVENTS_comm_1,
337 	{0x16,	"trap_DMMU_miss"},
338 	{0x18,	"ts_by_suspend"},
339 	{0x19,	"ts_by_other"},
340 	SPARC64_VI_EVENTS_comm_2,
341 	{0x1b,	"decall_intlk"},
342 	{0x1e,	"2endop"},
343 	{0x1f,	"op_stv_wait_sxmiss"},
344 	{0x20,	"op_wait_all"},
345 	{0x30,	"dvp_count_pf"},
346 	{0x33,	"sx_miss_count_dm_opex"},
347 	{0x36,	"jbus_odrbus3_busy"},
348 	{NT_END, ""}
349 };
350 
351 static const struct nametable SPARC64_VI_names_u3[] = {
352 	SPARC64_VI_EVENTS_comm_0,
353 	{0x2,	"cse_priority_wait"},
354 	{0x3,	"w_d_move"},
355 	{0x4,	"w_cse_window_empty_sp_full"},
356 	SPARC64_VI_EVENTS_comm_1,
357 	{0x13,	"regwin_intlk"},
358 	{0x15,	"rs1"},
359 	{0x16,	"trap_IMMU_miss"},
360 	SPARC64_VI_EVENTS_comm_2,
361 	{0x1d,	"both_threads_suspended"},
362 	{0x1e,	"1endop"},
363 	{0x1f,	"op_stv_wait_sxmiss_ex"},
364 	{0x20,	"if_wait_all"},
365 	{0x30,	"dvp_count_dm"},
366 	{0x33,	"sx_miss_count_dm_opsh"},
367 	{0x36,	"jbus_odrbus2_busy"},
368 	{NT_END, ""}
369 };
370 
371 #undef	SPARC64_VI_EVENTS_comm_0
372 #undef	SPARC64_VI_EVENTS_comm_1
373 #undef	SPARC64_VI_EVENTS_comm_2
374 
375 static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = {
376 	SPARC64_VI_names_l0,
377 	SPARC64_VI_names_u0,
378 	SPARC64_VI_names_l1,
379 	SPARC64_VI_names_u1,
380 	SPARC64_VI_names_l2,
381 	SPARC64_VI_names_u2,
382 	SPARC64_VI_names_l3,
383 	SPARC64_VI_names_u3
384 };
385 
386 opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = {
387 	{0, 0x3f, 0, 0},
388 	{1, 0x3f, 0, 0},
389 	{2, 0x3f, 0, 0},
390 	{3, 0x3f, 0, 0},
391 	{4, 0x3f, 0, 0},
392 	{5, 0x3f, 0, 0},
393 	{6, 0x3f, 0, 0},
394 	{7, 0x3f, 0, 0}
395 };
396 
397 static const struct nametable **events;
398 static const char *opl_impl_name;
399 static const char *opl_cpuref;
400 static char *pic_events[CPC_SPARC64_VI_NPIC];
401 
402 static const char *sp_6_ref = "See the \"SPARC64 VI extensions\" and "
403 	"\"SPARC64 VII extensions\" for descriptions of these events.";
404 
405 static int
406 opl_pcbe_init(void)
407 {
408 	const struct nametable	*n;
409 	int			i;
410 	size_t			size;
411 
412 	/*
413 	 * Discover type of CPU
414 	 *
415 	 * Point nametable to that CPU's table
416 	 */
417 	switch (ULTRA_VER_IMPL(ultra_getver())) {
418 	case OLYMPUS_C_IMPL:
419 	case JUPITER_IMPL:
420 		events = SPARC64_VI_names;
421 		opl_impl_name = "SPARC64 VI & VII";
422 		opl_cpuref = sp_6_ref;
423 		break;
424 	default:
425 		return (-1);
426 	}
427 
428 	/*
429 	 * Initialize the list of events for each PIC.
430 	 * Do two passes: one to compute the size necessary and another
431 	 * to copy the strings. Need room for event, comma, and NULL terminator.
432 	 */
433 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
434 		size = 0;
435 		for (n = events[i]; n->bits != NT_END; n++)
436 			size += strlen(n->name) + 1;
437 		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
438 		*pic_events[i] = '\0';
439 		for (n = events[i]; n->bits != NT_END; n++) {
440 			(void) strcat(pic_events[i], n->name);
441 			(void) strcat(pic_events[i], ",");
442 		}
443 		/*
444 		 * Remove trailing comma.
445 		 */
446 		pic_events[i][size - 1] = '\0';
447 	}
448 
449 	return (0);
450 }
451 
452 static uint_t
453 opl_pcbe_ncounters(void)
454 {
455 	return (CPC_SPARC64_VI_NPIC);
456 }
457 
458 static const char *
459 opl_pcbe_impl_name(void)
460 {
461 	return (opl_impl_name);
462 }
463 
464 static const char *
465 opl_pcbe_cpuref(void)
466 {
467 	return (opl_cpuref);
468 }
469 
470 static char *
471 opl_pcbe_list_events(uint_t picnum)
472 {
473 	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
474 
475 	return (pic_events[picnum]);
476 }
477 
478 static char *
479 opl_pcbe_list_attrs(void)
480 {
481 	return ("");
482 }
483 
484 static const struct nametable *
485 find_event(int regno, char *name)
486 {
487 	const struct nametable *n;
488 
489 	n = events[regno];
490 
491 	for (; n->bits != NT_END; n++)
492 		if (strcmp(name, n->name) == 0)
493 			return (n);
494 
495 	return (NULL);
496 }
497 
498 static uint64_t
499 opl_pcbe_event_coverage(char *event)
500 {
501 	uint64_t bitmap = 0;
502 
503 	int	i;
504 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
505 		if (find_event(i, event) != NULL)
506 			bitmap |= (1 << i);
507 	}
508 
509 	return (bitmap);
510 }
511 
512 /*
513  * Check if counter overflow and clear it.
514  */
515 static uint64_t
516 opl_pcbe_overflow_bitmap(void)
517 {
518 	uint64_t	pcr;
519 
520 	pcr = ultra_getpcr();
521 	DTRACE_PROBE1(sparc64__getpcr, uint64_t, pcr);
522 
523 	return ((pcr & SPARC64_VI_PCR_OVF) >> CPC_SPARC64_VI_PCR_OVF_SHIFT);
524 }
525 
526 /*ARGSUSED*/
527 static int
528 opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
529     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
530 {
531 	opl_pcbe_config_t *conf;
532 	const struct nametable *n;
533 	opl_pcbe_config_t *other_config;
534 
535 	/*
536 	 * If we've been handed an existing configuration, we need only preset
537 	 * the counter value.
538 	 */
539 	if (*data != NULL) {
540 		conf = *data;
541 		conf->opl_pic = (uint32_t)preset;
542 		return (0);
543 	}
544 
545 	if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC)
546 		return (CPC_INVALID_PICNUM);
547 
548 	if (nattrs != 0)
549 		return (CPC_INVALID_ATTRIBUTE);
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->opl_flags != flags))
557 		return (CPC_CONFLICTING_REQS);
558 
559 	if ((n = find_event(picnum, event)) == NULL)
560 		return (CPC_INVALID_EVENT);
561 
562 	conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP);
563 
564 	conf->opl_picno = picnum;
565 	conf->opl_bits = (uint32_t)n->bits;
566 	conf->opl_flags = flags;
567 	conf->opl_pic = (uint32_t)preset;
568 
569 	*data = conf;
570 	return (0);
571 }
572 
573 static void
574 opl_pcbe_program(void *token)
575 {
576 	opl_pcbe_config_t	*pic[CPC_SPARC64_VI_NPIC];
577 	opl_pcbe_config_t	*firstconfig;
578 	opl_pcbe_config_t	*tmp;
579 	uint64_t		pcr;
580 	uint64_t		curpic;
581 	uint8_t			bitmap = 0;	/* for used pic config */
582 	int			i;
583 	opl_pcbe_config_t	dummypic[CPC_SPARC64_VI_NPIC];
584 
585 	/* Get next pic config */
586 	firstconfig = tmp = kcpc_next_config(token, NULL, NULL);
587 
588 	while (tmp != NULL) {
589 		ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC);
590 		ASSERT(firstconfig->opl_flags == tmp->opl_flags);
591 		pic[tmp->opl_picno] = tmp;
592 		bitmap |= (uint8_t)(1 << tmp->opl_picno);
593 		tmp = kcpc_next_config(token, tmp, NULL);
594 	}
595 	if (bitmap == 0)
596 		panic("opl_pcbe: token %p has no configs", token);
597 
598 	/* Fill in unused pic config */
599 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
600 		if (bitmap & (1 << i))
601 			continue;
602 
603 		dummypic[i] = nullpic[i];
604 		dummypic[i].opl_flags = firstconfig->opl_flags;
605 		pic[i] = &dummypic[i];
606 	}
607 
608 	/*
609 	 * For each counter pair, initialize event settings and
610 	 * counter values.
611 	 */
612 	ultra_setpcr(allstopped);
613 	pcr = allstopped;
614 	pcr &= ~SPARC64_VI_PCR_ULRO;
615 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
616 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
617 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
618 		    pic[i*2 + 1]->opl_bits);
619 
620 		ultra_setpcr(pcr);
621 		curpic = (uint64_t)(pic[i*2]->opl_pic |
622 		    ((uint64_t)pic[i*2 + 1]->opl_pic << 32));
623 		ultra_setpic(curpic);
624 	}
625 
626 	/*
627 	 * For each counter pair, enable the trace flags to start
628 	 * counting. Re-read the counters to sample the counter value now
629 	 * and use that as the baseline for future samples.
630 	 */
631 
632 	/* Get PCR */
633 	pcr = ultra_getpcr();
634 	pcr |= SPARC64_VI_PCR_ULRO;
635 	pcr &= ~(SPARC64_VI_PCR_OVRO | SPARC64_VI_PCR_OVF);
636 
637 	if (pic[0]->opl_flags & CPC_COUNT_USER)
638 		pcr |= SPARC64_VI_PCR_USR;
639 	if (pic[0]->opl_flags & CPC_COUNT_SYSTEM)
640 		pcr |= SPARC64_VI_PCR_SYS;
641 
642 	/* Set counter values */
643 
644 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
645 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
646 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
647 		    pic[i*2 + 1]->opl_bits);
648 
649 		ultra_setpcr(pcr);
650 		DTRACE_PROBE1(sparc64__setpcr, uint64_t, pcr);
651 
652 		curpic = ultra_getpic();
653 		DTRACE_PROBE1(sparc64__newpic, uint64_t, curpic);
654 		pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
655 		pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
656 	}
657 	pcr |= SPARC64_VI_PCR_OVRO;
658 	ultra_setpcr(pcr);
659 }
660 
661 static void
662 opl_pcbe_allstop(void)
663 {
664 	ultra_setpcr(allstopped);
665 }
666 
667 
668 static void
669 opl_pcbe_sample(void *token)
670 {
671 	uint64_t		curpic;
672 	uint64_t		pcr;
673 	uint64_t		overflow;
674 	int64_t			diff;
675 	uint64_t		*pic_data[CPC_SPARC64_VI_NPIC];
676 	uint64_t		*dtmp;
677 	opl_pcbe_config_t	*pic[CPC_SPARC64_VI_NPIC];
678 	opl_pcbe_config_t	*ctmp;
679 	opl_pcbe_config_t	*firstconfig;
680 	uint8_t			bitmap = 0;	/* for used pic config */
681 	int			i;
682 	opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC];
683 	uint64_t dummypic_data[CPC_SPARC64_VI_NPIC];
684 
685 	/* Get next pic config */
686 	firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp);
687 
688 	while (ctmp != NULL) {
689 		ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC);
690 		ASSERT(firstconfig->opl_flags == ctmp->opl_flags);
691 		pic[ctmp->opl_picno] = ctmp;
692 		pic_data[ctmp->opl_picno] = dtmp;
693 		bitmap |= (uint8_t)(1 << ctmp->opl_picno);
694 		ctmp = kcpc_next_config(token, ctmp, &dtmp);
695 	}
696 	if (bitmap == 0)
697 		panic("opl_pcbe: token %p has no configs", token);
698 
699 	/* Fill in unuse pic config */
700 	for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) {
701 		if (bitmap & (1 << i))
702 			continue;
703 
704 		dummypic[i] = nullpic[i];
705 		dummypic[i].opl_flags = firstconfig->opl_flags;
706 		pic[i] = &dummypic[i];
707 
708 		dummypic_data[i] = 0;
709 		pic_data[i] = &dummypic_data[i];
710 	}
711 
712 	pcr = ultra_getpcr();
713 	pcr &= ~SPARC64_VI_PCR_OVRO;
714 	pcr |= SPARC64_VI_PCR_ULRO;
715 
716 	for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) {
717 		SPARC64_VI_PCR_SEL_PIC(pcr, i);
718 		SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits,
719 		    pic[i*2 + 1]->opl_bits);
720 
721 		ultra_setpcr(pcr);
722 
723 		curpic = ultra_getpic();
724 		DTRACE_PROBE1(sparc64__getpic, unit64_t, curpic);
725 
726 		diff = (curpic & PIC_MASK) - (uint64_t)pic[i*2]->opl_pic;
727 		overflow = SPARC64_VI_CHK_OVF(pcr, i*2);
728 		if (overflow || (diff < 0)) {
729 			SPARC64_VI_CLR_OVF(pcr, i*2);
730 			ultra_setpcr(pcr);
731 			diff += (1ll << 32);
732 		}
733 		*pic_data[i*2] += diff;
734 
735 		diff = (curpic >> 32) - (uint64_t)pic[i*2 + 1]->opl_pic;
736 		overflow = SPARC64_VI_CHK_OVF(pcr, i*2 + 1);
737 		if (overflow || (diff < 0)) {
738 			SPARC64_VI_CLR_OVF(pcr, i*2 + 1);
739 			ultra_setpcr(pcr);
740 			diff += (1ll << 32);
741 		}
742 		*pic_data[i*2 + 1] += diff;
743 
744 		pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK);
745 		pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32);
746 	}
747 	pcr = ultra_getpcr();
748 	pcr |= SPARC64_VI_PCR_OVRO;
749 	ultra_setpcr(pcr);
750 }
751 
752 static void
753 opl_pcbe_free(void *config)
754 {
755 	kmem_free(config, sizeof (opl_pcbe_config_t));
756 }
757 
758 
759 static struct modlpcbe modlpcbe = {
760 	&mod_pcbeops,
761 	"SPARC64 VI&VII Perf Cntrs v%I%",
762 	&opl_pcbe_ops
763 };
764 
765 static struct modlinkage modl = {
766 	MODREV_1,
767 	&modlpcbe,
768 };
769 
770 int
771 _init(void)
772 {
773 	if (opl_pcbe_init() != 0)
774 		return (ENOTSUP);
775 	return (mod_install(&modl));
776 }
777 
778 int
779 _fini(void)
780 {
781 	return (mod_remove(&modl));
782 }
783 
784 int
785 _info(struct modinfo *mi)
786 {
787 	return (mod_info(&modl, mi));
788 }
789