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 * Niagara2 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/archsystm.h> 35 #include <sys/cmn_err.h> 36 #include <sys/cpc_impl.h> 37 #include <sys/cpc_pcbe.h> 38 #include <sys/modctl.h> 39 #include <sys/machsystm.h> 40 #include <sys/sdt.h> 41 #include <sys/niagara2regs.h> 42 #include <sys/hsvc.h> 43 #include <sys/hypervisor_api.h> 44 #include <sys/disp.h> 45 46 /*LINTLIBRARY*/ 47 static int ni2_pcbe_init(void); 48 static uint_t ni2_pcbe_ncounters(void); 49 static const char *ni2_pcbe_impl_name(void); 50 static const char *ni2_pcbe_cpuref(void); 51 static char *ni2_pcbe_list_events(uint_t picnum); 52 static char *ni2_pcbe_list_attrs(void); 53 static uint64_t ni2_pcbe_event_coverage(char *event); 54 static uint64_t ni2_pcbe_overflow_bitmap(void); 55 static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 56 uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 57 void *token); 58 static void ni2_pcbe_program(void *token); 59 static void ni2_pcbe_allstop(void); 60 static void ni2_pcbe_sample(void *token); 61 static void ni2_pcbe_free(void *config); 62 63 extern void ultra_setpcr(uint64_t); 64 extern uint64_t ultra_getpcr(void); 65 extern void ultra_setpic(uint64_t); 66 extern uint64_t ultra_getpic(void); 67 extern uint64_t ultra_gettick(void); 68 extern char cpu_module_name[]; 69 70 pcbe_ops_t ni2_pcbe_ops = { 71 PCBE_VER_1, 72 CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, 73 ni2_pcbe_ncounters, 74 ni2_pcbe_impl_name, 75 ni2_pcbe_cpuref, 76 ni2_pcbe_list_events, 77 ni2_pcbe_list_attrs, 78 ni2_pcbe_event_coverage, 79 ni2_pcbe_overflow_bitmap, 80 ni2_pcbe_configure, 81 ni2_pcbe_program, 82 ni2_pcbe_allstop, 83 ni2_pcbe_sample, 84 ni2_pcbe_free 85 }; 86 87 typedef struct _ni2_pcbe_config { 88 uint_t pcbe_picno; /* 0 for pic0 or 1 for pic1 */ 89 uint32_t pcbe_evsel; /* %pcr event code unshifted */ 90 uint32_t pcbe_flags; /* hpriv/user/system/priv */ 91 uint32_t pcbe_pic; /* unshifted raw %pic value */ 92 } ni2_pcbe_config_t; 93 94 typedef struct _ni2_event { 95 const char *name; 96 const uint32_t emask; 97 const uint32_t emask_valid; /* Mask of unreserved MASK bits */ 98 } ni2_event_t; 99 100 #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_NIAGARA2_PCR_PRIV_SHIFT) 101 #define EV_END {NULL, 0, 0} 102 103 static const uint64_t allstopped = (ULTRA_PCR_PRIVPIC | 104 CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); 105 106 /* 107 * We update this array in the program and allstop routine. The array 108 * is checked in the sample routine to allow us to only perform the 109 * PCR.ht bit check when counting is in progress. 110 */ 111 static boolean_t ni2_cpc_counting[NCPU]; 112 113 static ni2_event_t ni2_events[] = { 114 { "Idle_strands", 0x000, 0x00 }, 115 { "Br_completed", 0x201, 0xff }, 116 { "Br_taken", 0x202, 0xff }, 117 { "Instr_FGU_arithmetic", 0x204, 0xff }, 118 { "Instr_ld", 0x208, 0xff }, 119 { "Instr_st", 0x210, 0xff }, 120 { "Instr_sw", 0x220, 0xff }, 121 { "Instr_other", 0x240, 0xff }, 122 { "Atomics", 0x280, 0xff }, 123 { "Instr_cnt", 0x2fd, 0xff }, 124 { "IC_miss", 0x301, 0x33 }, 125 { "DC_miss", 0x302, 0x33 }, 126 { "L2_imiss", 0x310, 0x33 }, 127 { "L2_dmiss_ld", 0x320, 0x33 }, 128 { "ITLB_HWTW_ref_L2", 0x404, 0x3c }, 129 { "DTLB_HWTW_ref_L2", 0x408, 0x3c }, 130 { "ITLB_HWTW_miss_L2", 0x410, 0x3c }, 131 { "DTLB_HWTW_miss_L2", 0x420, 0x3c }, 132 { "Stream_ld_to_PCX", 0x501, 0x3f }, 133 { "Stream_st_to_PCX", 0x502, 0x3f }, 134 { "CPU_ld_to_PCX", 0x504, 0x3f }, 135 { "CPU_ifetch_to_PCX", 0x508, 0x3f }, 136 { "CPU_st_to_PCX", 0x510, 0x3f }, 137 { "MMU_ld_to_PCX", 0x520, 0x3f }, 138 { "DES_3DES_op", 0x601, 0x3f }, 139 { "AES_op", 0x602, 0x3f }, 140 { "RC4_op", 0x604, 0x3f }, 141 { "MD5_SHA-1_SHA-256_op", 0x608, 0x3f }, 142 { "MA_op", 0x610, 0x3f }, 143 { "CRC_TCPIP_cksum", 0x620, 0x3f }, 144 { "DES_3DES_busy_cycle", 0x701, 0x3f }, 145 { "AES_busy_cycle", 0x702, 0x3f }, 146 { "RC4_busy_cycle", 0x704, 0x3f }, 147 { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0x3f }, 148 { "MA_busy_cycle", 0x710, 0x3f }, 149 { "CRC_MPA_cksum", 0x720, 0x3f }, 150 { "ITLB_miss", 0xb04, 0x0c }, 151 { "DTLB_miss", 0xb08, 0x0c }, 152 { "TLB_miss", 0xb0c, 0x0c }, 153 EV_END 154 }; 155 156 static char *evlist; 157 static size_t evlist_sz; 158 static uint16_t pcr_pic0_mask; 159 static uint16_t pcr_pic1_mask; 160 161 #define CPU_REF_URL " Documentation for Sun processors can be found at: " \ 162 "http://www.sun.com/processors/manuals" 163 164 #if defined(NIAGARA2_IMPL) 165 static const char *cpu_impl_name = "UltraSPARC T2"; 166 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" " 167 "for descriptions of these events." CPU_REF_URL; 168 #elif defined(VFALLS_IMPL) 169 static const char *cpu_impl_name = "UltraSPARC T2+"; 170 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" " 171 "for descriptions of these events." CPU_REF_URL; 172 #endif 173 174 static boolean_t cpu_hsvc_available = B_TRUE; 175 176 static int 177 ni2_pcbe_init(void) 178 { 179 ni2_event_t *evp; 180 int status; 181 uint64_t cpu_hsvc_major; 182 uint64_t cpu_hsvc_minor; 183 #if defined(NIAGARA2_IMPL) 184 uint64_t hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU; 185 uint64_t hsvc_cpu_major = NIAGARA2_HSVC_MAJOR; 186 #elif defined(VFALLS_IMPL) 187 uint64_t hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU; 188 uint64_t hsvc_cpu_major = VFALLS_HSVC_MAJOR; 189 #endif 190 191 pcr_pic0_mask = CPC_NIAGARA2_PCR_PIC0_MASK; 192 pcr_pic1_mask = CPC_NIAGARA2_PCR_PIC1_MASK; 193 194 /* 195 * Validate API version for Niagara2 specific hypervisor services 196 */ 197 status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major, 198 &cpu_hsvc_minor); 199 if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) { 200 cmn_err(CE_WARN, "hypervisor services not negotiated " 201 "or unsupported major number: group: 0x%lx major: 0x%lx " 202 "minor: 0x%lx errno: %d", hsvc_cpu_group, 203 cpu_hsvc_major, cpu_hsvc_minor, status); 204 cpu_hsvc_available = B_FALSE; 205 } 206 207 /* 208 * Construct event list. 209 * 210 * First pass: Calculate size needed. We'll need an additional byte 211 * for the NULL pointer during the last strcat. 212 * 213 * Second pass: Copy strings. 214 */ 215 for (evp = ni2_events; evp->name != NULL; evp++) 216 evlist_sz += strlen(evp->name) + 1; 217 218 evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP); 219 evlist[0] = '\0'; 220 221 for (evp = ni2_events; evp->name != NULL; evp++) { 222 (void) strcat(evlist, evp->name); 223 (void) strcat(evlist, ","); 224 } 225 /* 226 * Remove trailing comma. 227 */ 228 evlist[evlist_sz - 1] = '\0'; 229 230 return (0); 231 } 232 233 static uint_t 234 ni2_pcbe_ncounters(void) 235 { 236 return (2); 237 } 238 239 static const char * 240 ni2_pcbe_impl_name(void) 241 { 242 return (cpu_impl_name); 243 } 244 245 static const char * 246 ni2_pcbe_cpuref(void) 247 { 248 return (cpu_pcbe_ref); 249 } 250 251 static char * 252 ni2_pcbe_list_events(uint_t picnum) 253 { 254 ASSERT(picnum < cpc_ncounters); 255 256 return (evlist); 257 } 258 259 static char * 260 ni2_pcbe_list_attrs(void) 261 { 262 if (cpu_hsvc_available == B_TRUE) 263 #if defined(NIAGARA2_IMPL) 264 return ("hpriv,emask"); 265 #elif defined(VFALLS_IMPL) 266 return ("hpriv,l2ctl,emask"); 267 #endif 268 else 269 return ("emask"); 270 } 271 272 static ni2_event_t * 273 find_event(char *name) 274 { 275 ni2_event_t *evp; 276 277 for (evp = ni2_events; evp->name != NULL; evp++) 278 if (strcmp(name, evp->name) == 0) 279 return (evp); 280 281 return (NULL); 282 } 283 284 /*ARGSUSED*/ 285 static uint64_t 286 ni2_pcbe_event_coverage(char *event) 287 { 288 /* 289 * Fortunately, both pic0 and pic1 can count all events. 290 */ 291 return (0x3); 292 } 293 294 static uint64_t 295 ni2_pcbe_overflow_bitmap(void) 296 { 297 uint64_t pcr, overflow; 298 uint64_t pic; 299 uint32_t pic0, pic1; 300 boolean_t update_pic = B_FALSE; 301 302 ASSERT(getpil() >= DISP_LEVEL); 303 pcr = ultra_getpcr(); 304 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 305 overflow = (pcr & CPC_NIAGARA2_PCR_OV0_MASK) >> 306 CPC_NIAGARA2_PCR_OV0_SHIFT; 307 overflow |= (pcr & CPC_NIAGARA2_PCR_OV1_MASK) >> 308 CPC_NIAGARA2_PCR_OV1_SHIFT; 309 310 pic = ultra_getpic(); 311 pic0 = (uint32_t)(pic & PIC0_MASK); 312 pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK); 313 314 pcr |= (CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); 315 316 if (overflow & 0x1) { 317 pcr &= ~(CPC_NIAGARA2_PCR_OV0_MASK | 318 CPC_NIAGARA2_PCR_HOLDOV0); 319 if (PIC_IN_OV_RANGE(pic0)) { 320 pic0 = 0; 321 update_pic = B_TRUE; 322 } 323 } 324 325 if (overflow & 0x2) { 326 pcr &= ~(CPC_NIAGARA2_PCR_OV1_MASK | 327 CPC_NIAGARA2_PCR_HOLDOV1); 328 if (PIC_IN_OV_RANGE(pic1)) { 329 pic1 = 0; 330 update_pic = B_TRUE; 331 } 332 } 333 334 if (update_pic) 335 ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0); 336 337 /* 338 * The HV interface does not need to be used here because we are 339 * only resetting the OV bits and do not need to set the HT bit. 340 */ 341 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 342 ultra_setpcr(pcr); 343 344 return (overflow); 345 } 346 347 /*ARGSUSED*/ 348 static int 349 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 350 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 351 { 352 ni2_pcbe_config_t *cfg; 353 ni2_pcbe_config_t *other_config; 354 ni2_event_t *evp; 355 int i; 356 uint32_t evsel; 357 358 /* 359 * If we've been handed an existing configuration, we need only preset 360 * the counter value. 361 */ 362 if (*data != NULL) { 363 cfg = *data; 364 cfg->pcbe_pic = (uint32_t)preset; 365 return (0); 366 } 367 368 if (picnum > 1) 369 return (CPC_INVALID_PICNUM); 370 371 if ((evp = find_event(event)) == NULL) 372 return (CPC_INVALID_EVENT); 373 374 evsel = evp->emask; 375 376 for (i = 0; i < nattrs; i++) { 377 if (strcmp(attrs[i].ka_name, "hpriv") == 0) { 378 if (attrs[i].ka_val != 0) 379 flags |= CPC_COUNT_HV; 380 } else if (strcmp(attrs[i].ka_name, "emask") == 0) { 381 if ((attrs[i].ka_val | evp->emask_valid) != 382 evp->emask_valid) 383 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 384 evsel |= attrs[i].ka_val; 385 #if defined(VFALLS_IMPL) 386 } else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) { 387 if ((attrs[i].ka_val | VFALLS_L2_CTL_MASK) != 388 VFALLS_L2_CTL_MASK) 389 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 390 /* 391 * Set PERF_CONTROL bits in L2_CONTROL_REG 392 * only when events have SL bits equal to 3. 393 */ 394 if ((evsel & VFALLS_SL3_MASK) == VFALLS_SL3_MASK) { 395 if ((hv_niagara_setperf(HV_NIAGARA_L2_CTL, 396 attrs[i].ka_val)) != 0) 397 return (CPC_HV_NO_ACCESS); 398 } 399 #endif 400 } else 401 return (CPC_INVALID_ATTRIBUTE); 402 } 403 404 /* 405 * Find other requests that will be programmed with this one, and ensure 406 * the flags don't conflict. 407 */ 408 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 409 (other_config->pcbe_flags != flags)) 410 return (CPC_CONFLICTING_REQS); 411 412 /* 413 * If the hpriv attribute is present, make sure we have 414 * access to hyperprivileged events before continuing with 415 * this configuration. If we can set the ht bit in the PCR 416 * successfully, we must have access to hyperprivileged 417 * events. 418 * 419 * If this is a static per-CPU configuration, the CPC 420 * driver ensures there can not be more than one for this 421 * CPU. If this is a per-LWP configuration, the driver 422 * ensures no static per-CPU counting is ongoing and that 423 * the target LWP is not already being monitored. 424 */ 425 if (flags & CPC_COUNT_HV) { 426 kpreempt_disable(); 427 428 DTRACE_PROBE1(niagara2__setpcr, uint64_t, 429 allstopped | CPC_NIAGARA2_PCR_HT); 430 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, 431 allstopped | CPC_NIAGARA2_PCR_HT) != H_EOK) { 432 kpreempt_enable(); 433 return (CPC_HV_NO_ACCESS); 434 } 435 436 DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped); 437 (void) hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped); 438 439 kpreempt_enable(); 440 } 441 442 cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP); 443 444 cfg->pcbe_picno = picnum; 445 cfg->pcbe_evsel = evsel; 446 cfg->pcbe_flags = flags; 447 cfg->pcbe_pic = (uint32_t)preset; 448 449 *data = cfg; 450 return (0); 451 } 452 453 static void 454 ni2_pcbe_program(void *token) 455 { 456 ni2_pcbe_config_t *pic0; 457 ni2_pcbe_config_t *pic1; 458 ni2_pcbe_config_t *tmp; 459 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 460 uint64_t pcr; 461 uint64_t curpic; 462 uint64_t toe; 463 464 /* enable trap-on-event for pic0 and pic1 */ 465 toe = (CPC_NIAGARA2_PCR_TOE0 | CPC_NIAGARA2_PCR_TOE1); 466 467 if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == 468 NULL) 469 panic("ni2_pcbe: token %p has no configs", token); 470 471 if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { 472 pic1 = &nullcfg; 473 nullcfg.pcbe_flags = pic0->pcbe_flags; 474 toe = CPC_NIAGARA2_PCR_TOE0; /* enable trap-on-event for pic0 */ 475 } 476 477 if (pic0->pcbe_picno != 0) { 478 /* 479 * pic0 is counter 1, so if we need the null config it should 480 * be counter 0. 481 */ 482 nullcfg.pcbe_picno = 0; 483 tmp = pic0; 484 pic0 = pic1; 485 pic1 = tmp; 486 toe = CPC_NIAGARA2_PCR_TOE1; /* enable trap-on-event for pic1 */ 487 } 488 489 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 490 panic("%s: bad config on token %p\n", cpu_impl_name, token); 491 492 /* 493 * UltraSPARC does not allow pic0 to be configured differently 494 * from pic1. If the flags on these two configurations are 495 * different, they are incompatible. This condition should be 496 * caught at configure time. 497 */ 498 ASSERT(pic0->pcbe_flags == pic1->pcbe_flags); 499 500 ni2_pcbe_allstop(); 501 502 ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) | 503 (uint64_t)pic0->pcbe_pic); 504 505 pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_NIAGARA2_PCR_PIC0_SHIFT; 506 pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) << 507 CPC_NIAGARA2_PCR_PIC1_SHIFT; 508 509 if (pic0->pcbe_flags & CPC_COUNT_USER) 510 pcr |= (1ull << CPC_NIAGARA2_PCR_UT_SHIFT); 511 if (pic0->pcbe_flags & CPC_COUNT_SYSTEM) 512 pcr |= (1ull << CPC_NIAGARA2_PCR_ST_SHIFT); 513 if (pic0->pcbe_flags & CPC_COUNT_HV) 514 pcr |= (1ull << CPC_NIAGARA2_PCR_HT_SHIFT); 515 pcr |= toe; 516 517 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 518 519 if (pic0->pcbe_flags & CPC_COUNT_HV) { 520 /* 521 * The ht bit in the PCR is only writable in 522 * hyperprivileged mode. So if we are counting 523 * hpriv events, we must use the HV interface 524 * hv_niagara_setperf to set the PCR. If this 525 * fails, assume we no longer have access to 526 * hpriv events. 527 */ 528 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != H_EOK) { 529 kcpc_invalidate_config(token); 530 return; 531 } 532 } else 533 /* Set the PCR with no hpriv event counting enabled. */ 534 ultra_setpcr(pcr); 535 536 ni2_cpc_counting[CPU->cpu_id] = B_TRUE; 537 538 /* 539 * On UltraSPARC, only read-to-read counts are accurate. We cannot 540 * expect the value we wrote into the PIC, above, to be there after 541 * starting the counter. We must sample the counter value now and use 542 * that as the baseline for future samples. 543 */ 544 curpic = ultra_getpic(); 545 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 546 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 547 548 DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic); 549 } 550 551 static void 552 ni2_pcbe_allstop(void) 553 { 554 /* 555 * We use the HV interface here because if we were counting 556 * hyperprivileged events, we must reset the PCR.ht bit to stop 557 * the counting. In the event that this HV call fails, we fall 558 * back on ultra_setpcr which does not have write access to the 559 * ht bit. 560 */ 561 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped) != H_EOK) 562 ultra_setpcr(allstopped); 563 564 ni2_cpc_counting[CPU->cpu_id] = B_FALSE; 565 } 566 567 static void 568 ni2_pcbe_sample(void *token) 569 { 570 uint64_t curpic; 571 int64_t diff; 572 uint64_t *pic0_data; 573 uint64_t *pic1_data; 574 uint64_t *dtmp; 575 uint64_t tmp; 576 uint64_t pcr; 577 ni2_pcbe_config_t *pic0; 578 ni2_pcbe_config_t *pic1; 579 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 580 ni2_pcbe_config_t *ctmp; 581 582 curpic = ultra_getpic(); 583 DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic); 584 585 if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL) 586 panic("%s: token %p has no configs", cpu_impl_name, token); 587 588 if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) { 589 pic1 = &nullcfg; 590 pic1_data = &tmp; 591 } 592 593 if (pic0->pcbe_picno != 0) { 594 nullcfg.pcbe_picno = 0; 595 ctmp = pic0; 596 pic0 = pic1; 597 pic1 = ctmp; 598 dtmp = pic0_data; 599 pic0_data = pic1_data; 600 pic1_data = dtmp; 601 } 602 603 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 604 panic("%s: bad config on token %p\n", cpu_impl_name, token); 605 606 607 if (pic0->pcbe_flags & CPC_COUNT_HV) { 608 /* 609 * If the hpriv attribute is present, but the HT bit 610 * is not set in the PCR, access to hyperprivileged 611 * events must have been revoked. Only perform this 612 * check if counting is not stopped. 613 */ 614 pcr = ultra_getpcr(); 615 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 616 if (ni2_cpc_counting[CPU->cpu_id] && 617 !(pcr & CPC_NIAGARA2_PCR_HT)) { 618 kcpc_invalidate_config(token); 619 return; 620 } 621 } 622 623 diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic; 624 if (diff < 0) 625 diff += (1ll << 32); 626 *pic0_data += diff; 627 628 diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic; 629 if (diff < 0) 630 diff += (1ll << 32); 631 *pic1_data += diff; 632 633 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 634 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 635 } 636 637 static void 638 ni2_pcbe_free(void *config) 639 { 640 kmem_free(config, sizeof (ni2_pcbe_config_t)); 641 } 642 643 644 static struct modlpcbe modlpcbe = { 645 &mod_pcbeops, 646 #if defined(NIAGARA2_IMPL) 647 "UltraSPARC T2 Performance Counters", 648 #elif defined(VFALLS_IMPL) 649 "UltraSPARC T2+ Performance Counters", 650 #endif 651 &ni2_pcbe_ops 652 }; 653 654 static struct modlinkage modl = { 655 MODREV_1, 656 &modlpcbe, 657 }; 658 659 int 660 _init(void) 661 { 662 if (ni2_pcbe_init() != 0) 663 return (ENOTSUP); 664 return (mod_install(&modl)); 665 } 666 667 int 668 _fini(void) 669 { 670 return (mod_remove(&modl)); 671 } 672 673 int 674 _info(struct modinfo *mi) 675 { 676 return (mod_info(&modl, mi)); 677 } 678