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 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 680 us_pcbe_ncounters(void) 681 { 682 return (2); 683 } 684 685 static const char * 686 us_pcbe_impl_name(void) 687 { 688 return (us_impl_name); 689 } 690 691 static const char * 692 us_pcbe_cpuref(void) 693 { 694 return (us_cpuref); 695 } 696 697 static char * 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 * 706 us_pcbe_list_attrs(void) 707 { 708 return (""); 709 } 710 711 static const us_generic_event_t * 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 * 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 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 757 us_pcbe_overflow_bitmap(void) 758 { 759 return (0x3); 760 } 761 762 /*ARGSUSED*/ 763 static int 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 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 887 us_pcbe_allstop(void) 888 { 889 ultra_setpcr(allstopped); 890 } 891 892 893 static void 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 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 963 _init(void) 964 { 965 if (us_pcbe_init() != 0) 966 return (ENOTSUP); 967 return (mod_install(&modl)); 968 } 969 970 int 971 _fini(void) 972 { 973 return (mod_remove(&modl)); 974 } 975 976 int 977 _info(struct modinfo *mi) 978 { 979 return (mod_info(&modl, mi)); 980 } 981