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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains preset event names from the Performance Application 28 * Programming Interface v3.5 which included the following notice: 29 * 30 * Copyright (c) 2005,6 31 * Innovative Computing Labs 32 * Computer Science Department, 33 * University of Tennessee, 34 * Knoxville, TN. 35 * All Rights Reserved. 36 * 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions are met: 40 * 41 * * Redistributions of source code must retain the above copyright notice, 42 * this list of conditions and the following disclaimer. 43 * * Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * * Neither the name of the University of Tennessee nor the names of its 47 * contributors may be used to endorse or promote products derived from 48 * this software without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 51 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 54 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 * POSSIBILITY OF SUCH DAMAGE. 61 * 62 * 63 * This open source software license conforms to the BSD License template. 64 */ 65 66 /* 67 * Niagara2 Performance Counter Backend 68 */ 69 70 #include <sys/cpuvar.h> 71 #include <sys/systm.h> 72 #include <sys/archsystm.h> 73 #include <sys/cmn_err.h> 74 #include <sys/cpc_impl.h> 75 #include <sys/cpc_pcbe.h> 76 #include <sys/modctl.h> 77 #include <sys/machsystm.h> 78 #include <sys/sdt.h> 79 #include <sys/niagara2regs.h> 80 #include <sys/hsvc.h> 81 #include <sys/hypervisor_api.h> 82 #include <sys/disp.h> 83 84 /*LINTLIBRARY*/ 85 static int ni2_pcbe_init(void); 86 static uint_t ni2_pcbe_ncounters(void); 87 static const char *ni2_pcbe_impl_name(void); 88 static const char *ni2_pcbe_cpuref(void); 89 static char *ni2_pcbe_list_events(uint_t picnum); 90 static char *ni2_pcbe_list_attrs(void); 91 static uint64_t ni2_pcbe_event_coverage(char *event); 92 static uint64_t ni2_pcbe_overflow_bitmap(void); 93 static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 94 uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 95 void *token); 96 static void ni2_pcbe_program(void *token); 97 static void ni2_pcbe_allstop(void); 98 static void ni2_pcbe_sample(void *token); 99 static void ni2_pcbe_free(void *config); 100 101 extern void ultra_setpcr(uint64_t); 102 extern uint64_t ultra_getpcr(void); 103 extern void ultra_setpic(uint64_t); 104 extern uint64_t ultra_getpic(void); 105 extern uint64_t ultra_gettick(void); 106 extern char cpu_module_name[]; 107 108 pcbe_ops_t ni2_pcbe_ops = { 109 PCBE_VER_1, 110 CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, 111 ni2_pcbe_ncounters, 112 ni2_pcbe_impl_name, 113 ni2_pcbe_cpuref, 114 ni2_pcbe_list_events, 115 ni2_pcbe_list_attrs, 116 ni2_pcbe_event_coverage, 117 ni2_pcbe_overflow_bitmap, 118 ni2_pcbe_configure, 119 ni2_pcbe_program, 120 ni2_pcbe_allstop, 121 ni2_pcbe_sample, 122 ni2_pcbe_free 123 }; 124 125 typedef struct _ni2_pcbe_config { 126 uint_t pcbe_picno; /* 0 for pic0 or 1 for pic1 */ 127 uint32_t pcbe_evsel; /* %pcr event code unshifted */ 128 uint32_t pcbe_flags; /* hpriv/user/system/priv */ 129 uint32_t pcbe_pic; /* unshifted raw %pic value */ 130 } ni2_pcbe_config_t; 131 132 typedef struct _ni2_event { 133 const char *name; 134 const uint32_t emask; 135 const uint32_t emask_valid; /* Mask of unreserved MASK bits */ 136 } ni2_event_t; 137 138 typedef struct _ni2_generic_event { 139 char *name; 140 char *event; 141 } ni2_generic_event_t; 142 143 #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_PCR_PRIV_SHIFT) 144 #define EV_END {NULL, 0, 0} 145 #define GEN_EV_END {NULL, NULL} 146 147 static const uint64_t allstopped = (ULTRA_PCR_PRIVPIC | 148 CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1); 149 150 /* 151 * We update this array in the program and allstop routine. The array 152 * is checked in the sample routine to allow us to only perform the 153 * PCR.ht bit check when counting is in progress. 154 */ 155 static boolean_t ni2_cpc_counting[NCPU]; 156 157 static ni2_event_t ni2_events[] = { 158 { "Idle_strands", 0x000, 0x00 }, 159 { "Br_completed", 0x201, 0xff }, 160 { "Br_taken", 0x202, 0xff }, 161 { "Instr_FGU_arithmetic", 0x204, 0xff }, 162 { "Instr_ld", 0x208, 0xff }, 163 { "Instr_st", 0x210, 0xff }, 164 { "Instr_sw", 0x220, 0xff }, 165 { "Instr_other", 0x240, 0xff }, 166 { "Atomics", 0x280, 0xff }, 167 { "Instr_cnt", 0x2fd, 0xff }, 168 { "IC_miss", 0x301, 0x33 }, 169 { "DC_miss", 0x302, 0x33 }, 170 { "L2_imiss", 0x310, 0x33 }, 171 { "L2_dmiss_ld", 0x320, 0x33 }, 172 { "ITLB_HWTW_ref_L2", 0x404, 0x3c }, 173 { "DTLB_HWTW_ref_L2", 0x408, 0x3c }, 174 { "ITLB_HWTW_miss_L2", 0x410, 0x3c }, 175 { "DTLB_HWTW_miss_L2", 0x420, 0x3c }, 176 { "Stream_ld_to_PCX", 0x501, 0x3f }, 177 { "Stream_st_to_PCX", 0x502, 0x3f }, 178 { "CPU_ld_to_PCX", 0x504, 0x3f }, 179 { "CPU_ifetch_to_PCX", 0x508, 0x3f }, 180 { "CPU_st_to_PCX", 0x510, 0x3f }, 181 { "MMU_ld_to_PCX", 0x520, 0x3f }, 182 #ifdef KT_IMPL 183 { "DES_3DES_op", 0x601, 0xff }, 184 { "AES_op", 0x602, 0xff }, 185 { "Kasumi_op", 0x604, 0xff }, 186 { "MD5_SHA-1_SHA-256_op", 0x608, 0xff }, 187 { "MA_op", 0x610, 0xff }, 188 { "CRC_TCPIP_cksum", 0x620, 0xff }, 189 { "DES_3DES_busy_cycle", 0x701, 0xff }, 190 { "AES_busy_cycle", 0x702, 0xff }, 191 { "Kasumi_busy_cycle", 0x704, 0xff }, 192 { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0xff }, 193 { "MA_busy_cycle", 0x710, 0xff }, 194 { "CRC_MPA_cksum", 0x720, 0xff }, 195 #else 196 { "DES_3DES_op", 0x601, 0x3f }, 197 { "AES_op", 0x602, 0x3f }, 198 { "RC4_op", 0x604, 0x3f }, 199 { "MD5_SHA-1_SHA-256_op", 0x608, 0x3f }, 200 { "MA_op", 0x610, 0x3f }, 201 { "CRC_TCPIP_cksum", 0x620, 0x3f }, 202 { "DES_3DES_busy_cycle", 0x701, 0x3f }, 203 { "AES_busy_cycle", 0x702, 0x3f }, 204 { "RC4_busy_cycle", 0x704, 0x3f }, 205 { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0x3f }, 206 { "MA_busy_cycle", 0x710, 0x3f }, 207 { "CRC_MPA_cksum", 0x720, 0x3f }, 208 #endif 209 { "ITLB_miss", 0xb04, 0x0c }, 210 { "DTLB_miss", 0xb08, 0x0c }, 211 { "TLB_miss", 0xb0c, 0x0c }, 212 EV_END 213 }; 214 215 static ni2_generic_event_t ni2_generic_events[] = { 216 { "PAPI_tot_ins", "Instr_cnt" }, 217 { "PAPI_l1_dcm", "DC_miss" }, 218 { "PAPI_l1_icm", "IC_miss" }, 219 { "PAPI_l2_icm", "L2_imiss" }, 220 { "PAPI_l2_ldm", "L2_dmiss_ld" }, 221 { "PAPI_tlb_dm", "DTLB_miss" }, 222 { "PAPI_tlb_im", "ITLB_miss" }, 223 { "PAPI_tlb_tm", "TLB_miss" }, 224 { "PAPI_br_tkn", "Br_taken" }, 225 { "PAPI_br_ins", "Br_completed" }, 226 { "PAPI_ld_ins", "Instr_ld" }, 227 { "PAPI_sr_ins", "Instr_st" }, 228 { "PAPI_fp_ops", "Instr_FGU_arithmetic" }, 229 { "PAPI_fp_ins", "Instr_FGU_arithmetic" }, 230 GEN_EV_END 231 }; 232 233 static char *evlist; 234 static size_t evlist_sz; 235 static uint16_t pcr_pic0_mask; 236 static uint16_t pcr_pic1_mask; 237 238 #define CPU_REF_URL " Documentation for Sun processors can be found at: " \ 239 "http://www.sun.com/processors/manuals" 240 241 #if defined(NIAGARA2_IMPL) 242 static const char *cpu_impl_name = "UltraSPARC T2"; 243 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" " 244 "for descriptions of these events." CPU_REF_URL; 245 #elif defined(VFALLS_IMPL) 246 static const char *cpu_impl_name = "UltraSPARC T2+"; 247 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" " 248 "for descriptions of these events." CPU_REF_URL; 249 #elif defined(KT_IMPL) 250 static const char *cpu_impl_name = "UltraSPARC KT"; 251 static const char *cpu_pcbe_ref = "See the \"UltraSPARC KT User's Manual\" " 252 "for descriptions of these events." CPU_REF_URL; 253 #endif 254 255 static boolean_t cpu_hsvc_available = B_TRUE; 256 257 static int 258 ni2_pcbe_init(void) 259 { 260 ni2_event_t *evp; 261 ni2_generic_event_t *gevp; 262 int status; 263 uint64_t cpu_hsvc_major; 264 uint64_t cpu_hsvc_minor; 265 #if defined(NIAGARA2_IMPL) 266 uint64_t hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU; 267 uint64_t hsvc_cpu_major = NIAGARA2_HSVC_MAJOR; 268 #elif defined(VFALLS_IMPL) 269 uint64_t hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU; 270 uint64_t hsvc_cpu_major = VFALLS_HSVC_MAJOR; 271 #elif defined(KT_IMPL) 272 uint64_t hsvc_cpu_group = HSVC_GROUP_KT_CPU; 273 uint64_t hsvc_cpu_major = KT_HSVC_MAJOR; 274 #endif 275 276 pcr_pic0_mask = CPC_PCR_PIC0_MASK; 277 pcr_pic1_mask = CPC_PCR_PIC1_MASK; 278 279 /* 280 * Validate API version for Niagara2 specific hypervisor services 281 */ 282 status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major, 283 &cpu_hsvc_minor); 284 if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) { 285 cmn_err(CE_WARN, "hypervisor services not negotiated " 286 "or unsupported major number: group: 0x%lx major: 0x%lx " 287 "minor: 0x%lx errno: %d", hsvc_cpu_group, 288 cpu_hsvc_major, cpu_hsvc_minor, status); 289 cpu_hsvc_available = B_FALSE; 290 } 291 292 /* 293 * Construct event list. 294 * 295 * First pass: Calculate size needed. We'll need an additional byte 296 * for the NULL pointer during the last strcat. 297 * 298 * Second pass: Copy strings. 299 */ 300 for (evp = ni2_events; evp->name != NULL; evp++) 301 evlist_sz += strlen(evp->name) + 1; 302 303 for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) 304 evlist_sz += strlen(gevp->name) + 1; 305 306 evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP); 307 evlist[0] = '\0'; 308 309 for (evp = ni2_events; evp->name != NULL; evp++) { 310 (void) strcat(evlist, evp->name); 311 (void) strcat(evlist, ","); 312 } 313 314 for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) { 315 (void) strcat(evlist, gevp->name); 316 (void) strcat(evlist, ","); 317 } 318 319 /* 320 * Remove trailing comma. 321 */ 322 evlist[evlist_sz - 1] = '\0'; 323 324 return (0); 325 } 326 327 static uint_t 328 ni2_pcbe_ncounters(void) 329 { 330 return (2); 331 } 332 333 static const char * 334 ni2_pcbe_impl_name(void) 335 { 336 return (cpu_impl_name); 337 } 338 339 static const char * 340 ni2_pcbe_cpuref(void) 341 { 342 return (cpu_pcbe_ref); 343 } 344 345 static char * 346 ni2_pcbe_list_events(uint_t picnum) 347 { 348 ASSERT(picnum < cpc_ncounters); 349 350 return (evlist); 351 } 352 353 static char * 354 ni2_pcbe_list_attrs(void) 355 { 356 if (cpu_hsvc_available == B_TRUE) 357 #if defined(NIAGARA2_IMPL) 358 return ("hpriv,emask"); 359 #elif defined(VFALLS_IMPL) 360 return ("hpriv,l2ctl,emask"); 361 #elif defined(KT_IMPL) 362 return ("hpriv,l2ctl,emask,sample"); 363 #endif 364 else 365 #if defined(KT_IMPL) 366 return ("emask,sample"); 367 #else 368 return ("emask"); 369 #endif 370 } 371 372 static ni2_generic_event_t * 373 find_generic_event(char *name) 374 { 375 ni2_generic_event_t *gevp; 376 377 for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) { 378 if (strcmp(name, gevp->name) == 0) 379 return (gevp); 380 } 381 382 return (NULL); 383 } 384 385 static ni2_event_t * 386 find_event(char *name) 387 { 388 ni2_event_t *evp; 389 390 for (evp = ni2_events; evp->name != NULL; evp++) 391 if (strcmp(name, evp->name) == 0) 392 return (evp); 393 394 return (NULL); 395 } 396 397 /*ARGSUSED*/ 398 static uint64_t 399 ni2_pcbe_event_coverage(char *event) 400 { 401 /* 402 * Check whether counter event is supported 403 */ 404 if (find_event(event) == NULL && find_generic_event(event) == NULL) 405 return (0); 406 407 /* 408 * Fortunately, both pic0 and pic1 can count all events. 409 */ 410 return (0x3); 411 } 412 413 static uint64_t 414 ni2_pcbe_overflow_bitmap(void) 415 { 416 uint64_t pcr, overflow; 417 uint64_t pic; 418 uint32_t pic0, pic1; 419 boolean_t update_pic = B_FALSE; 420 boolean_t pic_inrange = B_FALSE; 421 422 ASSERT(getpil() >= DISP_LEVEL); 423 pcr = ultra_getpcr(); 424 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 425 overflow = (pcr & CPC_PCR_OV0_MASK) >> 426 CPC_PCR_OV0_SHIFT; 427 overflow |= (pcr & CPC_PCR_OV1_MASK) >> 428 CPC_PCR_OV1_SHIFT; 429 430 pic = ultra_getpic(); 431 pic0 = (uint32_t)(pic & PIC0_MASK); 432 pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK); 433 434 pcr |= (CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1); 435 436 if (overflow & 0x1) { 437 pcr &= ~(CPC_PCR_OV0_MASK | 438 CPC_PCR_HOLDOV0); 439 pic_inrange = PIC_IN_OV_RANGE(pic0); 440 #if defined(KT_IMPL) 441 if (pcr & CPC_PCR_SAMPLE_MODE_MASK) 442 pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic0); 443 #endif 444 if (pic_inrange) { 445 pic0 = 0; 446 update_pic = B_TRUE; 447 } 448 } 449 450 if (overflow & 0x2) { 451 pcr &= ~(CPC_PCR_OV1_MASK | 452 CPC_PCR_HOLDOV1); 453 pic_inrange = PIC_IN_OV_RANGE(pic1); 454 #if defined(KT_IMPL) 455 if (pcr & CPC_PCR_SAMPLE_MODE_MASK) 456 pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic1); 457 #endif 458 if (pic_inrange) { 459 pic1 = 0; 460 update_pic = B_TRUE; 461 } 462 } 463 464 if (update_pic) 465 ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0); 466 467 /* 468 * The HV interface does not need to be used here because we are 469 * only resetting the OV bits and do not need to set the HT bit. 470 */ 471 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 472 ultra_setpcr(pcr); 473 474 return (overflow); 475 } 476 477 /*ARGSUSED*/ 478 static int 479 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 480 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 481 { 482 ni2_pcbe_config_t *cfg; 483 ni2_pcbe_config_t *other_config; 484 ni2_event_t *evp; 485 ni2_generic_event_t *gevp; 486 int i; 487 uint32_t evsel; 488 #if defined(VFALLS_IMPL) || defined(KT_IMPL) 489 uint64_t l2ctl = 0; 490 #endif 491 492 /* 493 * If we've been handed an existing configuration, we need only preset 494 * the counter value. 495 */ 496 if (*data != NULL) { 497 cfg = *data; 498 cfg->pcbe_pic = (uint32_t)preset; 499 return (0); 500 } 501 502 if (picnum > 1) 503 return (CPC_INVALID_PICNUM); 504 505 506 if ((evp = find_event(event)) == NULL) { 507 if ((gevp = find_generic_event(event)) != NULL) { 508 evp = find_event(gevp->event); 509 ASSERT(evp != NULL); 510 511 if (nattrs > 0) 512 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 513 } else { 514 return (CPC_INVALID_EVENT); 515 } 516 } 517 518 evsel = evp->emask; 519 520 for (i = 0; i < nattrs; i++) { 521 if (strcmp(attrs[i].ka_name, "hpriv") == 0) { 522 if (attrs[i].ka_val != 0) 523 flags |= CPC_COUNT_HV; 524 } else if (strcmp(attrs[i].ka_name, "emask") == 0) { 525 if ((attrs[i].ka_val | evp->emask_valid) != 526 evp->emask_valid) 527 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 528 evsel |= attrs[i].ka_val; 529 #if defined(VFALLS_IMPL) || defined(KT_IMPL) 530 } else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) { 531 if ((attrs[i].ka_val | L2_CTL_MASK) != 532 L2_CTL_MASK) 533 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 534 else 535 l2ctl = attrs[i].ka_val; 536 #endif 537 #if defined(KT_IMPL) 538 } else if (strcmp(attrs[i].ka_name, "sample") == 0) { 539 if (attrs[i].ka_val != 0) 540 flags |= CPC_COUNT_SAMPLE_MODE; 541 #endif 542 } else 543 return (CPC_INVALID_ATTRIBUTE); 544 } 545 546 #if defined(VFALLS_IMPL) || defined(KT_IMPL) 547 /* 548 * Set PERF_CONTROL bits in L2_CONTROL_REG only when events have 549 * SL bits equal to 3. 550 */ 551 if ((evsel & SL3_MASK) == SL3_MASK) { 552 if ((hv_niagara_setperf(HV_L2_CTL, l2ctl)) != 0) 553 return (CPC_HV_NO_ACCESS); 554 } 555 #endif 556 557 /* 558 * Find other requests that will be programmed with this one, and ensure 559 * the flags don't conflict. 560 */ 561 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 562 (other_config->pcbe_flags != flags)) 563 return (CPC_CONFLICTING_REQS); 564 565 /* 566 * If the hpriv attribute is present, make sure we have 567 * access to hyperprivileged events before continuing with 568 * this configuration. If we can set the ht bit in the PCR 569 * successfully, we must have access to hyperprivileged 570 * events. 571 * 572 * If this is a static per-CPU configuration, the CPC 573 * driver ensures there can not be more than one for this 574 * CPU. If this is a per-LWP configuration, the driver 575 * ensures no static per-CPU counting is ongoing and that 576 * the target LWP is not already being monitored. 577 */ 578 if (flags & CPC_COUNT_HV) { 579 kpreempt_disable(); 580 581 DTRACE_PROBE1(niagara2__setpcr, uint64_t, 582 allstopped | CPC_PCR_HT); 583 if (hv_niagara_setperf(HV_SPARC_CTL, 584 allstopped | CPC_PCR_HT) != H_EOK) { 585 kpreempt_enable(); 586 return (CPC_HV_NO_ACCESS); 587 } 588 589 DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped); 590 (void) hv_niagara_setperf(HV_SPARC_CTL, allstopped); 591 592 kpreempt_enable(); 593 } 594 595 cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP); 596 597 cfg->pcbe_picno = picnum; 598 cfg->pcbe_evsel = evsel; 599 cfg->pcbe_flags = flags; 600 cfg->pcbe_pic = (uint32_t)preset; 601 602 *data = cfg; 603 return (0); 604 } 605 606 static void 607 ni2_pcbe_program(void *token) 608 { 609 ni2_pcbe_config_t *pic0; 610 ni2_pcbe_config_t *pic1; 611 ni2_pcbe_config_t *tmp; 612 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 613 uint64_t pcr; 614 uint64_t curpic; 615 uint64_t toe; 616 617 /* enable trap-on-event for pic0 and pic1 */ 618 toe = (CPC_PCR_TOE0 | CPC_PCR_TOE1); 619 620 if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == 621 NULL) 622 panic("ni2_pcbe: token %p has no configs", token); 623 624 if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { 625 pic1 = &nullcfg; 626 nullcfg.pcbe_flags = pic0->pcbe_flags; 627 toe = CPC_PCR_TOE0; /* enable trap-on-event for pic0 */ 628 } 629 630 if (pic0->pcbe_picno != 0) { 631 /* 632 * pic0 is counter 1, so if we need the null config it should 633 * be counter 0. 634 */ 635 nullcfg.pcbe_picno = 0; 636 tmp = pic0; 637 pic0 = pic1; 638 pic1 = tmp; 639 toe = CPC_PCR_TOE1; /* enable trap-on-event for pic1 */ 640 } 641 642 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 643 panic("%s: bad config on token %p\n", cpu_impl_name, token); 644 645 /* 646 * UltraSPARC does not allow pic0 to be configured differently 647 * from pic1. If the flags on these two configurations are 648 * different, they are incompatible. This condition should be 649 * caught at configure time. 650 */ 651 ASSERT(pic0->pcbe_flags == pic1->pcbe_flags); 652 653 ni2_pcbe_allstop(); 654 655 ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) | 656 (uint64_t)pic0->pcbe_pic); 657 658 pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_PCR_PIC0_SHIFT; 659 pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) << 660 CPC_PCR_PIC1_SHIFT; 661 662 if (pic0->pcbe_flags & CPC_COUNT_USER) 663 pcr |= (1ull << CPC_PCR_UT_SHIFT); 664 if (pic0->pcbe_flags & CPC_COUNT_SYSTEM) 665 pcr |= (1ull << CPC_PCR_ST_SHIFT); 666 if (pic0->pcbe_flags & CPC_COUNT_HV) 667 pcr |= (1ull << CPC_PCR_HT_SHIFT); 668 #if defined(KT_IMPL) 669 if (pic0->pcbe_flags & CPC_COUNT_SAMPLE_MODE) 670 pcr |= (1ull << CPC_PCR_SAMPLE_MODE_SHIFT); 671 #endif 672 pcr |= toe; 673 674 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 675 676 if (pic0->pcbe_flags & CPC_COUNT_HV) { 677 /* 678 * The ht bit in the PCR is only writable in 679 * hyperprivileged mode. So if we are counting 680 * hpriv events, we must use the HV interface 681 * hv_niagara_setperf to set the PCR. If this 682 * fails, assume we no longer have access to 683 * hpriv events. 684 */ 685 if (hv_niagara_setperf(HV_SPARC_CTL, pcr) != H_EOK) { 686 kcpc_invalidate_config(token); 687 return; 688 } 689 } else 690 /* Set the PCR with no hpriv event counting enabled. */ 691 ultra_setpcr(pcr); 692 693 ni2_cpc_counting[CPU->cpu_id] = B_TRUE; 694 695 /* 696 * On UltraSPARC, only read-to-read counts are accurate. We cannot 697 * expect the value we wrote into the PIC, above, to be there after 698 * starting the counter. We must sample the counter value now and use 699 * that as the baseline for future samples. 700 */ 701 curpic = ultra_getpic(); 702 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 703 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 704 705 DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic); 706 } 707 708 static void 709 ni2_pcbe_allstop(void) 710 { 711 /* 712 * We use the HV interface here because if we were counting 713 * hyperprivileged events, we must reset the PCR.ht bit to stop 714 * the counting. In the event that this HV call fails, we fall 715 * back on ultra_setpcr which does not have write access to the 716 * ht bit. 717 */ 718 if (hv_niagara_setperf(HV_SPARC_CTL, allstopped) != H_EOK) 719 ultra_setpcr(allstopped); 720 721 ni2_cpc_counting[CPU->cpu_id] = B_FALSE; 722 } 723 724 static void 725 ni2_pcbe_sample(void *token) 726 { 727 uint64_t curpic; 728 int64_t diff; 729 uint64_t *pic0_data; 730 uint64_t *pic1_data; 731 uint64_t *dtmp; 732 uint64_t tmp; 733 uint64_t pcr; 734 ni2_pcbe_config_t *pic0; 735 ni2_pcbe_config_t *pic1; 736 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 737 ni2_pcbe_config_t *ctmp; 738 739 curpic = ultra_getpic(); 740 DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic); 741 742 if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL) 743 panic("%s: token %p has no configs", cpu_impl_name, token); 744 745 if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) { 746 pic1 = &nullcfg; 747 pic1_data = &tmp; 748 } 749 750 if (pic0->pcbe_picno != 0) { 751 nullcfg.pcbe_picno = 0; 752 ctmp = pic0; 753 pic0 = pic1; 754 pic1 = ctmp; 755 dtmp = pic0_data; 756 pic0_data = pic1_data; 757 pic1_data = dtmp; 758 } 759 760 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 761 panic("%s: bad config on token %p\n", cpu_impl_name, token); 762 763 764 if (pic0->pcbe_flags & CPC_COUNT_HV) { 765 /* 766 * If the hpriv attribute is present, but the HT bit 767 * is not set in the PCR, access to hyperprivileged 768 * events must have been revoked. Only perform this 769 * check if counting is not stopped. 770 */ 771 pcr = ultra_getpcr(); 772 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 773 if (ni2_cpc_counting[CPU->cpu_id] && 774 !(pcr & CPC_PCR_HT)) { 775 kcpc_invalidate_config(token); 776 return; 777 } 778 } 779 780 diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic; 781 if (diff < 0) 782 diff += (1ll << 32); 783 *pic0_data += diff; 784 785 diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic; 786 if (diff < 0) 787 diff += (1ll << 32); 788 *pic1_data += diff; 789 790 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 791 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 792 } 793 794 static void 795 ni2_pcbe_free(void *config) 796 { 797 kmem_free(config, sizeof (ni2_pcbe_config_t)); 798 } 799 800 801 static struct modlpcbe modlpcbe = { 802 &mod_pcbeops, 803 #if defined(NIAGARA2_IMPL) 804 "UltraSPARC T2 Performance Counters", 805 #elif defined(VFALLS_IMPL) 806 "UltraSPARC T2+ Performance Counters", 807 #elif defined(KT_IMPL) 808 "UltraSPARC KT Performance Counters", 809 #endif 810 &ni2_pcbe_ops 811 }; 812 813 static struct modlinkage modl = { 814 MODREV_1, 815 &modlpcbe, 816 }; 817 818 int 819 _init(void) 820 { 821 if (ni2_pcbe_init() != 0) 822 return (ENOTSUP); 823 return (mod_install(&modl)); 824 } 825 826 int 827 _fini(void) 828 { 829 return (mod_remove(&modl)); 830 } 831 832 int 833 _info(struct modinfo *mi) 834 { 835 return (mod_info(&modl, mi)); 836 } 837