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