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