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