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 #define PIC_MASK (((uint64_t)1 << 32) - 1) 94 95 #define SPARC64_VI_PCR_PRIVPIC UINT64_C(1) 96 97 #define CPC_SPARC64_VI_PCR_USR_SHIFT 2 98 #define CPC_SPARC64_VI_PCR_SYS_SHIFT 1 99 100 #define CPC_SPARC64_VI_PCR_PICL_SHIFT 4 101 #define CPC_SPARC64_VI_PCR_PICU_SHIFT 11 102 #define CPC_SPARC64_VI_PCR_PIC_MASK UINT64_C(0x3f) 103 104 #define CPC_SPARC64_VI_NPIC 8 105 106 #define CPC_SPARC64_VI_PCR_ULRO_SHIFT 3 107 #define CPC_SPARC64_VI_PCR_SC_SHIFT 18 108 #define CPC_SPARC64_VI_PCR_SC_MASK UINT64_C(0x7) 109 #define CPC_SPARC64_VI_PCR_NC_SHIFT 22 110 #define CPC_SPARC64_VI_PCR_NC_MASK UINT64_C(0x7) 111 #define CPC_SPARC64_VI_PCR_OVRO_SHIFT 26 112 #define CPC_SPARC64_VI_PCR_OVF_SHIFT 32 113 #define CPC_SPARC64_VI_PCR_OVF_MASK UINT64_C(0xffff) 114 115 #define SPARC64_VI_PCR_SYS (UINT64_C(1) << CPC_SPARC64_VI_PCR_SYS_SHIFT) 116 #define SPARC64_VI_PCR_USR (UINT64_C(1) << CPC_SPARC64_VI_PCR_USR_SHIFT) 117 #define SPARC64_VI_PCR_ULRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_ULRO_SHIFT) 118 #define SPARC64_VI_PCR_OVRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_OVRO_SHIFT) 119 #define SPARC64_VI_PCR_OVF (CPC_SPARC64_VI_PCR_OVF_MASK << \ 120 CPC_SPARC64_VI_PCR_OVF_SHIFT) 121 122 #define SPARC64_VI_NUM_PIC_PAIRS 4 123 124 #define SPARC64_VI_PCR_SEL_PIC(pcr, picno) { \ 125 pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK \ 126 << CPC_SPARC64_VI_PCR_SC_SHIFT)); \ 127 \ 128 pcr |= (((picno) & CPC_SPARC64_VI_PCR_SC_MASK) \ 129 << CPC_SPARC64_VI_PCR_SC_SHIFT); \ 130 } 131 132 #define SPARC64_VI_PCR_SEL_EVENT(pcr, sl, su) { \ 133 pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK \ 134 << CPC_SPARC64_VI_PCR_PICL_SHIFT) \ 135 | (CPC_SPARC64_VI_PCR_PIC_MASK \ 136 << CPC_SPARC64_VI_PCR_PICU_SHIFT)); \ 137 \ 138 pcr |= (((sl) & CPC_SPARC64_VI_PCR_PIC_MASK) \ 139 << CPC_SPARC64_VI_PCR_PICL_SHIFT); \ 140 pcr |= (((su) & CPC_SPARC64_VI_PCR_PIC_MASK) \ 141 << CPC_SPARC64_VI_PCR_PICU_SHIFT); \ 142 } 143 144 #define NT_END 0xFF 145 146 static const uint64_t allstopped = SPARC64_VI_PCR_PRIVPIC | 147 SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO; 148 149 #define SPARC64_VI_EVENTS_comm \ 150 {0x0, "cycle_counts"}, \ 151 {0x1, "instruction_counts"}, \ 152 {0x8, "load_store_instructions"}, \ 153 {0x9, "branch_instructions"}, \ 154 {0xa, "floating_instructions"}, \ 155 {0xb, "impdep2_instructions"}, \ 156 {0xc, "prefetch_instructions"} 157 158 static const struct nametable SPARC64_VI_names_l0[] = { 159 SPARC64_VI_EVENTS_comm, 160 {0x16, "trap_int_vector"}, 161 {0x20, "write_op_uTLB"}, 162 {0x30, "sx_miss_wait_pf"}, 163 {0x31, "jbus_cpi_count"}, 164 {NT_END, ""} 165 }; 166 167 static const struct nametable SPARC64_VI_names_u0[] = { 168 SPARC64_VI_EVENTS_comm, 169 {0x16, "trap_all"}, 170 {0x20, "write_if_uTLB"}, 171 {0x30, "sx_miss_wait_dm"}, 172 {0x31, "jbus_bi_count"}, 173 {NT_END, ""} 174 }; 175 176 static const struct nametable SPARC64_VI_names_l1[] = { 177 SPARC64_VI_EVENTS_comm, 178 {0x16, "trap_spill"}, 179 {0x20, "write_op_uTLB"}, 180 {0x30, "sx_miss_count_pf"}, 181 {0x31, "jbus_cpd_count"}, 182 {NT_END, ""} 183 }; 184 185 static const struct nametable SPARC64_VI_names_u1[] = { 186 SPARC64_VI_EVENTS_comm, 187 {0x16, "trap_int_level"}, 188 {0x20, "write_if_uTLB"}, 189 {0x30, "sx_miss_count_dm"}, 190 {0x31, "jbus_cpb_count"}, 191 {NT_END, ""} 192 }; 193 194 static const struct nametable SPARC64_VI_names_l2[] = { 195 SPARC64_VI_EVENTS_comm, 196 {0x16, "trap_trap_inst"}, 197 {0x20, "op_r_iu_req_mi_go"}, 198 {0x30, "sx_read_count_pf"}, 199 {NT_END, ""} 200 }; 201 202 static const struct nametable SPARC64_VI_names_u2[] = { 203 SPARC64_VI_EVENTS_comm, 204 {0x16, "trap_fill"}, 205 {0x20, "if_r_iu_req_mi_go"}, 206 {0x30, "sx_read_count_dm"}, 207 {NT_END, ""} 208 }; 209 210 static const struct nametable SPARC64_VI_names_l3[] = { 211 SPARC64_VI_EVENTS_comm, 212 {0x16, "trap_DMMU_miss"}, 213 {0x20, "op_wait_all"}, 214 {0x30, "dvp_count_pf"}, 215 {NT_END, ""} 216 }; 217 218 static const struct nametable SPARC64_VI_names_u3[] = { 219 SPARC64_VI_EVENTS_comm, 220 {0x16, "trap_IMMU_miss"}, 221 {0x20, "if_wait_all"}, 222 {0x30, "dvp_count_dm"}, 223 {NT_END, ""} 224 }; 225 226 #undef SPARC64_VI_EVENTS_comm 227 228 static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = { 229 SPARC64_VI_names_l0, 230 SPARC64_VI_names_u0, 231 SPARC64_VI_names_l1, 232 SPARC64_VI_names_u1, 233 SPARC64_VI_names_l2, 234 SPARC64_VI_names_u2, 235 SPARC64_VI_names_l3, 236 SPARC64_VI_names_u3 237 }; 238 239 opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = { 240 {0, 0x3f, 0, 0}, 241 {1, 0x3f, 0, 0}, 242 {2, 0x3f, 0, 0}, 243 {3, 0x3f, 0, 0}, 244 {4, 0x3f, 0, 0}, 245 {5, 0x3f, 0, 0}, 246 {6, 0x3f, 0, 0}, 247 {7, 0x3f, 0, 0} 248 }; 249 250 static const struct nametable **events; 251 static const char *opl_impl_name; 252 static const char *opl_cpuref; 253 static char *pic_events[CPC_SPARC64_VI_NPIC]; 254 255 static const char *sp_6_ref = "See the \"SPARC64 VI User's Manual\" " 256 "for descriptions of these events."; 257 258 static int 259 opl_pcbe_init(void) 260 { 261 const struct nametable *n; 262 int i; 263 size_t size; 264 265 /* 266 * Discover type of CPU 267 * 268 * Point nametable to that CPU's table 269 */ 270 switch (ULTRA_VER_IMPL(ultra_getver())) { 271 case OLYMPUS_C_IMPL: 272 events = SPARC64_VI_names; 273 opl_impl_name = "SPARC64 VI"; 274 opl_cpuref = sp_6_ref; 275 break; 276 default: 277 return (-1); 278 } 279 280 /* 281 * Initialize the list of events for each PIC. 282 * Do two passes: one to compute the size necessary and another 283 * to copy the strings. Need room for event, comma, and NULL terminator. 284 */ 285 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 286 size = 0; 287 for (n = events[i]; n->bits != NT_END; n++) 288 size += strlen(n->name) + 1; 289 pic_events[i] = kmem_alloc(size + 1, KM_SLEEP); 290 *pic_events[i] = '\0'; 291 for (n = events[i]; n->bits != NT_END; n++) { 292 (void) strcat(pic_events[i], n->name); 293 (void) strcat(pic_events[i], ","); 294 } 295 /* 296 * Remove trailing comma. 297 */ 298 pic_events[i][size - 1] = '\0'; 299 } 300 301 return (0); 302 } 303 304 static uint_t 305 opl_pcbe_ncounters(void) 306 { 307 return (CPC_SPARC64_VI_NPIC); 308 } 309 310 static const char * 311 opl_pcbe_impl_name(void) 312 { 313 return (opl_impl_name); 314 } 315 316 static const char * 317 opl_pcbe_cpuref(void) 318 { 319 return (opl_cpuref); 320 } 321 322 static char * 323 opl_pcbe_list_events(uint_t picnum) 324 { 325 ASSERT(picnum >= 0 && picnum < cpc_ncounters); 326 327 return (pic_events[picnum]); 328 } 329 330 static char * 331 opl_pcbe_list_attrs(void) 332 { 333 return (""); 334 } 335 336 static const struct nametable * 337 find_event(int regno, char *name) 338 { 339 const struct nametable *n; 340 341 n = events[regno]; 342 343 for (; n->bits != NT_END; n++) 344 if (strcmp(name, n->name) == 0) 345 return (n); 346 347 return (NULL); 348 } 349 350 static uint64_t 351 opl_pcbe_event_coverage(char *event) 352 { 353 uint64_t bitmap = 0; 354 355 int i; 356 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 357 if (find_event(i, event) != NULL) 358 bitmap |= (1 << i); 359 } 360 361 return (bitmap); 362 } 363 364 /* 365 * XXX: Need to check if overflow bits can be cleared here. 366 */ 367 static uint64_t 368 opl_pcbe_overflow_bitmap(void) 369 { 370 uint64_t pcr; 371 372 pcr = ultra_getpcr(); 373 return ((pcr & SPARC64_VI_PCR_OVF) >> CPC_SPARC64_VI_PCR_OVF_SHIFT); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 379 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 380 { 381 opl_pcbe_config_t *conf; 382 const struct nametable *n; 383 opl_pcbe_config_t *other_config; 384 385 /* 386 * If we've been handed an existing configuration, we need only preset 387 * the counter value. 388 */ 389 if (*data != NULL) { 390 conf = *data; 391 conf->opl_pic = (uint32_t)preset; 392 return (0); 393 } 394 395 if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC) 396 return (CPC_INVALID_PICNUM); 397 398 if (nattrs != 0) 399 return (CPC_INVALID_ATTRIBUTE); 400 401 /* 402 * Find other requests that will be programmed with this one, and ensure 403 * the flags don't conflict. 404 */ 405 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 406 (other_config->opl_flags != flags)) 407 return (CPC_CONFLICTING_REQS); 408 409 if ((n = find_event(picnum, event)) == NULL) 410 return (CPC_INVALID_EVENT); 411 412 conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP); 413 414 conf->opl_picno = picnum; 415 conf->opl_bits = (uint32_t)n->bits; 416 conf->opl_flags = flags; 417 conf->opl_pic = (uint32_t)preset; 418 419 *data = conf; 420 return (0); 421 } 422 423 static void 424 opl_pcbe_program(void *token) 425 { 426 opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; 427 opl_pcbe_config_t *firstconfig; 428 opl_pcbe_config_t *tmp; 429 uint64_t pcr; 430 uint64_t curpic; 431 uint8_t bitmap = 0; /* for used pic config */ 432 int i; 433 opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; 434 435 /* Get next pic config */ 436 firstconfig = tmp = kcpc_next_config(token, NULL, NULL); 437 438 while (tmp != NULL) { 439 ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC); 440 ASSERT(firstconfig->opl_flags == tmp->opl_flags); 441 pic[tmp->opl_picno] = tmp; 442 bitmap |= (uint8_t)(1 << tmp->opl_picno); 443 tmp = kcpc_next_config(token, tmp, NULL); 444 } 445 if (bitmap == 0) 446 panic("opl_pcbe: token %p has no configs", token); 447 448 /* Fill in unused pic config */ 449 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 450 if (bitmap & (1 << i)) 451 continue; 452 453 dummypic[i] = nullpic[i]; 454 dummypic[i].opl_flags = firstconfig->opl_flags; 455 pic[i] = &nullpic[i]; 456 } 457 458 /* 459 * For each counter pair, initialize event settings and 460 * counter values. 461 */ 462 ultra_setpcr(allstopped); 463 pcr = allstopped; 464 pcr &= ~SPARC64_VI_PCR_ULRO; 465 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 466 SPARC64_VI_PCR_SEL_PIC(pcr, i); 467 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 468 pic[i*2 + 1]->opl_bits); 469 470 ultra_setpcr(pcr); 471 curpic = (uint64_t)(pic[i*2]->opl_pic | 472 ((uint64_t)pic[i*2 + 1]->opl_pic << 32)); 473 ultra_setpic(curpic); 474 } 475 476 /* 477 * For each counter pair, enable the trace flags to start 478 * counting. Re-read the counters to sample the counter value now 479 * and use that as the baseline for future samples. 480 */ 481 482 /* Set pcr */ 483 pcr = ultra_getpcr(); 484 pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO); 485 if (pic[0]->opl_flags & CPC_COUNT_USER) 486 pcr |= SPARC64_VI_PCR_USR; 487 if (pic[0]->opl_flags & CPC_COUNT_SYSTEM) 488 pcr |= SPARC64_VI_PCR_SYS; 489 490 /* Set counter values */ 491 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 492 SPARC64_VI_PCR_SEL_PIC(pcr, i); 493 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 494 pic[i*2 + 1]->opl_bits); 495 496 ultra_setpcr(pcr); 497 curpic = ultra_getpic(); 498 pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); 499 pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); 500 } 501 502 } 503 504 static void 505 opl_pcbe_allstop(void) 506 { 507 ultra_setpcr(allstopped); 508 } 509 510 511 static void 512 opl_pcbe_sample(void *token) 513 { 514 uint64_t curpic; 515 uint64_t pcr; 516 int64_t diff; 517 uint64_t *pic_data[CPC_SPARC64_VI_NPIC]; 518 uint64_t *dtmp; 519 opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; 520 opl_pcbe_config_t *ctmp; 521 opl_pcbe_config_t *firstconfig; 522 uint8_t bitmap = 0; /* for used pic config */ 523 int i; 524 opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; 525 uint64_t dummypic_data[CPC_SPARC64_VI_NPIC]; 526 527 /* Get next pic config */ 528 firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp); 529 530 while (ctmp != NULL) { 531 ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC); 532 ASSERT(firstconfig->opl_flags == ctmp->opl_flags); 533 pic[ctmp->opl_picno] = ctmp; 534 pic_data[ctmp->opl_picno] = dtmp; 535 bitmap |= (uint8_t)(1 << ctmp->opl_picno); 536 ctmp = kcpc_next_config(token, ctmp, &dtmp); 537 } 538 if (bitmap == 0) 539 panic("opl_pcbe: token %p has no configs", token); 540 541 /* Fill in unuse pic config */ 542 for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { 543 if (bitmap & (1 << i)) 544 continue; 545 546 dummypic[i] = nullpic[i]; 547 dummypic[i].opl_flags = firstconfig->opl_flags; 548 pic[i] = &dummypic[i]; 549 550 dummypic_data[i] = 0; 551 pic_data[i] = &dummypic_data[i]; 552 } 553 554 pcr = ultra_getpcr(); 555 pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO); 556 557 for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { 558 SPARC64_VI_PCR_SEL_PIC(pcr, i); 559 SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, 560 pic[i*2 + 1]->opl_bits); 561 562 ultra_setpcr(pcr); 563 curpic = ultra_getpic(); 564 565 diff = (int64_t)((uint32_t)(curpic & PIC_MASK) - 566 pic[i*2]->opl_pic); 567 if (diff < 0) 568 diff += (1ll << 32); 569 *pic_data[i*2] += diff; 570 571 diff = (int64_t)((uint32_t)(curpic >> 32) - 572 pic[i*2 + 1]->opl_pic); 573 if (diff < 0) 574 diff += (1ll << 32); 575 *pic_data[i*2 + 1] += diff; 576 577 pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); 578 pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); 579 } 580 581 } 582 583 static void 584 opl_pcbe_free(void *config) 585 { 586 kmem_free(config, sizeof (opl_pcbe_config_t)); 587 } 588 589 590 static struct modlpcbe modlpcbe = { 591 &mod_pcbeops, 592 "SPARC64 VI Performance Counters v%I%", 593 &opl_pcbe_ops 594 }; 595 596 static struct modlinkage modl = { 597 MODREV_1, 598 &modlpcbe, 599 }; 600 601 int 602 _init(void) 603 { 604 if (opl_pcbe_init() != 0) 605 return (ENOTSUP); 606 return (mod_install(&modl)); 607 } 608 609 int 610 _fini(void) 611 { 612 return (mod_remove(&modl)); 613 } 614 615 int 616 _info(struct modinfo *mi) 617 { 618 return (mod_info(&modl, mi)); 619 } 620