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 * UltraSPARC 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/spitregs.h> 36 #include <sys/cheetahregs.h> 37 #include <sys/cpc_impl.h> 38 #include <sys/cpc_pcbe.h> 39 #include <sys/modctl.h> 40 #include <sys/machsystm.h> 41 #include <sys/sdt.h> 42 43 static int us_pcbe_init(void); 44 static uint_t us_pcbe_ncounters(void); 45 static const char *us_pcbe_impl_name(void); 46 static const char *us_pcbe_cpuref(void); 47 static char *us_pcbe_list_events(uint_t picnum); 48 static char *us_pcbe_list_attrs(void); 49 static uint64_t us_pcbe_event_coverage(char *event); 50 static uint64_t us_pcbe_overflow_bitmap(void); 51 static int us_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 52 uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 53 void *token); 54 static void us_pcbe_program(void *token); 55 static void us_pcbe_allstop(void); 56 static void us_pcbe_sample(void *token); 57 static void us_pcbe_free(void *config); 58 59 extern void ultra_setpcr(uint64_t); 60 extern uint64_t ultra_getpcr(void); 61 extern void ultra_setpic(uint64_t); 62 extern uint64_t ultra_getpic(void); 63 extern uint64_t ultra_gettick(void); 64 65 pcbe_ops_t us_pcbe_ops = { 66 PCBE_VER_1, 67 CPC_CAP_OVERFLOW_INTERRUPT, 68 us_pcbe_ncounters, 69 us_pcbe_impl_name, 70 us_pcbe_cpuref, 71 us_pcbe_list_events, 72 us_pcbe_list_attrs, 73 us_pcbe_event_coverage, 74 us_pcbe_overflow_bitmap, 75 us_pcbe_configure, 76 us_pcbe_program, 77 us_pcbe_allstop, 78 us_pcbe_sample, 79 us_pcbe_free 80 }; 81 82 typedef struct _us_pcbe_config { 83 uint8_t us_picno; /* 0 for pic0 or 1 for pic1 */ 84 uint32_t us_bits; /* %pcr event code unshifted */ 85 uint32_t us_flags; /* user/system/priv */ 86 uint32_t us_pic; /* unshifted raw %pic value */ 87 } us_pcbe_config_t; 88 89 struct nametable { 90 const uint8_t bits; 91 const char *name; 92 }; 93 94 #define PIC0_MASK (((uint64_t)1 << 32) - 1) 95 96 #define ULTRA_PCR_SYS (UINT64_C(1) << CPC_ULTRA_PCR_SYS) 97 #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_ULTRA_PCR_PRIVPIC) 98 99 #define CPC_ULTRA_PCR_USR 2 100 #define CPC_ULTRA_PCR_SYS 1 101 #define CPC_ULTRA_PCR_PRIVPIC 0 102 103 #define CPC_ULTRA_PCR_PIC0_SHIFT 4 104 #define CPC_ULTRA2_PCR_PIC_MASK UINT64_C(0xf) 105 #define CPC_ULTRA3_PCR_PIC_MASK UINT64_C(0x3f) 106 #define CPC_ULTRA_PCR_PIC1_SHIFT 11 107 108 #define NT_END 0xFF 109 110 static const uint64_t allstopped = ULTRA_PCR_PRIVPIC; 111 112 #define USall_EVENTS_0 \ 113 {0x0, "Cycle_cnt"}, \ 114 {0x1, "Instr_cnt"}, \ 115 {0x2, "Dispatch0_IC_miss"}, \ 116 {0x8, "IC_ref"}, \ 117 {0x9, "DC_rd"}, \ 118 {0xa, "DC_wr"}, \ 119 {0xc, "EC_ref"}, \ 120 {0xe, "EC_snoop_inv"} 121 122 static const struct nametable US12_names0[] = { 123 USall_EVENTS_0, 124 {0x3, "Dispatch0_storeBuf"}, 125 {0xb, "Load_use"}, 126 {0xd, "EC_write_hit_RDO"}, 127 {0xf, "EC_rd_hit"}, 128 {NT_END, ""} 129 }; 130 131 #define US3all_EVENTS_0 \ 132 {0x3, "Dispatch0_br_target"}, \ 133 {0x4, "Dispatch0_2nd_br"}, \ 134 {0x5, "Rstall_storeQ"}, \ 135 {0x6, "Rstall_IU_use"}, \ 136 {0xd, "EC_write_hit_RTO"}, \ 137 {0xf, "EC_rd_miss"}, \ 138 {0x10, "PC_port0_rd"}, \ 139 {0x11, "SI_snoop"}, \ 140 {0x12, "SI_ciq_flow"}, \ 141 {0x13, "SI_owned"}, \ 142 {0x14, "SW_count_0"}, \ 143 {0x15, "IU_Stat_Br_miss_taken"}, \ 144 {0x16, "IU_Stat_Br_count_taken"}, \ 145 {0x17, "Dispatch_rs_mispred"}, \ 146 {0x18, "FA_pipe_completion"} 147 148 #define US3_MC_EVENTS_0 \ 149 {0x20, "MC_reads_0"}, \ 150 {0x21, "MC_reads_1"}, \ 151 {0x22, "MC_reads_2"}, \ 152 {0x23, "MC_reads_3"}, \ 153 {0x24, "MC_stalls_0"}, \ 154 {0x25, "MC_stalls_2"} 155 156 #define US3_I_MC_EVENTS_0 \ 157 {0x20, "MC_read_dispatched"}, \ 158 {0x21, "MC_write_dispatched"}, \ 159 {0x22, "MC_read_returned_to_JBU"}, \ 160 {0x23, "MC_msl_busy_stall"}, \ 161 {0x24, "MC_mdb_overflow_stall"}, \ 162 {0x25, "MC_miu_spec_request"} 163 164 #define USall_EVENTS_1 \ 165 {0x0, "Cycle_cnt"}, \ 166 {0x1, "Instr_cnt"}, \ 167 {0x2, "Dispatch0_mispred"}, \ 168 {0xd, "EC_wb"}, \ 169 {0xe, "EC_snoop_cb"} 170 171 static const struct nametable US3_names0[] = { 172 USall_EVENTS_0, 173 US3all_EVENTS_0, 174 US3_MC_EVENTS_0, 175 {NT_END, ""} 176 }; 177 178 static const struct nametable US3_PLUS_names0[] = { 179 USall_EVENTS_0, 180 US3all_EVENTS_0, 181 US3_MC_EVENTS_0, 182 {0x19, "EC_wb_remote"}, 183 {0x1a, "EC_miss_local"}, 184 {0x1b, "EC_miss_mtag_remote"}, 185 {NT_END, ""} 186 }; 187 188 static const struct nametable US3_I_names0[] = { 189 USall_EVENTS_0, 190 US3all_EVENTS_0, 191 US3_I_MC_EVENTS_0, 192 {NT_END, ""} 193 }; 194 195 static const struct nametable US4_PLUS_names0[] = { 196 {0x0, "Cycle_cnt"}, 197 {0x1, "Instr_cnt"}, 198 {0x2, "Dispatch0_IC_miss"}, 199 {0x3, "IU_stat_jmp_correct_pred"}, 200 {0x4, "Dispatch0_2nd_br"}, 201 {0x5, "Rstall_storeQ"}, 202 {0x6, "Rstall_IU_use"}, 203 {0x7, "IU_stat_ret_correct_pred"}, 204 {0x8, "IC_ref"}, 205 {0x9, "DC_rd"}, 206 {0xa, "Rstall_FP_use"}, 207 {0xb, "SW_pf_instr"}, 208 {0xc, "L2_ref"}, 209 {0xd, "L2_write_hit_RTO"}, 210 {0xe, "L2_snoop_inv_sh"}, 211 {0xf, "L2_rd_miss"}, 212 {0x10, "PC_rd"}, 213 {0x11, "SI_snoop_sh"}, 214 {0x12, "SI_ciq_flow_sh"}, 215 {0x13, "Re_DC_miss"}, 216 {0x14, "SW_count_NOP"}, 217 {0x15, "IU_stat_br_miss_taken"}, 218 {0x16, "IU_stat_br_count_untaken"}, 219 {0x17, "HW_pf_exec"}, 220 {0x18, "FA_pipe_completion"}, 221 {0x19, "SSM_L3_wb_remote"}, 222 {0x1a, "SSM_L3_miss_local"}, 223 {0x1b, "SSM_L3_miss_mtag_remote"}, 224 {0x1c, "SW_pf_str_trapped"}, 225 {0x1d, "SW_pf_PC_installed"}, 226 {0x1e, "IPB_to_IC_fill"}, 227 {0x1f, "L2_write_miss"}, 228 {0x20, "MC_reads_0_sh"}, 229 {0x21, "MC_reads_1_sh"}, 230 {0x22, "MC_reads_2_sh"}, 231 {0x23, "MC_reads_3_sh"}, 232 {0x24, "MC_stalls_0_sh"}, 233 {0x25, "MC_stalls_2_sh"}, 234 {0x26, "L2_hit_other_half"}, 235 {0x28, "L3_rd_miss"}, 236 {0x29, "Re_L2_miss"}, 237 {0x2a, "IC_miss_cancelled"}, 238 {0x2b, "DC_wr_miss"}, 239 {0x2c, "L3_hit_I_state_sh"}, 240 {0x2d, "SI_RTS_src_data"}, 241 {0x2e, "L2_IC_miss"}, 242 {0x2f, "SSM_new_transaction_sh"}, 243 {0x30, "L2_SW_pf_miss"}, 244 {0x31, "L2_wb"}, 245 {0x32, "L2_wb_sh"}, 246 {0x33, "L2_snoop_cb_sh"}, 247 {NT_END, ""} 248 }; 249 250 251 #define US3all_EVENTS_1 \ 252 {0x3, "IC_miss_cancelled"}, \ 253 {0x5, "Re_FPU_bypass"}, \ 254 {0x6, "Re_DC_miss"}, \ 255 {0x7, "Re_EC_miss"}, \ 256 {0x8, "IC_miss"}, \ 257 {0x9, "DC_rd_miss"}, \ 258 {0xa, "DC_wr_miss"}, \ 259 {0xb, "Rstall_FP_use"}, \ 260 {0xc, "EC_misses"}, \ 261 {0xf, "EC_ic_miss"}, \ 262 {0x10, "Re_PC_miss"}, \ 263 {0x11, "ITLB_miss"}, \ 264 {0x12, "DTLB_miss"}, \ 265 {0x13, "WC_miss"}, \ 266 {0x14, "WC_snoop_cb"}, \ 267 {0x15, "WC_scrubbed"}, \ 268 {0x16, "WC_wb_wo_read"}, \ 269 {0x18, "PC_soft_hit"}, \ 270 {0x19, "PC_snoop_inv"}, \ 271 {0x1a, "PC_hard_hit"}, \ 272 {0x1b, "PC_port1_rd"}, \ 273 {0x1c, "SW_count_1"}, \ 274 {0x1d, "IU_Stat_Br_miss_untaken"}, \ 275 {0x1e, "IU_Stat_Br_count_untaken"}, \ 276 {0x1f, "PC_MS_misses"}, \ 277 {0x26, "Re_RAW_miss"}, \ 278 {0x27, "FM_pipe_completion"} 279 280 #define US3_MC_EVENTS_1 \ 281 {0x20, "MC_writes_0"}, \ 282 {0x21, "MC_writes_1"}, \ 283 {0x22, "MC_writes_2"}, \ 284 {0x23, "MC_writes_3"}, \ 285 {0x24, "MC_stalls_1"}, \ 286 {0x25, "MC_stalls_3"} 287 288 #define US3_I_MC_EVENTS_1 \ 289 {0x20, "MC_open_bank_cmds"}, \ 290 {0x21, "MC_reads"}, \ 291 {0x22, "MC_writes"}, \ 292 {0x23, "MC_page_close_stall"} 293 294 static const struct nametable US3_names1[] = { 295 USall_EVENTS_1, 296 US3all_EVENTS_1, 297 US3_MC_EVENTS_1, 298 {0x4, "Re_endian_miss"}, 299 {NT_END, ""} 300 }; 301 302 static const struct nametable US3_PLUS_names1[] = { 303 USall_EVENTS_1, 304 US3all_EVENTS_1, 305 US3_MC_EVENTS_1, 306 {0x4, "Re_DC_missovhd"}, 307 {0x28, "EC_miss_mtag_remote"}, 308 {0x29, "EC_miss_remote"}, 309 {NT_END, ""} 310 }; 311 312 static const struct nametable US3_I_names1[] = { 313 USall_EVENTS_1, 314 US3all_EVENTS_1, 315 US3_I_MC_EVENTS_1, 316 {0x4, "Re_DC_missovhd"}, 317 {NT_END, ""} 318 }; 319 320 static const struct nametable US4_PLUS_names1[] = { 321 {0x0, "Cycle_cnt"}, 322 {0x1, "Instr_cnt"}, 323 {0x2, "Dispatch0_other"}, 324 {0x3, "DC_wr"}, 325 {0x4, "Re_DC_missovhd"}, 326 {0x5, "Re_FPU_bypass"}, 327 {0x6, "L3_write_hit_RTO"}, 328 {0x7, "L2L3_snoop_inv_sh"}, 329 {0x8, "IC_L2_req"}, 330 {0x9, "DC_rd_miss"}, 331 {0xa, "L2_hit_I_state_sh"}, 332 {0xb, "L3_write_miss_RTO"}, 333 {0xc, "L2_miss"}, 334 {0xd, "SI_owned_sh"}, 335 {0xe, "SI_RTO_src_data"}, 336 {0xf, "SW_pf_duplicate"}, 337 {0x10, "IU_stat_jmp_mispred"}, 338 {0x11, "ITLB_miss"}, 339 {0x12, "DTLB_miss"}, 340 {0x13, "WC_miss"}, 341 {0x14, "IC_fill"}, 342 {0x15, "IU_stat_ret_mispred"}, 343 {0x16, "Re_L3_miss"}, 344 {0x17, "Re_PFQ_full"}, 345 {0x18, "PC_soft_hit"}, 346 {0x19, "PC_inv"}, 347 {0x1a, "PC_hard_hit"}, 348 {0x1b, "IC_pf"}, 349 {0x1c, "SW_count_NOP"}, 350 {0x1d, "IU_stat_br_miss_untaken"}, 351 {0x1e, "IU_stat_br_count_taken"}, 352 {0x1f, "PC_miss"}, 353 {0x20, "MC_writes_0_sh"}, 354 {0x21, "MC_writes_1_sh"}, 355 {0x22, "MC_writes_2_sh"}, 356 {0x23, "MC_writes_3_sh"}, 357 {0x24, "MC_stalls_1_sh"}, 358 {0x25, "MC_stalls_3_sh"}, 359 {0x26, "Re_RAW_miss"}, 360 {0x27, "FM_pipe_completion"}, 361 {0x28, "SSM_L3_miss_mtag_remote"}, 362 {0x29, "SSM_L3_miss_remote"}, 363 {0x2a, "SW_pf_exec"}, 364 {0x2b, "SW_pf_str_exec"}, 365 {0x2c, "SW_pf_dropped"}, 366 {0x2d, "SW_pf_L2_installed"}, 367 {0x2f, "L2_HW_pf_miss"}, 368 {0x31, "L3_miss"}, 369 {0x32, "L3_IC_miss"}, 370 {0x33, "L3_SW_pf_miss"}, 371 {0x34, "L3_hit_other_half"}, 372 {0x35, "L3_wb"}, 373 {0x36, "L3_wb_sh"}, 374 {0x37, "L2L3_snoop_cb_sh"}, 375 {NT_END, ""} 376 }; 377 378 static const struct nametable US12_names1[] = { 379 USall_EVENTS_1, 380 {0x3, "Dispatch0_FP_use"}, 381 {0x8, "IC_hit"}, 382 {0x9, "DC_rd_hit"}, 383 {0xa, "DC_wr_hit"}, 384 {0xb, "Load_use_RAW"}, 385 {0xc, "EC_hit"}, 386 {0xf, "EC_ic_hit"}, 387 {NT_END, ""} 388 }; 389 390 static const struct nametable *US12_names[2] = { 391 US12_names0, 392 US12_names1 393 }; 394 395 static const struct nametable *US3_names[2] = { 396 US3_names0, 397 US3_names1 398 }; 399 400 static const struct nametable *US3_PLUS_names[2] = { 401 US3_PLUS_names0, 402 US3_PLUS_names1 403 }; 404 405 static const struct nametable *US4_PLUS_names[2] = { 406 US4_PLUS_names0, 407 US4_PLUS_names1 408 }; 409 410 static const struct nametable *US3_I_names[2] = { 411 US3_I_names0, 412 US3_I_names1 413 }; 414 415 static const struct nametable **events; 416 static const char *us_impl_name; 417 static const char *us_cpuref; 418 static char *pic_events[2]; 419 static uint16_t pcr_pic_mask; 420 421 #define CPU_REF_URL " Documentation for Sun processors can be found at: " \ 422 "http://www.sun.com/processors/manuals" 423 424 static const char *us_2_ref = "See the \"UltraSPARC I/II User\'s Manual\" " 425 "(Part No. 802-7220-02) " 426 "for descriptions of these events." CPU_REF_URL; 427 428 static const char *us_3cu_ref = "See the \"UltraSPARC III Cu User's Manual\" " 429 "for descriptions of these events." CPU_REF_URL; 430 431 static const char *us4_plus_ref = "See the \"UltraSPARC IV+ User's Manual\" " 432 "for descriptions of these events." CPU_REF_URL; 433 434 static const char *us_3i_ref = "See the \"UltraSPARC IIIi User's Manual\" " 435 "for descriptions of these events." CPU_REF_URL; 436 437 static int 438 us_pcbe_init(void) 439 { 440 const struct nametable *n; 441 int i; 442 size_t size; 443 444 /* 445 * Discover type of CPU 446 * 447 * Point nametable to that CPU's table 448 */ 449 switch (ULTRA_VER_IMPL(ultra_getver())) { 450 case SPITFIRE_IMPL: 451 case BLACKBIRD_IMPL: 452 case SABRE_IMPL: 453 case HUMMBRD_IMPL: 454 events = US12_names; 455 us_impl_name = "UltraSPARC I&II"; 456 us_cpuref = us_2_ref; 457 pcr_pic_mask = CPC_ULTRA2_PCR_PIC_MASK; 458 us_pcbe_ops.pcbe_caps &= ~CPC_CAP_OVERFLOW_INTERRUPT; 459 break; 460 case CHEETAH_IMPL: 461 events = US3_names; 462 us_impl_name = "UltraSPARC III"; 463 us_cpuref = us_3cu_ref; 464 pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK; 465 break; 466 case CHEETAH_PLUS_IMPL: 467 case JAGUAR_IMPL: 468 events = US3_PLUS_names; 469 us_impl_name = "UltraSPARC III+ & IV"; 470 us_cpuref = us_3cu_ref; 471 pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK; 472 break; 473 case PANTHER_IMPL: 474 events = US4_PLUS_names; 475 us_impl_name = "UltraSPARC IV+"; 476 us_cpuref = us4_plus_ref; 477 pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK; 478 break; 479 case JALAPENO_IMPL: 480 case SERRANO_IMPL: 481 events = US3_I_names; 482 us_impl_name = "UltraSPARC IIIi & IIIi+"; 483 us_cpuref = us_3i_ref; 484 pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK; 485 break; 486 default: 487 return (-1); 488 } 489 490 /* 491 * Initialize the list of events for each PIC. 492 * Do two passes: one to compute the size necessary and another 493 * to copy the strings. Need room for event, comma, and NULL terminator. 494 */ 495 for (i = 0; i < 2; i++) { 496 size = 0; 497 for (n = events[i]; n->bits != NT_END; n++) 498 size += strlen(n->name) + 1; 499 pic_events[i] = kmem_alloc(size + 1, KM_SLEEP); 500 *pic_events[i] = '\0'; 501 for (n = events[i]; n->bits != NT_END; n++) { 502 (void) strcat(pic_events[i], n->name); 503 (void) strcat(pic_events[i], ","); 504 } 505 /* 506 * Remove trailing comma. 507 */ 508 pic_events[i][size - 1] = '\0'; 509 } 510 511 return (0); 512 } 513 514 static uint_t 515 us_pcbe_ncounters(void) 516 { 517 return (2); 518 } 519 520 static const char * 521 us_pcbe_impl_name(void) 522 { 523 return (us_impl_name); 524 } 525 526 static const char * 527 us_pcbe_cpuref(void) 528 { 529 return (us_cpuref); 530 } 531 532 static char * 533 us_pcbe_list_events(uint_t picnum) 534 { 535 ASSERT(picnum >= 0 && picnum < cpc_ncounters); 536 537 return (pic_events[picnum]); 538 } 539 540 static char * 541 us_pcbe_list_attrs(void) 542 { 543 return (""); 544 } 545 546 static const struct nametable * 547 find_event(int regno, char *name) 548 { 549 const struct nametable *n; 550 551 n = events[regno]; 552 553 for (; n->bits != NT_END; n++) 554 if (strcmp(name, n->name) == 0) 555 return (n); 556 557 return (NULL); 558 } 559 560 static uint64_t 561 us_pcbe_event_coverage(char *event) 562 { 563 uint64_t bitmap = 0; 564 565 if (find_event(0, event) != NULL) 566 bitmap = 0x1; 567 if (find_event(1, event) != NULL) 568 bitmap |= 0x2; 569 570 return (bitmap); 571 } 572 573 /* 574 * These processors cannot tell which counter overflowed. The PCBE interface 575 * requires such processors to act as if _all_ counters had overflowed. 576 */ 577 static uint64_t 578 us_pcbe_overflow_bitmap(void) 579 { 580 return (0x3); 581 } 582 583 /*ARGSUSED*/ 584 static int 585 us_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 586 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 587 { 588 us_pcbe_config_t *conf; 589 const struct nametable *n; 590 us_pcbe_config_t *other_config; 591 592 /* 593 * If we've been handed an existing configuration, we need only preset 594 * the counter value. 595 */ 596 if (*data != NULL) { 597 conf = *data; 598 conf->us_pic = (uint32_t)preset; 599 return (0); 600 } 601 602 if (picnum < 0 || picnum > 1) 603 return (CPC_INVALID_PICNUM); 604 605 if (nattrs != 0) 606 return (CPC_INVALID_ATTRIBUTE); 607 608 /* 609 * Find other requests that will be programmed with this one, and ensure 610 * the flags don't conflict. 611 */ 612 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 613 (other_config->us_flags != flags)) 614 return (CPC_CONFLICTING_REQS); 615 616 if ((n = find_event(picnum, event)) == NULL) 617 return (CPC_INVALID_EVENT); 618 619 conf = kmem_alloc(sizeof (us_pcbe_config_t), KM_SLEEP); 620 621 conf->us_picno = picnum; 622 conf->us_bits = (uint32_t)n->bits; 623 conf->us_flags = flags; 624 conf->us_pic = (uint32_t)preset; 625 626 *data = conf; 627 return (0); 628 } 629 630 static void 631 us_pcbe_program(void *token) 632 { 633 us_pcbe_config_t *pic0; 634 us_pcbe_config_t *pic1; 635 us_pcbe_config_t *tmp; 636 us_pcbe_config_t empty = { 1, 0x1c, 0, 0 }; /* SW_count_1 */ 637 uint64_t pcr; 638 uint64_t curpic; 639 640 if ((pic0 = (us_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == 641 NULL) 642 panic("us_pcbe: token %p has no configs", token); 643 644 if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { 645 pic1 = ∅ 646 empty.us_flags = pic0->us_flags; 647 } 648 649 if (pic0->us_picno != 0) { 650 /* 651 * pic0 is counter 1, so if we need the empty config it should 652 * be counter 0. 653 */ 654 empty.us_picno = 0; 655 empty.us_bits = 0x14; /* SW_count_0 - won't overflow */ 656 tmp = pic0; 657 pic0 = pic1; 658 pic1 = tmp; 659 } 660 661 if (pic0->us_picno != 0 || pic1->us_picno != 1) 662 panic("us_pcbe: bad config on token %p\n", token); 663 664 /* 665 * UltraSPARC does not allow pic0 to be configured differently 666 * from pic1. If the flags on these two configurations are 667 * different, they are incompatible. This condition should be 668 * caught at configure time. 669 */ 670 ASSERT(pic0->us_flags == pic1->us_flags); 671 672 ultra_setpcr(allstopped); 673 ultra_setpic(((uint64_t)pic1->us_pic << 32) | (uint64_t)pic0->us_pic); 674 675 pcr = (pic0->us_bits & pcr_pic_mask) << 676 CPC_ULTRA_PCR_PIC0_SHIFT; 677 pcr |= (pic1->us_bits & pcr_pic_mask) << 678 CPC_ULTRA_PCR_PIC1_SHIFT; 679 680 if (pic0->us_flags & CPC_COUNT_USER) 681 pcr |= (1ull << CPC_ULTRA_PCR_USR); 682 if (pic0->us_flags & CPC_COUNT_SYSTEM) 683 pcr |= (1ull << CPC_ULTRA_PCR_SYS); 684 685 DTRACE_PROBE1(ultra__pcr, uint64_t, pcr); 686 687 ultra_setpcr(pcr); 688 689 /* 690 * On UltraSPARC, only read-to-read counts are accurate. We cannot 691 * expect the value we wrote into the PIC, above, to be there after 692 * starting the counter. We must sample the counter value now and use 693 * that as the baseline for future samples. 694 */ 695 curpic = ultra_getpic(); 696 pic0->us_pic = (uint32_t)(curpic & PIC0_MASK); 697 pic1->us_pic = (uint32_t)(curpic >> 32); 698 } 699 700 static void 701 us_pcbe_allstop(void) 702 { 703 ultra_setpcr(allstopped); 704 } 705 706 707 static void 708 us_pcbe_sample(void *token) 709 { 710 uint64_t curpic; 711 int64_t diff; 712 uint64_t *pic0_data; 713 uint64_t *pic1_data; 714 uint64_t *dtmp; 715 uint64_t tmp; 716 us_pcbe_config_t *pic0; 717 us_pcbe_config_t *pic1; 718 us_pcbe_config_t empty = { 1, 0, 0, 0 }; 719 us_pcbe_config_t *ctmp; 720 721 curpic = ultra_getpic(); 722 723 if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL) 724 panic("us_pcbe: token %p has no configs", token); 725 726 if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) { 727 pic1 = ∅ 728 pic1_data = &tmp; 729 } 730 731 if (pic0->us_picno != 0) { 732 empty.us_picno = 0; 733 ctmp = pic0; 734 pic0 = pic1; 735 pic1 = ctmp; 736 dtmp = pic0_data; 737 pic0_data = pic1_data; 738 pic1_data = dtmp; 739 } 740 741 if (pic0->us_picno != 0 || pic1->us_picno != 1) 742 panic("us_pcbe: bad config on token %p\n", token); 743 744 diff = (curpic & PIC0_MASK) - (uint64_t)pic0->us_pic; 745 if (diff < 0) 746 diff += (1ll << 32); 747 *pic0_data += diff; 748 749 diff = (curpic >> 32) - (uint64_t)pic1->us_pic; 750 if (diff < 0) 751 diff += (1ll << 32); 752 *pic1_data += diff; 753 754 pic0->us_pic = (uint32_t)(curpic & PIC0_MASK); 755 pic1->us_pic = (uint32_t)(curpic >> 32); 756 } 757 758 static void 759 us_pcbe_free(void *config) 760 { 761 kmem_free(config, sizeof (us_pcbe_config_t)); 762 } 763 764 765 static struct modlpcbe modlpcbe = { 766 &mod_pcbeops, 767 "UltraSPARC Performance Counters", 768 &us_pcbe_ops 769 }; 770 771 static struct modlinkage modl = { 772 MODREV_1, 773 &modlpcbe, 774 }; 775 776 int 777 _init(void) 778 { 779 if (us_pcbe_init() != 0) 780 return (ENOTSUP); 781 return (mod_install(&modl)); 782 } 783 784 int 785 _fini(void) 786 { 787 return (mod_remove(&modl)); 788 } 789 790 int 791 _info(struct modinfo *mi) 792 { 793 return (mod_info(&modl, mi)); 794 } 795