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 = ∅
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 = ∅
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