xref: /illumos-gate/usr/src/uts/sun4u/pcbe/us234_pcbe.c (revision c7a079a8)
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  * UltraSPARC Performance Counter Backend
68  */
69 
70 #include <sys/cpuvar.h>
71 #include <sys/systm.h>
72 #include <sys/cmn_err.h>
73 #include <sys/spitregs.h>
74 #include <sys/cheetahregs.h>
75 #include <sys/cpc_impl.h>
76 #include <sys/cpc_pcbe.h>
77 #include <sys/modctl.h>
78 #include <sys/machsystm.h>
79 #include <sys/sdt.h>
80 
81 static int us_pcbe_init(void);
82 static uint_t us_pcbe_ncounters(void);
83 static const char *us_pcbe_impl_name(void);
84 static const char *us_pcbe_cpuref(void);
85 static char *us_pcbe_list_events(uint_t picnum);
86 static char *us_pcbe_list_attrs(void);
87 static uint64_t us_pcbe_event_coverage(char *event);
88 static uint64_t us_pcbe_overflow_bitmap(void);
89 static int us_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
90     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
91     void *token);
92 static void us_pcbe_program(void *token);
93 static void us_pcbe_allstop(void);
94 static void us_pcbe_sample(void *token);
95 static void us_pcbe_free(void *config);
96 
97 extern void ultra_setpcr(uint64_t);
98 extern uint64_t ultra_getpcr(void);
99 extern void ultra_setpic(uint64_t);
100 extern uint64_t ultra_getpic(void);
101 extern uint64_t ultra_gettick(void);
102 
103 pcbe_ops_t us_pcbe_ops = {
104 	PCBE_VER_1,
105 	CPC_CAP_OVERFLOW_INTERRUPT,
106 	us_pcbe_ncounters,
107 	us_pcbe_impl_name,
108 	us_pcbe_cpuref,
109 	us_pcbe_list_events,
110 	us_pcbe_list_attrs,
111 	us_pcbe_event_coverage,
112 	us_pcbe_overflow_bitmap,
113 	us_pcbe_configure,
114 	us_pcbe_program,
115 	us_pcbe_allstop,
116 	us_pcbe_sample,
117 	us_pcbe_free
118 };
119 
120 typedef struct _us_pcbe_config {
121 	uint8_t		us_picno;	/* 0 for pic0 or 1 for pic1 */
122 	uint32_t	us_bits;	/* %pcr event code unshifted */
123 	uint32_t	us_flags;	/* user/system/priv */
124 	uint32_t	us_pic;		/* unshifted raw %pic value */
125 } us_pcbe_config_t;
126 
127 struct nametable {
128 	const uint8_t	bits;
129 	const char	*name;
130 };
131 
132 typedef struct _us_generic_event {
133 	char *name;
134 	char *event;
135 } us_generic_event_t;
136 
137 #define	PIC0_MASK (((uint64_t)1 << 32) - 1)
138 
139 #define	ULTRA_PCR_SYS		(UINT64_C(1) << CPC_ULTRA_PCR_SYS)
140 #define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_ULTRA_PCR_PRIVPIC)
141 
142 #define	CPC_ULTRA_PCR_USR		2
143 #define	CPC_ULTRA_PCR_SYS		1
144 #define	CPC_ULTRA_PCR_PRIVPIC		0
145 
146 #define	CPC_ULTRA_PCR_PIC0_SHIFT	4
147 #define	CPC_ULTRA2_PCR_PIC_MASK		UINT64_C(0xf)
148 #define	CPC_ULTRA3_PCR_PIC_MASK		UINT64_C(0x3f)
149 #define	CPC_ULTRA_PCR_PIC1_SHIFT	11
150 
151 #define	NT_END 0xFF
152 #define	CPC_GEN_END { NULL, NULL }
153 
154 static const uint64_t   allstopped = ULTRA_PCR_PRIVPIC;
155 
156 #define	USall_EVENTS_0						\
157 	{0x0,	"Cycle_cnt"},					\
158 	{0x1,	"Instr_cnt"},					\
159 	{0x2,	"Dispatch0_IC_miss"},				\
160 	{0x8,	"IC_ref"},					\
161 	{0x9,	"DC_rd"},					\
162 	{0xa,	"DC_wr"},					\
163 	{0xc,	"EC_ref"},					\
164 	{0xe,	"EC_snoop_inv"}
165 
166 static const struct nametable US12_names0[] = {
167 	USall_EVENTS_0,
168 	{0x3,	"Dispatch0_storeBuf"},
169 	{0xb,	"Load_use"},
170 	{0xd,	"EC_write_hit_RDO"},
171 	{0xf,	"EC_rd_hit"},
172 	{NT_END, ""}
173 };
174 
175 #define	US3all_EVENTS_0						\
176 	{0x3,	"Dispatch0_br_target"},				\
177 	{0x4,	"Dispatch0_2nd_br"},				\
178 	{0x5,	"Rstall_storeQ"},				\
179 	{0x6,	"Rstall_IU_use"},				\
180 	{0xd,	"EC_write_hit_RTO"},				\
181 	{0xf,	"EC_rd_miss"},					\
182 	{0x10,	"PC_port0_rd"},					\
183 	{0x11,	"SI_snoop"},					\
184 	{0x12,	"SI_ciq_flow"},					\
185 	{0x13,	"SI_owned"},					\
186 	{0x14,	"SW_count_0"},					\
187 	{0x15,	"IU_Stat_Br_miss_taken"},			\
188 	{0x16,	"IU_Stat_Br_count_taken"},			\
189 	{0x17,	"Dispatch_rs_mispred"},				\
190 	{0x18,	"FA_pipe_completion"}
191 
192 #define	US3_MC_EVENTS_0						\
193 	{0x20,	"MC_reads_0"},					\
194 	{0x21,	"MC_reads_1"},					\
195 	{0x22,	"MC_reads_2"},					\
196 	{0x23,	"MC_reads_3"},					\
197 	{0x24,	"MC_stalls_0"},					\
198 	{0x25,	"MC_stalls_2"}
199 
200 #define	US3_I_MC_EVENTS_0					\
201 	{0x20,	"MC_read_dispatched"},				\
202 	{0x21,	"MC_write_dispatched"},				\
203 	{0x22,	"MC_read_returned_to_JBU"},			\
204 	{0x23,	"MC_msl_busy_stall"},				\
205 	{0x24,	"MC_mdb_overflow_stall"},			\
206 	{0x25,	"MC_miu_spec_request"}
207 
208 #define	USall_EVENTS_1						\
209 	{0x0,	"Cycle_cnt"},					\
210 	{0x1,	"Instr_cnt"},					\
211 	{0x2,	"Dispatch0_mispred"},				\
212 	{0xd,	"EC_wb"},					\
213 	{0xe,	"EC_snoop_cb"}
214 
215 static const struct nametable US3_names0[] = {
216 	USall_EVENTS_0,
217 	US3all_EVENTS_0,
218 	US3_MC_EVENTS_0,
219 	{NT_END, ""}
220 };
221 
222 static const struct nametable US3_PLUS_names0[] = {
223 	USall_EVENTS_0,
224 	US3all_EVENTS_0,
225 	US3_MC_EVENTS_0,
226 	{0x19,	"EC_wb_remote"},
227 	{0x1a,	"EC_miss_local"},
228 	{0x1b,	"EC_miss_mtag_remote"},
229 	{NT_END, ""}
230 };
231 
232 static const struct nametable US3_I_names0[] = {
233 	USall_EVENTS_0,
234 	US3all_EVENTS_0,
235 	US3_I_MC_EVENTS_0,
236 	{NT_END, ""}
237 };
238 
239 static const struct nametable US4_PLUS_names0[] = {
240 	{0x0,   "Cycle_cnt"},
241 	{0x1,   "Instr_cnt"},
242 	{0x2,   "Dispatch0_IC_miss"},
243 	{0x3,   "IU_stat_jmp_correct_pred"},
244 	{0x4,   "Dispatch0_2nd_br"},
245 	{0x5,   "Rstall_storeQ"},
246 	{0x6,   "Rstall_IU_use"},
247 	{0x7,   "IU_stat_ret_correct_pred"},
248 	{0x8,   "IC_ref"},
249 	{0x9,   "DC_rd"},
250 	{0xa,   "Rstall_FP_use"},
251 	{0xb,   "SW_pf_instr"},
252 	{0xc,   "L2_ref"},
253 	{0xd,   "L2_write_hit_RTO"},
254 	{0xe,   "L2_snoop_inv_sh"},
255 	{0xf,   "L2_rd_miss"},
256 	{0x10,  "PC_rd"},
257 	{0x11,  "SI_snoop_sh"},
258 	{0x12,  "SI_ciq_flow_sh"},
259 	{0x13,  "Re_DC_miss"},
260 	{0x14,  "SW_count_NOP"},
261 	{0x15,  "IU_stat_br_miss_taken"},
262 	{0x16,  "IU_stat_br_count_untaken"},
263 	{0x17,  "HW_pf_exec"},
264 	{0x18,  "FA_pipe_completion"},
265 	{0x19,  "SSM_L3_wb_remote"},
266 	{0x1a,  "SSM_L3_miss_local"},
267 	{0x1b,  "SSM_L3_miss_mtag_remote"},
268 	{0x1c,  "SW_pf_str_trapped"},
269 	{0x1d,  "SW_pf_PC_installed"},
270 	{0x1e,  "IPB_to_IC_fill"},
271 	{0x1f,  "L2_write_miss"},
272 	{0x20,  "MC_reads_0_sh"},
273 	{0x21,  "MC_reads_1_sh"},
274 	{0x22,  "MC_reads_2_sh"},
275 	{0x23,  "MC_reads_3_sh"},
276 	{0x24,  "MC_stalls_0_sh"},
277 	{0x25,  "MC_stalls_2_sh"},
278 	{0x26,  "L2_hit_other_half"},
279 	{0x28,  "L3_rd_miss"},
280 	{0x29,  "Re_L2_miss"},
281 	{0x2a,  "IC_miss_cancelled"},
282 	{0x2b,  "DC_wr_miss"},
283 	{0x2c,  "L3_hit_I_state_sh"},
284 	{0x2d,  "SI_RTS_src_data"},
285 	{0x2e,  "L2_IC_miss"},
286 	{0x2f,  "SSM_new_transaction_sh"},
287 	{0x30,  "L2_SW_pf_miss"},
288 	{0x31,  "L2_wb"},
289 	{0x32,  "L2_wb_sh"},
290 	{0x33,  "L2_snoop_cb_sh"},
291 	{NT_END, ""}
292 };
293 
294 
295 #define	US3all_EVENTS_1				\
296 	{0x3,	"IC_miss_cancelled"},		\
297 	{0x5,	"Re_FPU_bypass"},		\
298 	{0x6,	"Re_DC_miss"},			\
299 	{0x7,	"Re_EC_miss"},			\
300 	{0x8,	"IC_miss"},			\
301 	{0x9,	"DC_rd_miss"},			\
302 	{0xa,	"DC_wr_miss"},			\
303 	{0xb,	"Rstall_FP_use"},		\
304 	{0xc,	"EC_misses"},			\
305 	{0xf,	"EC_ic_miss"},			\
306 	{0x10,	"Re_PC_miss"},			\
307 	{0x11,	"ITLB_miss"},			\
308 	{0x12,	"DTLB_miss"},			\
309 	{0x13,	"WC_miss"},			\
310 	{0x14,	"WC_snoop_cb"},			\
311 	{0x15,	"WC_scrubbed"},			\
312 	{0x16,	"WC_wb_wo_read"},		\
313 	{0x18,	"PC_soft_hit"},			\
314 	{0x19,	"PC_snoop_inv"},		\
315 	{0x1a,	"PC_hard_hit"},			\
316 	{0x1b,	"PC_port1_rd"},			\
317 	{0x1c,	"SW_count_1"},			\
318 	{0x1d,	"IU_Stat_Br_miss_untaken"},	\
319 	{0x1e,	"IU_Stat_Br_count_untaken"},	\
320 	{0x1f,	"PC_MS_misses"},		\
321 	{0x26,	"Re_RAW_miss"},			\
322 	{0x27,	"FM_pipe_completion"}
323 
324 #define	US3_MC_EVENTS_1				\
325 	{0x20,	"MC_writes_0"},			\
326 	{0x21,	"MC_writes_1"},			\
327 	{0x22,	"MC_writes_2"},			\
328 	{0x23,	"MC_writes_3"},			\
329 	{0x24,	"MC_stalls_1"},			\
330 	{0x25,	"MC_stalls_3"}
331 
332 #define	US3_I_MC_EVENTS_1			\
333 	{0x20,	"MC_open_bank_cmds"},		\
334 	{0x21,	"MC_reads"},			\
335 	{0x22,	"MC_writes"},			\
336 	{0x23,	"MC_page_close_stall"}
337 
338 static const struct nametable US3_names1[] = {
339 	USall_EVENTS_1,
340 	US3all_EVENTS_1,
341 	US3_MC_EVENTS_1,
342 	{0x4,	"Re_endian_miss"},
343 	{NT_END, ""}
344 };
345 
346 static const struct nametable US3_PLUS_names1[] = {
347 	USall_EVENTS_1,
348 	US3all_EVENTS_1,
349 	US3_MC_EVENTS_1,
350 	{0x4,	"Re_DC_missovhd"},
351 	{0x28,	"EC_miss_mtag_remote"},
352 	{0x29,	"EC_miss_remote"},
353 	{NT_END, ""}
354 };
355 
356 static const struct nametable US3_I_names1[] = {
357 	USall_EVENTS_1,
358 	US3all_EVENTS_1,
359 	US3_I_MC_EVENTS_1,
360 	{0x4,	"Re_DC_missovhd"},
361 	{NT_END, ""}
362 };
363 
364 static const struct nametable US4_PLUS_names1[] = {
365 	{0x0,   "Cycle_cnt"},
366 	{0x1,   "Instr_cnt"},
367 	{0x2,   "Dispatch0_other"},
368 	{0x3,   "DC_wr"},
369 	{0x4,   "Re_DC_missovhd"},
370 	{0x5,   "Re_FPU_bypass"},
371 	{0x6,   "L3_write_hit_RTO"},
372 	{0x7,   "L2L3_snoop_inv_sh"},
373 	{0x8,   "IC_L2_req"},
374 	{0x9,   "DC_rd_miss"},
375 	{0xa,   "L2_hit_I_state_sh"},
376 	{0xb,   "L3_write_miss_RTO"},
377 	{0xc,   "L2_miss"},
378 	{0xd,   "SI_owned_sh"},
379 	{0xe,   "SI_RTO_src_data"},
380 	{0xf,   "SW_pf_duplicate"},
381 	{0x10,  "IU_stat_jmp_mispred"},
382 	{0x11,  "ITLB_miss"},
383 	{0x12,  "DTLB_miss"},
384 	{0x13,  "WC_miss"},
385 	{0x14,  "IC_fill"},
386 	{0x15,  "IU_stat_ret_mispred"},
387 	{0x16,  "Re_L3_miss"},
388 	{0x17,  "Re_PFQ_full"},
389 	{0x18,  "PC_soft_hit"},
390 	{0x19,  "PC_inv"},
391 	{0x1a,  "PC_hard_hit"},
392 	{0x1b,  "IC_pf"},
393 	{0x1c,  "SW_count_NOP"},
394 	{0x1d,  "IU_stat_br_miss_untaken"},
395 	{0x1e,  "IU_stat_br_count_taken"},
396 	{0x1f,  "PC_miss"},
397 	{0x20,  "MC_writes_0_sh"},
398 	{0x21,  "MC_writes_1_sh"},
399 	{0x22,  "MC_writes_2_sh"},
400 	{0x23,  "MC_writes_3_sh"},
401 	{0x24,  "MC_stalls_1_sh"},
402 	{0x25,  "MC_stalls_3_sh"},
403 	{0x26,  "Re_RAW_miss"},
404 	{0x27,  "FM_pipe_completion"},
405 	{0x28,  "SSM_L3_miss_mtag_remote"},
406 	{0x29,  "SSM_L3_miss_remote"},
407 	{0x2a,  "SW_pf_exec"},
408 	{0x2b,  "SW_pf_str_exec"},
409 	{0x2c,  "SW_pf_dropped"},
410 	{0x2d,  "SW_pf_L2_installed"},
411 	{0x2f,  "L2_HW_pf_miss"},
412 	{0x31,  "L3_miss"},
413 	{0x32,  "L3_IC_miss"},
414 	{0x33,  "L3_SW_pf_miss"},
415 	{0x34,  "L3_hit_other_half"},
416 	{0x35,  "L3_wb"},
417 	{0x36,  "L3_wb_sh"},
418 	{0x37,  "L2L3_snoop_cb_sh"},
419 	{NT_END, ""}
420 };
421 
422 static const struct nametable US12_names1[] = {
423 	USall_EVENTS_1,
424 	{0x3,	"Dispatch0_FP_use"},
425 	{0x8,	"IC_hit"},
426 	{0x9,	"DC_rd_hit"},
427 	{0xa,	"DC_wr_hit"},
428 	{0xb,	"Load_use_RAW"},
429 	{0xc,	"EC_hit"},
430 	{0xf,	"EC_ic_hit"},
431 	{NT_END, ""}
432 };
433 
434 static const struct nametable *US12_names[2] = {
435 	US12_names0,
436 	US12_names1
437 };
438 
439 static const struct nametable *US3_names[2] = {
440 	US3_names0,
441 	US3_names1
442 };
443 
444 static const struct nametable *US3_PLUS_names[2] = {
445 	US3_PLUS_names0,
446 	US3_PLUS_names1
447 };
448 
449 static const struct nametable *US4_PLUS_names[2] = {
450 	US4_PLUS_names0,
451 	US4_PLUS_names1
452 };
453 
454 static const struct nametable *US3_I_names[2] = {
455 	US3_I_names0,
456 	US3_I_names1
457 };
458 
459 static const us_generic_event_t US12_generic_names0[] = {
460 	{ "PAPI_tot_cyc",  "Cycle_cnt" },
461 	{ "PAPI_tot_ins",  "Instr_cnt" },
462 	{ "PAPI_tot_iis",  "Instr_cnt" },
463 	{ "PAPI_l1_dcr",   "DC_rd" },
464 	{ "PAPI_l1_dcw",   "DC_wr" },
465 	{ "PAPI_l1_ica",   "IC_ref" },
466 	{ "PAPI_l2_tca",   "EC_ref" },
467 	{ "PAPI_l2_dch",   "EC_rd_hit" },
468 	{ "PAPI_ca_inv",   "EC_snoop_inv" },
469 	CPC_GEN_END
470 };
471 
472 static const us_generic_event_t US12_generic_names1[] = {
473 	{ "PAPI_tot_cyc",  "Cycle_cnt" },
474 	{ "PAPI_tot_ins",  "Instr_cnt" },
475 	{ "PAPI_tot_iis",  "Instr_cnt" },
476 	{ "PAPI_br_msp",   "Dispatch0_mispred" },
477 	{ "PAPI_ca_snp",   "EC_snoop_cb" },
478 	{ "PAPI_l1_ich",   "IC_hit" },
479 	{ "PAPI_l2_tch",   "EC_hit" },
480 	{ "PAPI_l2_ich",   "EC_ic_hit" },
481 	CPC_GEN_END
482 };
483 
484 static const us_generic_event_t US3_generic_names0[] = {
485 	{ "PAPI_tot_cyc",  "Cycle_cnt" },
486 	{ "PAPI_tot_ins",  "Instr_cnt" },
487 	{ "PAPI_tot_iis",  "Instr_cnt" },
488 	{ "PAPI_fad_ins",  "FA_pipe_completion" },
489 	{ "PAPI_l1_dcr",   "DC_rd" },
490 	{ "PAPI_l1_dcw",   "DC_wr" },
491 	{ "PAPI_l1_ica",   "IC_ref" },
492 	{ "PAPI_l2_tca",   "EC_ref" },
493 	{ "PAPI_l2_ldm",   "EC_rd_miss" },
494 	{ "PAPI_ca_inv",   "EC_snoop_inv" },
495 	{ "PAPI_br_tkn",   "IU_Stat_Br_count_taken" },
496 	CPC_GEN_END
497 };
498 
499 static const us_generic_event_t US3_generic_names1[] = {
500 	{ "PAPI_tot_cyc",  "Cycle_cnt" },
501 	{ "PAPI_tot_ins",  "Instr_cnt" },
502 	{ "PAPI_tot_iis",  "Instr_cnt" },
503 	{ "PAPI_fml_ins",  "FM_pipe_completion" },
504 	{ "PAPI_l1_icm",   "IC_miss" },
505 	{ "PAPI_l1_ldm",   "DC_rd_miss" },
506 	{ "PAPI_l1_stm",   "DC_wr_miss" },
507 	{ "PAPI_l2_tcm",   "EC_misses" },
508 	{ "PAPI_l2_icm",   "EC_ic_miss" },
509 	{ "PAPI_tlb_dm",   "DTLB_miss" },
510 	{ "PAPI_tlb_im",   "ITLB_miss" },
511 	{ "PAPI_br_ntk",   "IU_Stat_Br_count_untaken" },
512 	{ "PAPI_br_msp",   "Dispatch0_mispred" },
513 	{ "PAPI_ca_snp",   "EC_snoop_cb" },
514 	CPC_GEN_END
515 };
516 
517 static const us_generic_event_t US4_PLUS_generic_names0[] = {
518 	{ "PAPI_tot_cyc",  "Cycle_cnt" },
519 	{ "PAPI_tot_ins",  "Instr_cnt" },
520 	{ "PAPI_tot_iis",  "Instr_cnt" },
521 	{ "PAPI_fma_ins",  "FA_pipe_completion" },
522 	{ "PAPI_l1_dcr",   "DC_rd" },
523 	{ "PAPI_l1_stm",   "DC_wr_miss" },
524 	{ "PAPI_l1_ica",   "IC_ref" },
525 	{ "PAPI_l2_tca",   "L2_ref" },
526 	{ "PAPI_l2_ldm",   "L2_rd_miss" },
527 	{ "PAPI_l2_icm",   "L2_IC_miss" },
528 	{ "PAPI_l2_stm",   "L2_write_miss" },
529 	{ "PAPI_l3_ldm",   "L3_rd_miss" },
530 	{ "PAPI_br_ntk",   "IU_stat_br_count_untaken" },
531 	CPC_GEN_END
532 };
533 
534 static const us_generic_event_t US4_PLUS_generic_names1[] = {
535 	{ "PAPI_tot_cyc", "Cycle_cnt" },
536 	{ "PAPI_tot_ins", "Instr_cnt" },
537 	{ "PAPI_tot_iis",  "Instr_cnt" },
538 	{ "PAPI_fml_ins",  "FM_pipe_completion" },
539 	{ "PAPI_l1_icm",   "IC_L2_req" },
540 	{ "PAPI_l1_ldm",   "DC_rd_miss" },
541 	{ "PAPI_l1_dcw",   "DC_wr" },
542 	{ "PAPI_l2_tcm",   "L2_miss" },
543 	{ "PAPI_l3_tcm",   "L3_miss" },
544 	{ "PAPI_l3_icm",   "L3_IC_miss" },
545 	{ "PAPI_tlb_im",   "ITLB_miss" },
546 	{ "PAPI_tlb_dm",   "DTLB_miss" },
547 	{ "PAPI_br_tkn",   "IU_stat_br_count_taken" },
548 	CPC_GEN_END
549 };
550 
551 static const us_generic_event_t *US12_generic_names[2] = {
552 	US12_generic_names0,
553 	US12_generic_names1
554 };
555 
556 static const us_generic_event_t *US3_generic_names[2] = {
557 	US3_generic_names0,
558 	US3_generic_names1
559 };
560 
561 static const us_generic_event_t *US4_PLUS_generic_names[2] = {
562 	US4_PLUS_generic_names0,
563 	US4_PLUS_generic_names1
564 };
565 
566 static const struct nametable **events;
567 static const us_generic_event_t **generic_events;
568 static const char *us_impl_name;
569 static const char *us_cpuref;
570 static char *pic_events[2];
571 static uint16_t pcr_pic_mask;
572 
573 #define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
574 			"http://www.sun.com/processors/manuals"
575 
576 static const char *us_2_ref = "See the \"UltraSPARC I/II User\'s Manual\" "
577 			"(Part No. 802-7220-02) "
578 			"for descriptions of these events." CPU_REF_URL;
579 
580 static const char *us_3cu_ref = "See the \"UltraSPARC III Cu User's Manual\" "
581 			"for descriptions of these events." CPU_REF_URL;
582 
583 static const char *us4_plus_ref = "See the \"UltraSPARC IV+ User's Manual\" "
584 			"for descriptions of these events." CPU_REF_URL;
585 
586 static const char *us_3i_ref = "See the \"UltraSPARC IIIi User's Manual\"  "
587 			"for descriptions of these events." CPU_REF_URL;
588 
589 static int
us_pcbe_init(void)590 us_pcbe_init(void)
591 {
592 	const struct nametable		*n;
593 	const us_generic_event_t	*gevp;
594 	int				i;
595 	size_t				size;
596 
597 	/*
598 	 * Discover type of CPU
599 	 *
600 	 * Point nametable to that CPU's table
601 	 */
602 	switch (ULTRA_VER_IMPL(ultra_getver())) {
603 	case SPITFIRE_IMPL:
604 	case BLACKBIRD_IMPL:
605 	case SABRE_IMPL:
606 	case HUMMBRD_IMPL:
607 		events = US12_names;
608 		generic_events = US12_generic_names;
609 		us_impl_name = "UltraSPARC I&II";
610 		us_cpuref = us_2_ref;
611 		pcr_pic_mask = CPC_ULTRA2_PCR_PIC_MASK;
612 		us_pcbe_ops.pcbe_caps &= ~CPC_CAP_OVERFLOW_INTERRUPT;
613 		break;
614 	case CHEETAH_IMPL:
615 		events = US3_names;
616 		generic_events = US3_generic_names;
617 		us_impl_name = "UltraSPARC III";
618 		us_cpuref = us_3cu_ref;
619 		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
620 		break;
621 	case CHEETAH_PLUS_IMPL:
622 	case JAGUAR_IMPL:
623 		events = US3_PLUS_names;
624 		generic_events = US3_generic_names;
625 		us_impl_name = "UltraSPARC III+ & IV";
626 		us_cpuref = us_3cu_ref;
627 		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
628 		break;
629 	case PANTHER_IMPL:
630 		events = US4_PLUS_names;
631 		generic_events = US4_PLUS_generic_names;
632 		us_impl_name = "UltraSPARC IV+";
633 		us_cpuref = us4_plus_ref;
634 		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
635 		break;
636 	case JALAPENO_IMPL:
637 	case SERRANO_IMPL:
638 		events = US3_I_names;
639 		generic_events = US3_generic_names;
640 		us_impl_name = "UltraSPARC IIIi & IIIi+";
641 		us_cpuref = us_3i_ref;
642 		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
643 		break;
644 	default:
645 		return (-1);
646 	}
647 
648 	/*
649 	 * Initialize the list of events for each PIC.
650 	 * Do two passes: one to compute the size necessary and another
651 	 * to copy the strings. Need room for event, comma, and NULL terminator.
652 	 */
653 	for (i = 0; i < 2; i++) {
654 		size = 0;
655 		for (n = events[i]; n->bits != NT_END; n++)
656 			size += strlen(n->name) + 1;
657 		for (gevp = generic_events[i]; gevp->name != NULL; gevp++)
658 			size += strlen(gevp->name) + 1;
659 		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
660 		*pic_events[i] = '\0';
661 		for (n = events[i]; n->bits != NT_END; n++) {
662 			(void) strcat(pic_events[i], n->name);
663 			(void) strcat(pic_events[i], ",");
664 		}
665 		for (gevp = generic_events[i]; gevp->name != NULL; gevp++) {
666 			(void) strcat(pic_events[i], gevp->name);
667 			(void) strcat(pic_events[i], ",");
668 		}
669 
670 		/*
671 		 * Remove trailing comma.
672 		 */
673 		pic_events[i][size - 1] = '\0';
674 	}
675 
676 	return (0);
677 }
678 
679 static uint_t
us_pcbe_ncounters(void)680 us_pcbe_ncounters(void)
681 {
682 	return (2);
683 }
684 
685 static const char *
us_pcbe_impl_name(void)686 us_pcbe_impl_name(void)
687 {
688 	return (us_impl_name);
689 }
690 
691 static const char *
us_pcbe_cpuref(void)692 us_pcbe_cpuref(void)
693 {
694 	return (us_cpuref);
695 }
696 
697 static char *
us_pcbe_list_events(uint_t picnum)698 us_pcbe_list_events(uint_t picnum)
699 {
700 	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
701 
702 	return (pic_events[picnum]);
703 }
704 
705 static char *
us_pcbe_list_attrs(void)706 us_pcbe_list_attrs(void)
707 {
708 	return ("");
709 }
710 
711 static const us_generic_event_t *
find_generic_event(int regno,char * name)712 find_generic_event(int regno, char *name)
713 {
714 	const us_generic_event_t *gevp;
715 
716 	for (gevp = generic_events[regno]; gevp->name != NULL; gevp++)
717 		if (strcmp(name, gevp->name) == 0)
718 			return (gevp);
719 
720 	return (NULL);
721 }
722 
723 static const struct nametable *
find_event(int regno,char * name)724 find_event(int regno, char *name)
725 {
726 	const struct nametable *n;
727 
728 	n = events[regno];
729 
730 	for (; n->bits != NT_END; n++)
731 		if (strcmp(name, n->name) == 0)
732 			return (n);
733 
734 	return (NULL);
735 }
736 
737 static uint64_t
us_pcbe_event_coverage(char * event)738 us_pcbe_event_coverage(char *event)
739 {
740 	uint64_t bitmap = 0;
741 
742 	if ((find_event(0, event) != NULL) ||
743 	    (find_generic_event(0, event) != NULL))
744 		bitmap = 0x1;
745 	if ((find_event(1, event) != NULL) ||
746 	    (find_generic_event(1, event) != NULL))
747 		bitmap |= 0x2;
748 
749 	return (bitmap);
750 }
751 
752 /*
753  * These processors cannot tell which counter overflowed. The PCBE interface
754  * requires such processors to act as if _all_ counters had overflowed.
755  */
756 static uint64_t
us_pcbe_overflow_bitmap(void)757 us_pcbe_overflow_bitmap(void)
758 {
759 	return (0x3);
760 }
761 
762 /*ARGSUSED*/
763 static int
us_pcbe_configure(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data,void * token)764 us_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
765     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
766 {
767 	us_pcbe_config_t		*conf;
768 	const struct nametable		*n;
769 	const us_generic_event_t	*gevp;
770 	us_pcbe_config_t		*other_config;
771 
772 	/*
773 	 * If we've been handed an existing configuration, we need only preset
774 	 * the counter value.
775 	 */
776 	if (*data != NULL) {
777 		conf = *data;
778 		conf->us_pic = (uint32_t)preset;
779 		return (0);
780 	}
781 
782 	if (picnum < 0 || picnum > 1)
783 		return (CPC_INVALID_PICNUM);
784 
785 	if (nattrs != 0)
786 		return (CPC_INVALID_ATTRIBUTE);
787 
788 	/*
789 	 * Find other requests that will be programmed with this one, and ensure
790 	 * the flags don't conflict.
791 	 */
792 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
793 	    (other_config->us_flags != flags))
794 		return (CPC_CONFLICTING_REQS);
795 
796 	if ((n = find_event(picnum, event)) == NULL) {
797 		if ((gevp = find_generic_event(picnum, event)) != NULL) {
798 			n = find_event(picnum, gevp->event);
799 			ASSERT(n != NULL);
800 		} else {
801 			return (CPC_INVALID_EVENT);
802 		}
803 	}
804 
805 	conf = kmem_alloc(sizeof (us_pcbe_config_t), KM_SLEEP);
806 
807 	conf->us_picno = picnum;
808 	conf->us_bits = (uint32_t)n->bits;
809 	conf->us_flags = flags;
810 	conf->us_pic = (uint32_t)preset;
811 
812 	*data = conf;
813 	return (0);
814 }
815 
816 static void
us_pcbe_program(void * token)817 us_pcbe_program(void *token)
818 {
819 	us_pcbe_config_t	*pic0;
820 	us_pcbe_config_t	*pic1;
821 	us_pcbe_config_t	*tmp;
822 	us_pcbe_config_t	empty = { 1, 0x1c, 0, 0 }; /* SW_count_1 */
823 	uint64_t		pcr;
824 	uint64_t		curpic;
825 
826 	if ((pic0 = (us_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
827 	    NULL)
828 		panic("us_pcbe: token %p has no configs", token);
829 
830 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
831 		pic1 = &empty;
832 		empty.us_flags = pic0->us_flags;
833 	}
834 
835 	if (pic0->us_picno != 0) {
836 		/*
837 		 * pic0 is counter 1, so if we need the empty config it should
838 		 * be counter 0.
839 		 */
840 		empty.us_picno = 0;
841 		empty.us_bits = 0x14; /* SW_count_0 - won't overflow */
842 		tmp = pic0;
843 		pic0 = pic1;
844 		pic1 = tmp;
845 	}
846 
847 	if (pic0->us_picno != 0 || pic1->us_picno != 1)
848 		panic("us_pcbe: bad config on token %p\n", token);
849 
850 	/*
851 	 * UltraSPARC does not allow pic0 to be configured differently
852 	 * from pic1. If the flags on these two configurations are
853 	 * different, they are incompatible. This condition should be
854 	 * caught at configure time.
855 	 */
856 	ASSERT(pic0->us_flags == pic1->us_flags);
857 
858 	ultra_setpcr(allstopped);
859 	ultra_setpic(((uint64_t)pic1->us_pic << 32) | (uint64_t)pic0->us_pic);
860 
861 	pcr = (pic0->us_bits & pcr_pic_mask) <<
862 	    CPC_ULTRA_PCR_PIC0_SHIFT;
863 	pcr |= (pic1->us_bits & pcr_pic_mask) <<
864 	    CPC_ULTRA_PCR_PIC1_SHIFT;
865 
866 	if (pic0->us_flags & CPC_COUNT_USER)
867 		pcr |= (1ull << CPC_ULTRA_PCR_USR);
868 	if (pic0->us_flags & CPC_COUNT_SYSTEM)
869 		pcr |= (1ull << CPC_ULTRA_PCR_SYS);
870 
871 	DTRACE_PROBE1(ultra__pcr, uint64_t, pcr);
872 
873 	ultra_setpcr(pcr);
874 
875 	/*
876 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
877 	 * expect the value we wrote into the PIC, above, to be there after
878 	 * starting the counter. We must sample the counter value now and use
879 	 * that as the baseline for future samples.
880 	 */
881 	curpic = ultra_getpic();
882 	pic0->us_pic = (uint32_t)(curpic & PIC0_MASK);
883 	pic1->us_pic = (uint32_t)(curpic >> 32);
884 }
885 
886 static void
us_pcbe_allstop(void)887 us_pcbe_allstop(void)
888 {
889 	ultra_setpcr(allstopped);
890 }
891 
892 
893 static void
us_pcbe_sample(void * token)894 us_pcbe_sample(void *token)
895 {
896 	uint64_t		curpic;
897 	int64_t			diff;
898 	uint64_t		*pic0_data;
899 	uint64_t		*pic1_data;
900 	uint64_t		*dtmp;
901 	uint64_t		tmp;
902 	us_pcbe_config_t	*pic0;
903 	us_pcbe_config_t	*pic1;
904 	us_pcbe_config_t	empty = { 1, 0, 0, 0 };
905 	us_pcbe_config_t	*ctmp;
906 
907 	curpic = ultra_getpic();
908 
909 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
910 		panic("us_pcbe: token %p has no configs", token);
911 
912 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
913 		pic1 = &empty;
914 		pic1_data = &tmp;
915 	}
916 
917 	if (pic0->us_picno != 0) {
918 		empty.us_picno = 0;
919 		ctmp = pic0;
920 		pic0 = pic1;
921 		pic1 = ctmp;
922 		dtmp = pic0_data;
923 		pic0_data = pic1_data;
924 		pic1_data = dtmp;
925 	}
926 
927 	if (pic0->us_picno != 0 || pic1->us_picno != 1)
928 		panic("us_pcbe: bad config on token %p\n", token);
929 
930 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->us_pic;
931 	if (diff < 0)
932 		diff += (1ll << 32);
933 	*pic0_data += diff;
934 
935 	diff = (curpic >> 32) - (uint64_t)pic1->us_pic;
936 	if (diff < 0)
937 		diff += (1ll << 32);
938 	*pic1_data += diff;
939 
940 	pic0->us_pic = (uint32_t)(curpic & PIC0_MASK);
941 	pic1->us_pic = (uint32_t)(curpic >> 32);
942 }
943 
944 static void
us_pcbe_free(void * config)945 us_pcbe_free(void *config)
946 {
947 	kmem_free(config, sizeof (us_pcbe_config_t));
948 }
949 
950 
951 static struct modlpcbe modlpcbe = {
952 	&mod_pcbeops,
953 	"UltraSPARC Performance Counters",
954 	&us_pcbe_ops
955 };
956 
957 static struct modlinkage modl = {
958 	MODREV_1,
959 	&modlpcbe,
960 };
961 
962 int
_init(void)963 _init(void)
964 {
965 	if (us_pcbe_init() != 0)
966 		return (ENOTSUP);
967 	return (mod_install(&modl));
968 }
969 
970 int
_fini(void)971 _fini(void)
972 {
973 	return (mod_remove(&modl));
974 }
975 
976 int
_info(struct modinfo * mi)977 _info(struct modinfo *mi)
978 {
979 	return (mod_info(&modl, mi));
980 }
981