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 2007 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 {0x1d, "act_thread_suspend"}, 235 {0x1e, "cse_window_empty"}, 236 {0x1f, "inh_cmit_gpr_2write"}, 237 {0x23, "if_l1_thrashing"}, 238 {0x24, "swpf_success_all"}, 239 {0x30, "sx_miss_wait_dm"}, 240 {0x31, "jbus_bi_count"}, 241 {0x34, "lost_softpf_pfp_full"}, 242 {0x36, "jbus_reqbus0_busy"}, 243 {NT_END, ""} 244 }; 245 246 static const struct nametable SPARC64_VI_names_l1[] = { 247 SPARC64_VI_EVENTS_comm_0, 248 {0x2, "single_mode_instructions"}, 249 {0x3, "w_branch_comp_wait"}, 250 {0x4, "w_op_stv_wait_sxmiss_ex"}, 251 SPARC64_VI_EVENTS_comm_1, 252 {0x13, "4iid_use"}, 253 {0x15, "flush_rs"}, 254 {0x16, "trap_spill"}, 255 {0x18, "ts_by_timer"}, 256 SPARC64_VI_EVENTS_comm_2, 257 {0x1b, "0iid_use"}, 258 {0x1d, "op_stv_wait_nc_pend"}, 259 {0x1e, "0endop"}, 260 {0x20, "write_op_uTLB"}, 261 {0x30, "sx_miss_count_pf"}, 262 {0x31, "jbus_cpd_count"}, 263 {0x32, "snres_64"}, 264 {0x36, "jbus_reqbus3_busy"}, 265 {NT_END, ""} 266 }; 267 268 static const struct nametable SPARC64_VI_names_u1[] = { 269 SPARC64_VI_EVENTS_comm_0, 270 {0x2, "single_mode_cycle_counts"}, 271 {0x3, "w_eu_comp_wait"}, 272 {0x4, "w_op_stv_wait_sxmiss"}, 273 SPARC64_VI_EVENTS_comm_1, 274 {0x13, "3iid_use"}, 275 {0x16, "trap_int_level"}, 276 {0x18, "ts_by_data_arrive"}, 277 {0x18, "both_threads_empty"}, 278 SPARC64_VI_EVENTS_comm_2, 279 {0x1b, "op_stv_wait_nc_pend"}, 280 {0x1d, "op_stv_wait_sxmiss_ex"}, 281 {0x1e, "branch_comp_wait"}, 282 {0x20, "write_if_uTLB"}, 283 {0x30, "sx_miss_count_dm"}, 284 {0x31, "jbus_cpb_count"}, 285 {0x32, "snres_256"}, 286 {0x34, "lost_softpf_by_abort"}, 287 {0x36, "jbus_reqbus2_busy"}, 288 {NT_END, ""} 289 }; 290 291 static const struct nametable SPARC64_VI_names_l2[] = { 292 SPARC64_VI_EVENTS_comm_0, 293 {0x2, "d_move_wait"}, 294 {0x3, "w_op_stv_wait"}, 295 {0x4, "w_fl_comp_wait"}, 296 SPARC64_VI_EVENTS_comm_1, 297 {0x13, "sync_intlk"}, 298 {0x16, "trap_trap_inst"}, 299 {0x18, "ts_by_if"}, 300 SPARC64_VI_EVENTS_comm_2, 301 {0x1e, "fl_comp_wait"}, 302 {0x20, "op_r_iu_req_mi_go"}, 303 {0x30, "sx_read_count_pf"}, 304 {0x31, "jbus_odrbus_busy"}, 305 {0x33, "sx_miss_count_dm_if"}, 306 {0x36, "jbus_odrbus1_busy"}, 307 {NT_END, ""} 308 }; 309 310 static const struct nametable SPARC64_VI_names_u2[] = { 311 SPARC64_VI_EVENTS_comm_0, 312 {0x2, "instruction_flow_counts"}, 313 {0x3, "iwr_empty"}, 314 SPARC64_VI_EVENTS_comm_1, 315 {0x16, "trap_fill"}, 316 {0x18, "ts_by_intr"}, 317 SPARC64_VI_EVENTS_comm_2, 318 {0x1b, "flush_rs"}, 319 {0x1d, "cse_window_empty_sp_full"}, 320 {0x1e, "op_stv_wait_ex"}, 321 {0x1f, "3endop"}, 322 {0x20, "if_r_iu_req_mi_go"}, 323 {0x24, "swpf_lbs_hit"}, 324 {0x30, "sx_read_count_dm"}, 325 {0x31, "jbus_reqbus_busy"}, 326 {0x33, "sx_btc_count"}, 327 {0x36, "jbus_odrbus0_busy"}, 328 {NT_END, ""} 329 }; 330 331 static const struct nametable SPARC64_VI_names_l3[] = { 332 SPARC64_VI_EVENTS_comm_0, 333 {0x2, "xma_inst"}, 334 {0x3, "w_0endop"}, 335 {0x4, "w_op_stv_wait_ex"}, 336 SPARC64_VI_EVENTS_comm_1, 337 {0x16, "trap_DMMU_miss"}, 338 {0x18, "ts_by_suspend"}, 339 {0x19, "ts_by_other"}, 340 SPARC64_VI_EVENTS_comm_2, 341 {0x1b, "decall_intlk"}, 342 {0x1e, "2endop"}, 343 {0x1f, "op_stv_wait_sxmiss"}, 344 {0x20, "op_wait_all"}, 345 {0x30, "dvp_count_pf"}, 346 {0x33, "sx_miss_count_dm_opex"}, 347 {0x36, "jbus_odrbus3_busy"}, 348 {NT_END, ""} 349 }; 350 351 static const struct nametable SPARC64_VI_names_u3[] = { 352 SPARC64_VI_EVENTS_comm_0, 353 {0x2, "cse_priority_wait"}, 354 {0x3, "w_d_move"}, 355 {0x4, "w_cse_window_empty_sp_full"}, 356 SPARC64_VI_EVENTS_comm_1, 357 {0x13, "regwin_intlk"}, 358 {0x15, "rs1"}, 359 {0x16, "trap_IMMU_miss"}, 360 SPARC64_VI_EVENTS_comm_2, 361 {0x1d, "both_threads_suspended"}, 362 {0x1e, "1endop"}, 363 {0x1f, "op_stv_wait_sxmiss_ex"}, 364 {0x20, "if_wait_all"}, 365 {0x30, "dvp_count_dm"}, 366 {0x33, "sx_miss_count_dm_opsh"}, 367 {0x36, "jbus_odrbus2_busy"}, 368 {NT_END, ""} 369 }; 370 371 #undef SPARC64_VI_EVENTS_comm_0 372 #undef SPARC64_VI_EVENTS_comm_1 373 #undef SPARC64_VI_EVENTS_comm_2 374 375 static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = { 376 SPARC64_VI_names_l0, 377 SPARC64_VI_names_u0, 378 SPARC64_VI_names_l1, 379 SPARC64_VI_names_u1, 380 SPARC64_VI_names_l2, 381 SPARC64_VI_names_u2, 382 SPARC64_VI_names_l3, 383 SPARC64_VI_names_u3 384 }; 385 386 opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = { 387 {0, 0x3f, 0, 0}, 388 {1, 0x3f, 0, 0}, 389 {2, 0x3f, 0, 0}, 390 {3, 0x3f, 0, 0}, 391 {4, 0x3f, 0, 0}, 392 {5, 0x3f, 0, 0}, 393 {6, 0x3f, 0, 0}, 394 {7, 0x3f, 0, 0} 395 }; 396 397 static const struct nametable **events; 398 static const char *opl_impl_name; 399 static const char *opl_cpuref; 400 static char *pic_events[CPC_SPARC64_VI_NPIC]; 401 402 static const char *sp_6_ref = "See the \"SPARC64 VI extensions\" and " 403 "\"SPARC64 VII extensions\" for descriptions of these events."; 404 405 static int 406 opl_pcbe_init(void) 407 { 408 const struct nametable *n; 409 int i; 410 size_t size; 411 412 /* 413 * Discover type of CPU 414 * 415 * Point nametable to that CPU's table 416 */ 417 switch (ULTRA_VER_IMPL(ultra_getver())) { 418 case OLYMPUS_C_IMPL: 419 case JUPITER_IMPL: 420 events = SPARC64_VI_names; 421 opl_impl_name = "SPARC64 VI & VII"; 422 opl_cpuref = sp_6_ref; 423 break; 424 default: 425 return (-1); 426 } 427 428 /* 429 * Initialize the list of events for each PIC. 430 * Do two passes: one to compute the size necessary and another 431 * to copy the strings. Need room for event, comma, and NULL terminator. 432 */ 433 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 434 size = 0; 435 for (n = events[i]; n->bits != NT_END; n++) 436 size += strlen(n->name) + 1; 437 pic_events[i] = kmem_alloc(size + 1, KM_SLEEP); 438 *pic_events[i] = '\0'; 439 for (n = events[i]; n->bits != NT_END; n++) { 440 (void) strcat(pic_events[i], n->name); 441 (void) strcat(pic_events[i], ","); 442 } 443 /* 444 * Remove trailing comma. 445 */ 446 pic_events[i][size - 1] = '\0'; 447 } 448 449 return (0); 450 } 451 452 static uint_t 453 opl_pcbe_ncounters(void) 454 { 455 return (CPC_SPARC64_VI_NPIC); 456 } 457 458 static const char * 459 opl_pcbe_impl_name(void) 460 { 461 return (opl_impl_name); 462 } 463 464 static const char * 465 opl_pcbe_cpuref(void) 466 { 467 return (opl_cpuref); 468 } 469 470 static char * 471 opl_pcbe_list_events(uint_t picnum) 472 { 473 ASSERT(picnum >= 0 && picnum < cpc_ncounters); 474 475 return (pic_events[picnum]); 476 } 477 478 static char * 479 opl_pcbe_list_attrs(void) 480 { 481 return (""); 482 } 483 484 static const struct nametable * 485 find_event(int regno, char *name) 486 { 487 const struct nametable *n; 488 489 n = events[regno]; 490 491 for (; n->bits != NT_END; n++) 492 if (strcmp(name, n->name) == 0) 493 return (n); 494 495 return (NULL); 496 } 497 498 static uint64_t 499 opl_pcbe_event_coverage(char *event) 500 { 501 uint64_t bitmap = 0; 502 503 int i; 504 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 505 if (find_event(i, event) != NULL) 506 bitmap |= (1 << i); 507 } 508 509 return (bitmap); 510 } 511 512 /* 513 * Check if counter overflow and clear it. 514 */ 515 static uint64_t 516 opl_pcbe_overflow_bitmap(void) 517 { 518 uint64_t pcr; 519 520 pcr = ultra_getpcr(); 521 DTRACE_PROBE1(sparc64__getpcr, uint64_t, pcr); 522 523 return ((pcr & SPARC64_VI_PCR_OVF) >> CPC_SPARC64_VI_PCR_OVF_SHIFT); 524 } 525 526 /*ARGSUSED*/ 527 static int 528 opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 529 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 530 { 531 opl_pcbe_config_t *conf; 532 const struct nametable *n; 533 opl_pcbe_config_t *other_config; 534 535 /* 536 * If we've been handed an existing configuration, we need only preset 537 * the counter value. 538 */ 539 if (*data != NULL) { 540 conf = *data; 541 conf->opl_pic = (uint32_t)preset; 542 return (0); 543 } 544 545 if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC) 546 return (CPC_INVALID_PICNUM); 547 548 if (nattrs != 0) 549 return (CPC_INVALID_ATTRIBUTE); 550 551 /* 552 * Find other requests that will be programmed with this one, and ensure 553 * the flags don't conflict. 554 */ 555 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 556 (other_config->opl_flags != flags)) 557 return (CPC_CONFLICTING_REQS); 558 559 if ((n = find_event(picnum, event)) == NULL) 560 return (CPC_INVALID_EVENT); 561 562 conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP); 563 564 conf->opl_picno = picnum; 565 conf->opl_bits = (uint32_t)n->bits; 566 conf->opl_flags = flags; 567 conf->opl_pic = (uint32_t)preset; 568 569 *data = conf; 570 return (0); 571 } 572 573 static void 574 opl_pcbe_program(void *token) 575 { 576 opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; 577 opl_pcbe_config_t *firstconfig; 578 opl_pcbe_config_t *tmp; 579 uint64_t pcr; 580 uint64_t curpic; 581 uint8_t bitmap = 0; /* for used pic config */ 582 int i; 583 opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; 584 585 /* Get next pic config */ 586 firstconfig = tmp = kcpc_next_config(token, NULL, NULL); 587 588 while (tmp != NULL) { 589 ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC); 590 ASSERT(firstconfig->opl_flags == tmp->opl_flags); 591 pic[tmp->opl_picno] = tmp; 592 bitmap |= (uint8_t)(1 << tmp->opl_picno); 593 tmp = kcpc_next_config(token, tmp, NULL); 594 } 595 if (bitmap == 0) 596 panic("opl_pcbe: token %p has no configs", token); 597 598 /* Fill in unused pic config */ 599 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 600 if (bitmap & (1 << i)) 601 continue; 602 603 dummypic[i] = nullpic[i]; 604 dummypic[i].opl_flags = firstconfig->opl_flags; 605 pic[i] = &dummypic[i]; 606 } 607 608 /* 609 * For each counter pair, initialize event settings and 610 * counter values. 611 */ 612 ultra_setpcr(allstopped); 613 pcr = allstopped; 614 pcr &= ~SPARC64_VI_PCR_ULRO; 615 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 616 SPARC64_VI_PCR_SEL_PIC(pcr, i); 617 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 618 pic[i*2 + 1]->opl_bits); 619 620 ultra_setpcr(pcr); 621 curpic = (uint64_t)(pic[i*2]->opl_pic | 622 ((uint64_t)pic[i*2 + 1]->opl_pic << 32)); 623 ultra_setpic(curpic); 624 } 625 626 /* 627 * For each counter pair, enable the trace flags to start 628 * counting. Re-read the counters to sample the counter value now 629 * and use that as the baseline for future samples. 630 */ 631 632 /* Get PCR */ 633 pcr = ultra_getpcr(); 634 pcr |= SPARC64_VI_PCR_ULRO; 635 pcr &= ~(SPARC64_VI_PCR_OVRO | SPARC64_VI_PCR_OVF); 636 637 if (pic[0]->opl_flags & CPC_COUNT_USER) 638 pcr |= SPARC64_VI_PCR_USR; 639 if (pic[0]->opl_flags & CPC_COUNT_SYSTEM) 640 pcr |= SPARC64_VI_PCR_SYS; 641 642 /* Set counter values */ 643 644 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 645 SPARC64_VI_PCR_SEL_PIC(pcr, i); 646 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 647 pic[i*2 + 1]->opl_bits); 648 649 ultra_setpcr(pcr); 650 DTRACE_PROBE1(sparc64__setpcr, uint64_t, pcr); 651 652 curpic = ultra_getpic(); 653 DTRACE_PROBE1(sparc64__newpic, uint64_t, curpic); 654 pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); 655 pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); 656 } 657 pcr |= SPARC64_VI_PCR_OVRO; 658 ultra_setpcr(pcr); 659 } 660 661 static void 662 opl_pcbe_allstop(void) 663 { 664 ultra_setpcr(allstopped); 665 } 666 667 668 static void 669 opl_pcbe_sample(void *token) 670 { 671 uint64_t curpic; 672 uint64_t pcr; 673 uint64_t overflow; 674 int64_t diff; 675 uint64_t *pic_data[CPC_SPARC64_VI_NPIC]; 676 uint64_t *dtmp; 677 opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; 678 opl_pcbe_config_t *ctmp; 679 opl_pcbe_config_t *firstconfig; 680 uint8_t bitmap = 0; /* for used pic config */ 681 int i; 682 opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; 683 uint64_t dummypic_data[CPC_SPARC64_VI_NPIC]; 684 685 /* Get next pic config */ 686 firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp); 687 688 while (ctmp != NULL) { 689 ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC); 690 ASSERT(firstconfig->opl_flags == ctmp->opl_flags); 691 pic[ctmp->opl_picno] = ctmp; 692 pic_data[ctmp->opl_picno] = dtmp; 693 bitmap |= (uint8_t)(1 << ctmp->opl_picno); 694 ctmp = kcpc_next_config(token, ctmp, &dtmp); 695 } 696 if (bitmap == 0) 697 panic("opl_pcbe: token %p has no configs", token); 698 699 /* Fill in unuse pic config */ 700 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 701 if (bitmap & (1 << i)) 702 continue; 703 704 dummypic[i] = nullpic[i]; 705 dummypic[i].opl_flags = firstconfig->opl_flags; 706 pic[i] = &dummypic[i]; 707 708 dummypic_data[i] = 0; 709 pic_data[i] = &dummypic_data[i]; 710 } 711 712 pcr = ultra_getpcr(); 713 pcr &= ~SPARC64_VI_PCR_OVRO; 714 pcr |= SPARC64_VI_PCR_ULRO; 715 716 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 717 SPARC64_VI_PCR_SEL_PIC(pcr, i); 718 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 719 pic[i*2 + 1]->opl_bits); 720 721 ultra_setpcr(pcr); 722 723 curpic = ultra_getpic(); 724 DTRACE_PROBE1(sparc64__getpic, unit64_t, curpic); 725 726 diff = (curpic & PIC_MASK) - (uint64_t)pic[i*2]->opl_pic; 727 overflow = SPARC64_VI_CHK_OVF(pcr, i*2); 728 if (overflow || (diff < 0)) { 729 SPARC64_VI_CLR_OVF(pcr, i*2); 730 ultra_setpcr(pcr); 731 diff += (1ll << 32); 732 } 733 *pic_data[i*2] += diff; 734 735 diff = (curpic >> 32) - (uint64_t)pic[i*2 + 1]->opl_pic; 736 overflow = SPARC64_VI_CHK_OVF(pcr, i*2 + 1); 737 if (overflow || (diff < 0)) { 738 SPARC64_VI_CLR_OVF(pcr, i*2 + 1); 739 ultra_setpcr(pcr); 740 diff += (1ll << 32); 741 } 742 *pic_data[i*2 + 1] += diff; 743 744 pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); 745 pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); 746 } 747 pcr = ultra_getpcr(); 748 pcr |= SPARC64_VI_PCR_OVRO; 749 ultra_setpcr(pcr); 750 } 751 752 static void 753 opl_pcbe_free(void *config) 754 { 755 kmem_free(config, sizeof (opl_pcbe_config_t)); 756 } 757 758 759 static struct modlpcbe modlpcbe = { 760 &mod_pcbeops, 761 "SPARC64 VI&VII Perf Cntrs v%I%", 762 &opl_pcbe_ops 763 }; 764 765 static struct modlinkage modl = { 766 MODREV_1, 767 &modlpcbe, 768 }; 769 770 int 771 _init(void) 772 { 773 if (opl_pcbe_init() != 0) 774 return (ENOTSUP); 775 return (mod_install(&modl)); 776 } 777 778 int 779 _fini(void) 780 { 781 return (mod_remove(&modl)); 782 } 783 784 int 785 _info(struct modinfo *mi) 786 { 787 return (mod_info(&modl, mi)); 788 } 789